| Server IP : 35.80.110.71 / Your IP : 216.73.216.21 Web Server : Apache/2.4.58 (Ubuntu) System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64 User : ubuntu ( 1000) PHP Version : 8.3.31 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/switchyard/current/database/seeders/ |
Upload File : |
<?php
namespace Database\Seeders;
use App\Enums\LeadEventKind;
use App\Enums\LeadSourceKind;
use App\Enums\LeadStatus;
use App\Models\ApiKey;
use App\Models\ClickUpConfig;
use App\Models\Lead;
use App\Models\LeadEvent;
use App\Models\LeadSource;
use App\Models\Scopes\WorkspaceScope;
use App\Models\Workspace;
use Carbon\CarbonImmutable;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Log;
/**
* Demo tenant: fictional workspace populated with 12 leads across 4 sources,
* a sane ClickUpConfig (taxonomy + portfolio examples), and a sandbox API
* key. Mirrors the /demo page on the docs site so an operator hitting
* /admin can poke at the same data through Filament.
*
* Idempotent — re-running the seeder updates the demo workspace in place
* rather than duplicating leads (uses the workspace slug + lead.external_ref
* as natural keys).
*/
class DemoTenantSeeder extends Seeder
{
public function run(): void
{
$slug = (string) config('switchyard.demo.workspace_slug', 'demo');
$workspace = Workspace::firstOrCreate(
['slug' => $slug],
['name' => 'Demo workspace'],
);
$this->seedSources($workspace);
$this->seedConfig($workspace);
$this->seedLeads($workspace);
$this->seedSandboxApiKey($workspace);
Log::info('DemoTenantSeeder: workspace seeded', ['workspace_id' => $workspace->id]);
}
private function seedSources(Workspace $workspace): void
{
$sources = [
['slug' => 'scopeforged-form', 'name' => 'ScopeForged contact form', 'kind' => LeadSourceKind::Webhook],
['slug' => 'upwork-email', 'name' => 'Upwork notification email', 'kind' => LeadSourceKind::Email],
['slug' => 'fiverr-email', 'name' => 'Fiverr message email', 'kind' => LeadSourceKind::Email],
['slug' => 'manual-paste', 'name' => 'Manual paste-in', 'kind' => LeadSourceKind::Manual],
];
foreach ($sources as $s) {
LeadSource::withoutGlobalScope(WorkspaceScope::class)
->updateOrCreate(
['workspace_id' => $workspace->id, 'slug' => $s['slug']],
[
'name' => $s['name'],
'kind' => $s['kind'],
'inbound_secret' => 'swhsec_demo_'.str_pad($s['slug'], 32, 'X'),
'field_mapping' => [],
'enabled' => true,
],
);
}
}
private function seedConfig(Workspace $workspace): void
{
ClickUpConfig::withoutGlobalScope(WorkspaceScope::class)
->updateOrCreate(
['workspace_id' => $workspace->id],
[
'inbound_list_id' => '901_demo_list',
'status_mapping' => [
'Closed Won' => 'won',
'Closed Lost' => 'lost',
'In Progress' => 'routed',
],
'custom_field_mapping' => [],
'service_taxonomy' => [
'web-app' => ['next.js', 'react', 'supabase', 'vercel', 'remix'],
'wordpress' => ['wordpress', 'woocommerce', 'wp', 'gutenberg', 'acf'],
'api' => ['api', 'rest', 'graphql', 'stripe webhook', 'laravel api'],
'devops' => ['devops', 'ci/cd', 'apache', 'pm2', 'ec2', 'docker'],
'data' => ['etl', 'pipeline', 'snowflake', 'duckdb', 'analytics'],
],
'portfolio_examples' => [
'web-app' => ['highlands-ranch-champ', 'integridev', 'smart-home-services'],
'wordpress' => ['wp-lawfirm', 'wp-coach', 'throughline-headless-wp'],
'api' => ['webhook-relay', 'pennant', 'inkwell', 'docgen'],
'devops' => ['shipyard'],
'data' => ['distill', 'codex'],
],
'auto_route_enabled' => true,
],
);
}
private function seedLeads(Workspace $workspace): void
{
$sources = LeadSource::withoutGlobalScope(WorkspaceScope::class)
->where('workspace_id', $workspace->id)
->pluck('id', 'slug');
$now = CarbonImmutable::now();
$seed = [
['demo_01', 'scopeforged-form', 'Jane Doe', 'jane@example.com', 'Acme Co', 'web-app', 92, LeadStatus::Enriched, null, '~$10k', '4 weeks', 'Next.js + Supabase MVP build'],
['demo_02', 'upwork-email', 'Marston Reid', 'reid@upwork.example', 'Marston Reid LLC', 'api', 88, LeadStatus::Enriched, null, '$80/hr', '3 months', 'Senior Laravel API engineer needed'],
['demo_03', 'fiverr-email', 'danielsmith42', null, null, 'wordpress', 64, LeadStatus::Routed, 'cu_8642', '$1,200', '2 weeks', 'Fiverr inquiry — WordPress migration'],
['demo_04', 'scopeforged-form', 'Mira Patel', 'mira@example.org', 'PatelCo', 'wordpress', 76, LeadStatus::Enriched, null, '$8k', null, 'Headless WP storefront'],
['demo_05', 'upwork-email', 'Acme Ops', 'ops@acme.example', 'Acme', 'api', 70, LeadStatus::Routed, 'cu_9001', '$50/hr', 'asap', 'Stripe webhook bridge'],
['demo_06', 'fiverr-email', 'lana.s', null, null, null, 28, LeadStatus::Dismissed, null, null, null, 'Quick landing-page tweak'],
['demo_07', 'scopeforged-form', 'Sam Levin', 'sam@levin.example', 'Levin Studio', 'web-app', 82, LeadStatus::Won, 'cu_7102', '$15k', '6 weeks', 'B2B SaaS dashboard refresh'],
['demo_08', 'manual-paste', 'Tally form', 'auto@tally.example', null, null, 35, LeadStatus::Enriched, null, null, null, 'Newsletter signup, requested follow-up'],
['demo_09', 'upwork-email', 'Holloway Ltd', 'hr@holloway.example', 'Holloway Ltd', 'devops', 73, LeadStatus::Enriched, null, '$70/hr', 'ongoing', 'DevOps consulting (Linux + Apache + PM2)'],
['demo_10', 'scopeforged-form', 'Drey Co', 'admin@drey.example', 'Drey Co', 'api', 80, LeadStatus::Routed, 'cu_4488', '$4k', '2 weeks', 'API rate-limit middleware retrofit'],
['demo_11', 'fiverr-email', 'rita_munoz', null, null, 'wordpress', 58, LeadStatus::Lost, 'cu_1199', '$700', '5 days', 'WP plugin custom block (CPT + ACF)'],
['demo_12', 'manual-paste', 'Caulk Studio', 'studio@caulk.example', 'Caulk', 'web-app', 67, LeadStatus::Enriched, null, null, '3 weeks', 'Tailwind + Filament admin makeover'],
];
foreach ($seed as $i => $row) {
[$ref, $sourceSlug, $name, $email, $company, $tag, $score, $status, $taskId, $budget, $timeline, $title] = $row;
$sourceId = $sources[$sourceSlug] ?? null;
if (! $sourceId) {
continue;
}
$createdAt = $now->subHours($i * 7 + 2);
$lead = Lead::withoutGlobalScope(WorkspaceScope::class)->updateOrCreate(
['source_id' => $sourceId, 'external_ref' => $ref],
[
'workspace_id' => $workspace->id,
'raw_payload' => [
'name' => $name,
'email' => $email,
'company' => $company,
'message' => $title.'. '.($budget ?? 'no budget').'. '.($timeline ?? 'flexible timeline').'.',
],
'parsed_contact' => array_filter([
'name' => $name,
'email' => $email,
'company' => $company,
]),
'parsed_job' => array_filter([
'title' => $title,
'body' => "Inquiry details for {$title}.",
'budget_text' => $budget,
'timeline_text' => $timeline,
]),
'service_tag' => $tag,
'suggested_examples' => $tag ? $this->examplesFor($tag) : [],
'lead_score' => $score,
'status' => $status,
'clickup_task_id' => $taskId,
'routed_at' => $taskId ? $createdAt->addMinutes(2) : null,
'won_at' => $status === LeadStatus::Won ? $createdAt->addDays(3) : null,
'lost_at' => $status === LeadStatus::Lost ? $createdAt->addDays(2) : null,
'dismissed_at' => $status === LeadStatus::Dismissed ? $createdAt->addMinutes(20) : null,
'created_at' => $createdAt,
'updated_at' => $createdAt,
],
);
$this->emit($lead->id, $workspace->id, LeadEventKind::Received, $createdAt);
$this->emit($lead->id, $workspace->id, LeadEventKind::Enriched, $createdAt->addSeconds(1));
if ($taskId) {
$this->emit($lead->id, $workspace->id, LeadEventKind::Routed, $createdAt->addMinutes(2), ['task_id' => $taskId]);
}
if ($status === LeadStatus::Won) {
$this->emit($lead->id, $workspace->id, LeadEventKind::StatusChanged, $createdAt->addDays(3), ['clickup_status' => 'Closed Won', 'mapped_status' => 'won']);
}
}
}
private function seedSandboxApiKey(Workspace $workspace): void
{
ApiKey::withoutGlobalScope(WorkspaceScope::class)
->updateOrCreate(
['workspace_id' => $workspace->id, 'name' => 'demo-sandbox'],
[
'prefix' => 'swy_demo_sandbox',
'key_hash' => hash('sha256', 'swy_demo_sandbox_'.str_pad('demo', 40, 'X')),
'last_four' => 'demo',
'scope' => ApiKey::SCOPE_ADMIN_READ,
],
);
}
private function examplesFor(string $tag): array
{
return match ($tag) {
'web-app' => ['highlands-ranch-champ', 'integridev'],
'wordpress' => ['wp-lawfirm', 'wp-coach'],
'api' => ['webhook-relay', 'pennant'],
'devops' => ['shipyard'],
'data' => ['distill'],
default => [],
};
}
private function emit(string $leadId, string $workspaceId, LeadEventKind $kind, CarbonImmutable $at, array $payload = []): void
{
LeadEvent::withoutGlobalScope(WorkspaceScope::class)->create([
'workspace_id' => $workspaceId,
'lead_id' => $leadId,
'kind' => $kind,
'payload' => $payload,
'created_at' => $at,
]);
}
}