File: /home/xedaptot/ai.naniguide.com/database/seeders/Demo/Stage20_ManifestWriter.php
<?php
namespace Database\Seeders\Demo;
use App\Model\Customer;
use App\Model\MailList;
use App\Model\Subscriber;
use Illuminate\Support\Facades\File;
/**
* Stage 20 — write docs/demo/DEMO_ACCOUNTS.json (the consumable manifest).
*
* This is the FINAL stage. Every other tool (e2e helpers, marketing video
* recorder, manual QA, README docs) reads this file to know:
* - which admin email/password to log in with
* - which customer accounts exist and what they're for
* - what data lives under each account (lists, subscribers, campaigns)
*
* If you change accounts in DemoConfig, just re-run DemoSeeder and the
* manifest is regenerated. There is no other source of truth.
*/
class Stage20_ManifestWriter extends AbstractDemoSeeder
{
public function run(): void
{
$manifest = [
'generated_at' => now()->toIso8601String(),
'seed_version' => DemoConfig::FAKER_SEED,
'login_url' => [
'admin' => '/admin/login',
'customer' => '/login',
],
'admins' => [],
'customers' => [],
'totals' => [],
'plans' => [],
];
// Admins
foreach (DemoConfig::admins() as $cfg) {
$entry = Stage01_AdminsSeeder::$created[$cfg['key']] ?? null;
$userId = $entry['user']->id ?? null;
$manifest['admins'][$cfg['key']] = [
'email' => $cfg['email'],
'password' => $cfg['password'],
'name' => trim($cfg['first_name'] . ' ' . $cfg['last_name']),
'purpose' => $cfg['purpose'],
'user_id' => $userId,
'role' => 'admin',
'has_customer_view' => $cfg['key'] === 'super', // primary admin also has customer view
];
}
// Customers
foreach (DemoConfig::customers() as $cfg) {
$customer = Stage03_CustomersSeeder::$created[$cfg['key']] ?? null;
if (!$customer) continue;
$listIds = collect(Stage07_MailListsSeeder::$created[$cfg['key']] ?? [])->pluck('id');
$subCount = $listIds->isEmpty() ? 0 : Subscriber::whereIn('mail_list_id', $listIds)->count();
$campaignCount = count(Stage10_CampaignsSeeder::$created[$cfg['key']] ?? []);
$entry = [
'email' => $cfg['email'],
'password' => $cfg['password'],
'company' => $cfg['company'],
'name' => trim($cfg['first_name'] . ' ' . $cfg['last_name']),
'plan' => $cfg['plan_key'],
'sub_status' => $cfg['sub_status'],
'purpose' => $cfg['purpose'] ?? '',
'customer_id' => $customer->id,
'role' => $cfg['key'] === 'primary' ? 'admin+customer' : 'customer',
'has_admin_view' => $cfg['key'] === 'primary',
'data' => [
'lists' => $listIds->count(),
'subscribers' => $subCount,
'campaigns' => $campaignCount,
'forms' => $cfg['forms'] ?? 0,
'automations' => $cfg['automations'] ?? 0,
'funnels' => $cfg['funnels'] ?? 0,
'websites' => $cfg['websites'] ?? 0,
],
];
// Additional team-member users sharing this customer workspace.
if (!empty($cfg['team_users'])) {
$entry['team_users'] = array_map(fn($m) => [
'email' => $m['email'],
'password' => $m['password'],
'first_name' => $m['first_name'],
'last_name' => $m['last_name'],
], $cfg['team_users']);
}
$manifest['customers'][$cfg['key']] = $entry;
}
// Totals (queried from DB so they reflect reality)
$manifest['totals'] = [
'admins' => \App\Model\Admin::count(),
'customers' => \App\Model\Customer::count(),
'plans' => \App\Model\Plan::count(),
'lists' => MailList::count(),
'subscribers' => Subscriber::count(),
'campaigns' => \App\Model\Campaign::count(),
'tracking_logs' => \DB::table('tracking_logs')->count(),
'open_logs' => \DB::table('open_logs')->count(),
'click_logs' => \DB::table('click_logs')->count(),
];
foreach (DemoConfig::plans() as $key => $plan) {
$manifest['plans'][$key] = ['name' => $plan['name'], 'price' => $plan['price']];
}
$path = DemoConfig::manifestPath();
File::ensureDirectoryExists(dirname($path));
File::put($path, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
$this->log("manifest written → {$path}");
$this->log("totals: " . json_encode($manifest['totals']));
}
}