[CORE] Initial project scaffold - NIS2 Agile Compliance Platform
Complete MVP implementation including: - PHP 8.4 backend with Front Controller pattern (80+ API endpoints) - Multi-tenant architecture with organization_id isolation - JWT authentication (HS256, 2h access + 7d refresh tokens) - 14 controllers: Auth, Organization, Assessment, Dashboard, Risk, Incident, Policy, SupplyChain, Training, Asset, Audit, Admin - AI Service integration (Anthropic Claude API) for gap analysis, risk suggestions, policy generation, incident classification - NIS2 gap analysis questionnaire (~80 questions, 10 categories) - MySQL schema (20 tables) with NIS2 Art. 21 compliance controls - NIS2 Art. 23 incident reporting workflow (24h/72h/30d) - Frontend: login, register, dashboard, assessment wizard, org setup - Docker configuration (PHP-FPM + Nginx + MySQL) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* NIS2 Agile - Admin Controller
|
||||
*
|
||||
* Gestione piattaforma (solo super_admin).
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/BaseController.php';
|
||||
|
||||
class AdminController extends BaseController
|
||||
{
|
||||
public function listOrganizations(): void
|
||||
{
|
||||
$this->requireSuperAdmin();
|
||||
$pagination = $this->getPagination();
|
||||
|
||||
$total = Database::count('organizations', '1=1');
|
||||
$orgs = Database::fetchAll(
|
||||
"SELECT o.*,
|
||||
(SELECT COUNT(*) FROM user_organizations WHERE organization_id = o.id) as member_count,
|
||||
(SELECT overall_score FROM assessments WHERE organization_id = o.id AND status = 'completed' ORDER BY completed_at DESC LIMIT 1) as last_score
|
||||
FROM organizations o
|
||||
ORDER BY o.created_at DESC
|
||||
LIMIT {$pagination['per_page']} OFFSET {$pagination['offset']}"
|
||||
);
|
||||
|
||||
$this->jsonPaginated($orgs, $total, $pagination['page'], $pagination['per_page']);
|
||||
}
|
||||
|
||||
public function listUsers(): void
|
||||
{
|
||||
$this->requireSuperAdmin();
|
||||
$pagination = $this->getPagination();
|
||||
|
||||
$total = Database::count('users', '1=1');
|
||||
$users = Database::fetchAll(
|
||||
"SELECT u.id, u.email, u.full_name, u.role, u.is_active, u.last_login_at, u.created_at,
|
||||
GROUP_CONCAT(o.name) as organizations
|
||||
FROM users u
|
||||
LEFT JOIN user_organizations uo ON uo.user_id = u.id
|
||||
LEFT JOIN organizations o ON o.id = uo.organization_id
|
||||
GROUP BY u.id
|
||||
ORDER BY u.created_at DESC
|
||||
LIMIT {$pagination['per_page']} OFFSET {$pagination['offset']}"
|
||||
);
|
||||
|
||||
$this->jsonPaginated($users, $total, $pagination['page'], $pagination['per_page']);
|
||||
}
|
||||
|
||||
public function platformStats(): void
|
||||
{
|
||||
$this->requireSuperAdmin();
|
||||
|
||||
$this->jsonSuccess([
|
||||
'total_organizations' => Database::count('organizations', '1=1'),
|
||||
'active_organizations' => Database::count('organizations', 'is_active = 1'),
|
||||
'total_users' => Database::count('users', '1=1'),
|
||||
'active_users' => Database::count('users', 'is_active = 1'),
|
||||
'total_assessments' => Database::count('assessments', '1=1'),
|
||||
'completed_assessments' => Database::count('assessments', 'status = "completed"'),
|
||||
'total_incidents' => Database::count('incidents', '1=1'),
|
||||
'open_incidents' => Database::count('incidents', 'status NOT IN ("closed", "post_mortem")'),
|
||||
'total_risks' => Database::count('risks', '1=1'),
|
||||
'total_policies' => Database::count('policies', '1=1'),
|
||||
'ai_interactions' => Database::count('ai_interactions', '1=1'),
|
||||
'plans_distribution' => Database::fetchAll(
|
||||
'SELECT subscription_plan, COUNT(*) as count FROM organizations GROUP BY subscription_plan'
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user