SIMON Master Console Rebuild
True command center for SIMON + WEB360
This rebuild gives you a cleaner production spine: interactive tree, live viewer, guarded editor, dynamic graphics, architecture map, and note storage. It is designed to sit beside your existing
console.php
and become the stronger replacement path.
Dashboard
Tree
Viewer
System Map
File Registry
Notes
Files
15,026
Folders
377
Scanned Size
3.79 GB
PHP Files
791
Editable Text Files
12,310
File viewer
guarded to /htdocs
/simon/social/accounts.php
<?php declare(strict_types=1); /** * /htdocs/simon/social/accounts.php * SIMON Social Accounts Console * * Purpose: * - Read provider configs from LINK registry * - Show only providers relevant to SOCIAL * - Display readiness, missing fields, capabilities, and test status * - Link operator into LINK editor for full configuration/testing */ date_default_timezone_set('America/Chicago'); header('Content-Type: text/html; charset=utf-8'); function h(string $value): string { return htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); } $rootDir = dirname(__DIR__); // /htdocs/simon $dataDir = $rootDir . '/data'; $logsDir = $rootDir . '/logs'; $registryFile = $dataDir . '/links_registry.json'; $statusFile = $dataDir . '/links_status.json'; $activityLog = $logsDir . '/links_activity.log'; $errorLog = $logsDir . '/links_errors.log'; if (!is_dir($dataDir)) { @mkdir($dataDir, 0775, true); } if (!is_dir($logsDir)) { @mkdir($logsDir, 0775, true); } function read_json_file(string $file): array { if (!is_file($file)) { return []; } $raw = @file_get_contents($file); $decoded = json_decode((string)$raw, true); return is_array($decoded) ? $decoded : []; } function ensure_social_providers_exist(string $file): void { $existing = []; if (is_file($file)) { $raw = @file_get_contents($file); $decoded = json_decode((string)$raw, true); if (is_array($decoded)) { $existing = $decoded; } } $seed = [ 'linkedin' => [ 'name' => 'LinkedIn', 'slug' => 'linkedin', 'provider_type' => 'social', 'category' => 'Social', 'owner_system' => 'SIMON', 'status' => 'planned', 'auth_type' => 'oauth2', 'platform_url' => 'https://www.linkedin.com/', 'module_routes' => ['social_dashboard'], 'required_fields' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'missing_required' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'readiness_score' => 40, 'last_test_status' => 'not_tested', 'last_test_message' => '', 'last_test_at' => '', 'capabilities' => ['publish', 'profile', 'analytics'], 'updated_at' => date('c'), ], 'facebook' => [ 'name' => 'Facebook', 'slug' => 'facebook', 'provider_type' => 'social', 'category' => 'Social', 'owner_system' => 'SIMON', 'status' => 'planned', 'auth_type' => 'oauth2', 'platform_url' => 'https://www.facebook.com/', 'module_routes' => ['social_dashboard'], 'required_fields' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'missing_required' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'readiness_score' => 40, 'last_test_status' => 'not_tested', 'last_test_message' => '', 'last_test_at' => '', 'capabilities' => ['publish', 'analytics', 'pages'], 'updated_at' => date('c'), ], 'instagram' => [ 'name' => 'Instagram', 'slug' => 'instagram', 'provider_type' => 'social', 'category' => 'Social', 'owner_system' => 'SIMON', 'status' => 'planned', 'auth_type' => 'oauth2', 'platform_url' => 'https://www.instagram.com/', 'module_routes' => ['social_dashboard'], 'required_fields' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'missing_required' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'readiness_score' => 40, 'last_test_status' => 'not_tested', 'last_test_message' => '', 'last_test_at' => '', 'capabilities' => ['publish', 'analytics', 'media'], 'updated_at' => date('c'), ], 'x' => [ 'name' => 'X', 'slug' => 'x', 'provider_type' => 'social', 'category' => 'Social', 'owner_system' => 'SIMON', 'status' => 'planned', 'auth_type' => 'oauth2', 'platform_url' => 'https://x.com/', 'module_routes' => ['social_dashboard'], 'required_fields' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'missing_required' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'readiness_score' => 40, 'last_test_status' => 'not_tested', 'last_test_message' => '', 'last_test_at' => '', 'capabilities' => ['publish', 'analytics'], 'updated_at' => date('c'), ], 'threads' => [ 'name' => 'Threads', 'slug' => 'threads', 'provider_type' => 'social', 'category' => 'Social', 'owner_system' => 'SIMON', 'status' => 'planned', 'auth_type' => 'oauth2', 'platform_url' => 'https://www.threads.net/', 'module_routes' => ['social_dashboard'], 'required_fields' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'missing_required' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'readiness_score' => 40, 'last_test_status' => 'not_tested', 'last_test_message' => '', 'last_test_at' => '', 'capabilities' => ['publish'], 'updated_at' => date('c'), ], 'tiktok' => [ 'name' => 'TikTok', 'slug' => 'tiktok', 'provider_type' => 'social', 'category' => 'Social', 'owner_system' => 'SIMON', 'status' => 'planned', 'auth_type' => 'oauth2', 'platform_url' => 'https://www.tiktok.com/', 'module_routes' => ['social_dashboard'], 'required_fields' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'missing_required' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'readiness_score' => 40, 'last_test_status' => 'not_tested', 'last_test_message' => '', 'last_test_at' => '', 'capabilities' => ['publish', 'analytics'], 'updated_at' => date('c'), ], 'pinterest' => [ 'name' => 'Pinterest', 'slug' => 'pinterest', 'provider_type' => 'social', 'category' => 'Social', 'owner_system' => 'SIMON', 'status' => 'planned', 'auth_type' => 'oauth2', 'platform_url' => 'https://www.pinterest.com/', 'module_routes' => ['social_dashboard'], 'required_fields' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'missing_required' => ['client_id_ref', 'client_secret_ref', 'callback_url'], 'readiness_score' => 40, 'last_test_status' => 'not_tested', 'last_test_message' => '', 'last_test_at' => '', 'capabilities' => ['publish', 'boards'], 'updated_at' => date('c'), ], 'substack' => [ 'name' => 'Substack', 'slug' => 'substack', 'provider_type' => 'publishing', 'category' => 'Publishing', 'owner_system' => 'SIMON', 'status' => 'planned', 'auth_type' => 'rss_or_manual', 'platform_url' => '', 'module_routes' => ['social_dashboard'], 'required_fields' => ['publication_url', 'rss_url'], 'missing_required' => ['publication_url', 'rss_url'], 'readiness_score' => 60, 'last_test_status' => 'not_tested', 'last_test_message' => '', 'last_test_at' => '', 'capabilities' => ['publish', 'rss'], 'updated_at' => date('c'), ], ]; foreach ($seed as $slug => $provider) { if (!isset($existing[$slug])) { $existing[$slug] = $provider; } } @file_put_contents($file, json_encode($existing, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); } ensure_social_providers_exist($registryFile); $registry = read_json_file($registryFile); $socialSlugs = [ 'facebook', 'instagram', 'linkedin', 'x', 'threads', 'tiktok', 'pinterest', 'substack', 'meta_business', ]; $socialProviders = array_filter( $registry, static function ($provider) use ($socialSlugs): bool { $slug = strtolower((string)($provider['slug'] ?? '')); $type = strtolower((string)($provider['provider_type'] ?? '')); return in_array($slug, $socialSlugs, true) || in_array($type, ['social', 'publishing'], true); } ); usort($socialProviders, static function (array $a, array $b): int { return strcasecmp((string)($a['name'] ?? ''), (string)($b['name'] ?? '')); }); $totalProviders = count($socialProviders); $connectedCount = 0; $plannedCount = 0; $issuesCount = 0; foreach ($socialProviders as $provider) { $status = strtolower((string)($provider['status'] ?? 'planned')); if ($status === 'connected') { $connectedCount++; } elseif ($status === 'planned') { $plannedCount++; } if (!empty($provider['missing_required']) || in_array(($provider['last_test_status'] ?? ''), ['error', 'warning'], true)) { $issuesCount++; } } function badge_class(string $status): string { $status = strtolower(trim($status)); return match ($status) { 'connected', 'ok', 'ready', 'success' => 'ok', 'warning', 'planned', 'pending', 'not_tested' => 'warn', 'error', 'failed', 'offline' => 'bad', default => 'neutral', }; } function score_class(int $score): string { if ($score >= 80) { return 'ok'; } if ($score >= 50) { return 'warn'; } return 'bad'; } function format_list(mixed $items, string $fallback = '—'): string { if (!is_array($items) || !$items) { return $fallback; } $items = array_map(static fn($v) => trim((string)$v), $items); $items = array_filter($items, static fn($v) => $v !== ''); return $items ? implode(', ', $items) : $fallback; } ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>SIMON Social Accounts</title> <style> :root{ --bg:#04101d; --bg2:#07192b; --panel:rgba(8,20,40,.82); --edge:rgba(90,216,255,.18); --edge2:rgba(255,255,255,.07); --text:#e8fbff; --muted:rgba(215,242,255,.72); --cyan:#7cecff; --cyan2:#23d5ff; --ok:#50e3a4; --warn:#ffc566; --bad:#ff8096; --neutral:#8ab4c7; } *{box-sizing:border-box} html,body{ margin:0; padding:0; font-family:Arial,Helvetica,sans-serif; color:var(--text); background: radial-gradient(circle at top left, rgba(31,98,153,.25), transparent 26%), radial-gradient(circle at top right, rgba(0,224,255,.14), transparent 22%), linear-gradient(180deg,var(--bg),#020814 78%); } .wrap{max-width:1500px;margin:0 auto;padding:24px} .topbar{ display:flex; justify-content:space-between; align-items:flex-start; gap:18px; flex-wrap:wrap; margin-bottom:20px; } .title{ font-size:30px; font-weight:800; letter-spacing:.3px; } .sub{ margin-top:6px; color:var(--muted); font-size:14px; } .quick{ display:flex; gap:12px; flex-wrap:wrap; } .quick-card{ min-width:150px; background:var(--panel); border:1px solid var(--edge); border-radius:18px; padding:14px 16px; box-shadow:0 15px 40px rgba(0,0,0,.28); } .quick-card .k{ font-size:12px; text-transform:uppercase; letter-spacing:.8px; color:var(--muted); } .quick-card .v{ margin-top:8px; font-size:24px; font-weight:800; } .panel{ background:var(--panel); border:1px solid var(--edge); border-radius:24px; box-shadow:0 18px 55px rgba(0,0,0,.30), inset 0 0 0 1px rgba(255,255,255,.02); overflow:hidden; } .panel-head{ display:flex; justify-content:space-between; align-items:center; gap:12px; padding:18px 20px; border-bottom:1px solid var(--edge2); flex-wrap:wrap; } .panel-title{ font-size:20px; font-weight:800; } .panel-note{ color:var(--muted); font-size:13px; } .table-wrap{ width:100%; overflow:auto; } table{ width:100%; border-collapse:collapse; min-width:1100px; } th,td{ text-align:left; padding:14px 16px; border-bottom:1px solid rgba(255,255,255,.06); vertical-align:top; } th{ font-size:12px; letter-spacing:.8px; text-transform:uppercase; color:var(--muted); background:rgba(255,255,255,.02); } tr:hover td{ background:rgba(255,255,255,.025); } .name{ font-weight:800; font-size:15px; } .slug{ color:var(--muted); font-size:12px; margin-top:4px; } .badge{ display:inline-flex; align-items:center; gap:8px; padding:6px 10px; border-radius:999px; font-size:12px; font-weight:700; border:1px solid var(--edge); background:rgba(255,255,255,.04); white-space:nowrap; } .ok{color:var(--ok)} .warn{color:var(--warn)} .bad{color:var(--bad)} .neutral{color:var(--neutral)} .small{ font-size:12px; color:var(--muted); } .actions{ display:flex; gap:10px; flex-wrap:wrap; } .btn{ text-decoration:none; padding:10px 14px; border-radius:12px; font-weight:700; font-size:13px; border:1px solid var(--edge); color:var(--text); background:rgba(255,255,255,.04); } .btn.primary{ color:#031019; background:linear-gradient(180deg,var(--cyan),var(--cyan2)); border:none; } .empty{ padding:26px 20px; color:var(--muted); } .score{ font-weight:800; } .footer-note{ margin-top:14px; color:var(--muted); font-size:12px; } </style> </head> <body> <div class="wrap"> <div class="topbar"> <div> <div class="title">SIMON Social Accounts</div> <div class="sub">Operator view for provider readiness, missing setup, last test state, and direct configuration links into LINK.</div> </div> <div class="quick"> <div class="quick-card"> <div class="k">Providers</div> <div class="v"><?php echo h((string)$totalProviders); ?></div> </div> <div class="quick-card"> <div class="k">Connected</div> <div class="v ok"><?php echo h((string)$connectedCount); ?></div> </div> <div class="quick-card"> <div class="k">Planned</div> <div class="v warn"><?php echo h((string)$plannedCount); ?></div> </div> <div class="quick-card"> <div class="k">Issues</div> <div class="v bad"><?php echo h((string)$issuesCount); ?></div> </div> </div> </div> <div class="panel"> <div class="panel-head"> <div> <div class="panel-title">Connected Account Readiness Matrix</div> <div class="panel-note">This screen reads the shared LINK registry and shows only social/publishing accounts used by the SOCIAL module.</div> </div> <div class="actions"> <a class="btn" href="/simon/social/social.php">Open Social Dashboard</a> <a class="btn" href="/simon/links.php?view=registry">Open Link Registry</a> </div> </div> <div class="table-wrap"> <table> <thead> <tr> <th>Provider</th> <th>Type</th> <th>Auth</th> <th>Status</th> <th>Readiness</th> <th>Missing Required</th> <th>Capabilities</th> <th>Last Test</th> <th>Actions</th> </tr> </thead> <tbody> <?php if (!$socialProviders): ?> <tr> <td colspan="9" class="empty">No social providers were found in the LINK registry.</td> </tr> <?php else: ?> <?php foreach ($socialProviders as $provider): ?> <?php $name = (string)($provider['name'] ?? 'Unknown'); $slug = (string)($provider['slug'] ?? ''); $type = (string)($provider['provider_type'] ?? '—'); $authType = (string)($provider['auth_type'] ?? '—'); $status = (string)($provider['status'] ?? 'planned'); $statusClass = badge_class($status); $score = (int)($provider['readiness_score'] ?? 0); $scoreClass = score_class($score); $missing = format_list($provider['missing_required'] ?? []); $caps = format_list($provider['capabilities'] ?? []); $lastTest = (string)($provider['last_test_status'] ?? 'not_tested'); $lastMsg = (string)($provider['last_test_message'] ?? ''); $lastTestClass = badge_class($lastTest); $linkEditorUrl = '/simon/link/link_editor.php?slug=' . urlencode($slug); $registryUrl = '/simon/links.php?view=registry'; ?> <tr> <td> <div class="name"><?php echo h($name); ?></div> <div class="slug"><?php echo h($slug); ?></div> </td> <td><?php echo h($type); ?></td> <td><?php echo h($authType); ?></td> <td> <span class="badge <?php echo h($statusClass); ?>"> <?php echo h(ucwords(str_replace('_', ' ', $status))); ?> </span> </td> <td> <span class="score <?php echo h($scoreClass); ?>"> <?php echo h((string)$score); ?>% </span> </td> <td><?php echo h($missing); ?></td> <td><?php echo h($caps); ?></td> <td> <div> <span class="badge <?php echo h($lastTestClass); ?>"> <?php echo h(ucwords(str_replace('_', ' ', $lastTest))); ?> </span> </div> <?php if ($lastMsg !== ''): ?> <div class="small" style="margin-top:8px;"><?php echo h($lastMsg); ?></div> <?php endif; ?> </td> <td> <div class="actions"> <a class="btn primary" href="<?php echo h($linkEditorUrl); ?>">Configure</a> <a class="btn" href="<?php echo h($registryUrl); ?>">Registry</a> </div> </td> </tr> <?php endforeach; ?> <?php endif; ?> </tbody> </table> </div> </div> <div class="footer-note"> Shared source: <code><?php echo h($registryFile); ?></code> </div> </div> </body> </html>
Save file
Quick jump
open a path
Open