prepare('SELECT 1 FROM platform_admins WHERE user_id = ?'); $stmt->execute([$userId]); return $stmt->fetchColumn() !== false; } /** * Requires a real SaaS login (any tenant role, or none) plus a * platform_admins entry. Exits with 403 otherwise. * * @return array{user_id: int, email: string, display_name: string} */ function app_require_platform_admin(PDO $pdo): array { $user = saas_current_user($pdo); if ($user === null) { header('Location: login.php'); exit; } if (!app_is_platform_admin($pdo, (int)$user['user_id'])) { http_response_code(403); exit('Kein Zugriff.'); } return $user; } /** * @return list */ function app_backoffice_fetch_tenants(PDO $pdo): array { $stmt = $pdo->query( "SELECT t.id, t.slug, t.name, t.status, t.created_at, COALESCE(tb.plan_code, 'free') AS plan_code, COUNT(p.id) AS participant_count, COALESCE(SUM(p.active), 0) AS active_participant_count, COALESCE(( SELECT SUM(le.amount_cents) FROM ledger_entries le WHERE le.tenant_id = t.id AND le.voided_at IS NULL ), 0) AS balance_cents FROM tenants t LEFT JOIN participants p ON p.tenant_id = t.id LEFT JOIN tenant_billing tb ON tb.tenant_id = t.id GROUP BY t.id, t.slug, t.name, t.status, t.created_at, tb.plan_code ORDER BY t.created_at DESC" ); return $stmt->fetchAll(); } /** * @return array{tenant: array, settings: ?array, members: list, recent_entries: list, recent_audit: list}|null */ function app_backoffice_fetch_tenant_detail(PDO $pdo, int $tenantId): ?array { $stmt = $pdo->prepare('SELECT id, slug, name, status, timezone, locale, currency_code, created_at FROM tenants WHERE id = ?'); $stmt->execute([$tenantId]); $tenant = $stmt->fetch(); if ($tenant === false) { return null; } $stmt = $pdo->prepare('SELECT * FROM tenant_settings WHERE tenant_id = ?'); $stmt->execute([$tenantId]); $settings = $stmt->fetch() ?: null; $stmt = $pdo->prepare( 'SELECT u.id, u.email, u.display_name, u.status, tm.role, tm.status AS membership_status FROM tenant_memberships tm JOIN users u ON u.id = tm.user_id WHERE tm.tenant_id = ? ORDER BY tm.role, u.display_name' ); $stmt->execute([$tenantId]); $members = $stmt->fetchAll(); $stmt = $pdo->prepare( 'SELECT le.id, le.type, le.amount_cents, le.booked_at, le.source, p.display_name FROM ledger_entries le JOIN participants p ON p.id = le.participant_id WHERE le.tenant_id = ? AND le.voided_at IS NULL ORDER BY le.booked_at DESC, le.id DESC LIMIT 20' ); $stmt->execute([$tenantId]); $recentEntries = $stmt->fetchAll(); $stmt = $pdo->prepare( 'SELECT a.id, a.action, a.subject_type, a.subject_id, a.created_at, u.display_name AS actor_name FROM audit_log a LEFT JOIN users u ON u.id = a.actor_user_id WHERE a.tenant_id = ? ORDER BY a.created_at DESC, a.id DESC LIMIT 20' ); $stmt->execute([$tenantId]); $recentAudit = $stmt->fetchAll(); return [ 'tenant' => $tenant, 'settings' => $settings, 'members' => $members, 'recent_entries' => $recentEntries, 'recent_audit' => $recentAudit, ]; }