/* =========================================================================== mock-db.jsx — ARGT MOCK DATA LAYER ◆◆◆ FOLD SEAM ◆◆◆ --------------------------------------------------------------------------- This is the ONLY place the dashboards read/write "server" data. No page hard-codes its own domain data anymore — every interactive surface calls: const [val, setVal] = window.useDB("collection") // React hook, persists window.ARGT_DB.get("collection") // read current value window.ARGT_DB.set("collection", v|fn) // write + notify + persist window.ARGT_DB.update("collection", fn) // functional write ───────────────────────────────────────────────────────────────────────── HOW TO FOLD INTO THE LIVE APP ───────────────────────────────────────────────────────────────────────── • Each top-level key in SEED is a "collection" and maps 1:1 to a live endpoint, e.g. creatorProfile → GET/PATCH /api/me/creator-profile. • The SEED object IS the response-shape contract. Replace the bodies of DB.get / DB.set / DB.update with real fetch() calls; keep the same keys and shapes and the UI needs zero changes. • Persistence here is localStorage ('argt-db-v1', versioned). In prod the server is the source of truth; drop the persist()/load() calls. • Nothing here is real PII or real algorithm detail — safe demo fixtures only. =========================================================================== */ (function () { "use strict"; const LS_KEY = "argt-db-v1"; const VERSION = 5; // ----- SEED FIXTURES (response-shape contracts; swap for server data) ----- const SEED = { // ---------- CREATOR ---------- creatorProfile: { stageName: "Maya Cole", city: "Tampa, FL", genre: "Soul", yearsActive: "6", bio: "Soul with a live-band heartbeat. Songs about leaving and coming back.", website: "mayacole.com", instagram: "@mayacolemusic", spotify: "spotify.com/artist/mayacole", youtube: "youtube.com/@mayacole", }, auditionSubmission: { trackA: "", trackB: "", trackBio: "", setLength: "45 minutes", bandSize: "4", ridersUrl: "", submitted: false, submittedAt: null, }, creatorProducts: [ { id: "p1", name: "Tour tee · charcoal", price: "$28", detail: "S–XXL · 124 in stock", glyph: "👕", active: true }, { id: "p2", name: "Single · vinyl 7\"", price: "$18", detail: "limited 500", glyph: "💿", active: true }, { id: "p3", name: "Sticker pack", price: "$6", detail: "set of 4", glyph: "✦", active: true }, { id: "p4", name: "Bundle · tee + vinyl", price: "$40", detail: "save $6", glyph: "📦", active: false }, ], creatorMedia: [ { id: "m1", type: "VIDEO", label: "Live at The Orpheum" }, { id: "m2", type: "PHOTO", label: "Press shot 01" }, { id: "m3", type: "AUDIO", label: "Garden State (master)" }, { id: "m4", type: "PHOTO", label: "Backstage 02" }, { id: "m5", type: "VIDEO", label: "Studio session" }, { id: "m6", type: "AUDIO", label: "Acoustic demo" }, ], creatorOpportunities: [ { id: "o1", title: "Main Stage · Sat early slot", org: "ARGT Programming", fee: "$1,200", status: "open" }, { id: "o2", title: "Halo Beauty brand collab reel", org: "Halo Beauty", fee: "$2,500", status: "open" }, { id: "o3", title: "Pavilion acoustic session", org: "ARGT Programming", fee: "$600", status: "applied" }, { id: "o4", title: "Clean Earth benefit single", org: "Clean Earth Initiative", fee: "Royalty split", status: "open" }, ], creatorOrders: [ { id: "ord1", item: "Tour tee · charcoal ×2", who: "S. Reilly", total: "$56", status: "approved" }, { id: "ord2", item: "Vinyl 7\" ×1", who: "J. Wynn", total: "$18", status: "pending" }, { id: "ord3", item: "Bundle ×1", who: "D. Kerr", total: "$40", status: "pending" }, ], // ---------- FAN ---------- fanReferral: { code: "KAM26", redeems: 12 }, // ---------- SPONSOR ---------- sponsorActivation: { zone: "Pavilion · gaming + lounge", goal: "Brand lift + sampling to Gen-Z fans", kpis: "50k impressions · 4k samples · 1.5k emails", hospitality: "12 VIP passes · 4 plus-ones", notes: "", confirmed: true, }, sponsorDeliverables: [ { id: "d1", label: "Logo on main-stage LED loop", status: "approved" }, { id: "d2", label: "Pavilion footprint (20×20)", status: "approved" }, { id: "d3", label: "Email feature (1 of 4 sends)", status: "pending" }, { id: "d4", label: "Post-event recap deck", status: "draft" }, ], // ---------- CREW ---------- crewAssignments: [ { id: "a1", title: "Stage lighting · Saturday 10 AM – 11 PM", pay: "$680 · 13h · OT after 8", status: "open" }, { id: "a2", title: "Hospitality coverage · Sunday 12 PM – 8 PM", pay: "$420 · 8h", status: "open" }, { id: "a3", title: "Crew call sheet brief · pre-festival", pay: "Wed Sep 17 · $200", status: "accepted" }, ], // ---------- VETERANS ---------- vetRecognition: { honorees: "", speaker: "", logistics: "" }, // ---------- LOCAL BUSINESS ---------- localOffer: { pct: "15%", starts: "Sep 17", ends: "Sep 21", terms: "One per wristband. Not combinable with other offers.", redemption: "Show QR at POS", published: false, }, localCreative: { tagline: "Festival fuel, two blocks away.", description: "Show your ARGT wristband for 15% off any order all weekend.", logo: null, hero: null, }, // ---------- PRESS ---------- pressInterviews: [ { id: "i1", subject: "Maya Cole (artist)", when: "Fri Sep 18 · 2:00 PM", status: "open" }, { id: "i2", subject: "Festival founders", when: "Press week · by appt", status: "open" }, { id: "i3", subject: "Clean Earth lead", when: "Sat Sep 19 · 11:00 AM", status: "requested" }, ], // ===================================================================== // LAUNCH COMMAND CENTER (folds /launch/* + /admin/launch/*) // Each key = one live endpoint; the shape IS the response contract. // ===================================================================== // ---------- TODAY / This Week (GET /api/launch/this-week) ---------- // tMinusWeek: integer weeks before the Sep 18 gate. status drives the board. launchTasks: [ { id: "t1", title: "Lock headliner contracts (3 of 5 signed)", engine: "content", owner: "Casey", tMinusWeek: 16, due: "Jun 5", status: "blocked", kpi: "5 headliners", risk: "high" }, { id: "t2", title: "Founders-phase ticket cascade go-live", engine: "tickets", owner: "Kam", tMinusWeek: 16, due: "Jun 1", status: "doing", kpi: "Phase 1 live", risk: "high" }, { id: "t3", title: "Approve sponsor activation footprints", engine: "sponsors", owner: "Taylor", tMinusWeek: 16, due: "Jun 3", status: "doing", kpi: "8 of 12", risk: "med" }, { id: "t4", title: "Publish week-of social calendar", engine: "social", owner: "Jordan", tMinusWeek: 16, due: "May 31", status: "todo", kpi: "21 posts", risk: "low" }, { id: "t5", title: "Vendor village compliance audit", engine: "day-of", owner: "Morgan", tMinusWeek: 15, due: "Jun 9", status: "todo", kpi: "40 vendors", risk: "med" }, { id: "t6", title: "Email sequence: ticket phase 1 announce", engine: "digital", owner: "Jordan", tMinusWeek: 16, due: "Jun 1", status: "doing", kpi: "24k list", risk: "low" }, { id: "t7", title: "Confirm 5-stage power + rigging plan", engine: "day-of", owner: "Morgan", tMinusWeek: 14, due: "Jun 16", status: "todo", kpi: "5 stages", risk: "med" }, { id: "t8", title: "Clean Earth 10% pledge page QA", engine: "digital", owner: "Jordan", tMinusWeek: 16, due: "Jun 2", status: "done", kpi: "Live", risk: "low" }, ], // ---------- ENGINES (GET /api/launch/engines) ---------- // The festival's six operating engines. status: healthy|attention|paused. // NOTE: progress / status / openTasks are LIVE-DERIVED from launchTasks in // the UI (see engineLive() in launch-app.jsx) — the seed values below are // only a fallback/contract shape. In prod the server computes these rollups. launchEngines: [ { key: "social", label: "Social", status: "healthy", owner: "Jordan", progress: 72, openTasks: 4, note: "Week-of calendar in review.", target: "2.5M reach", enabled: true }, { key: "digital", label: "Digital", status: "healthy", owner: "Jordan", progress: 64, openTasks: 6, note: "Email + site on track.", target: "24k list · site live", enabled: true }, { key: "sponsors", label: "Sponsors", status: "attention", owner: "Taylor", progress: 58, openTasks: 9, note: "4 activation footprints unconfirmed.", target: "$950k booked", enabled: true }, { key: "tickets", label: "Tickets", status: "attention", owner: "Kam", progress: 41, openTasks: 7, note: "Founders phase go-live pending.", target: "10k sold", enabled: true }, { key: "content", label: "Content", status: "attention", owner: "Casey", progress: 49, openTasks: 11, note: "2 headliner contracts outstanding.", target: "75+ artists", enabled: true }, { key: "day-of", label: "Day-Of", status: "paused", owner: "Morgan", progress: 23, openTasks: 14, note: "Opens after lineup locks.", target: "Show ready", enabled: false }, ], // ---------- INBOX / What changed (GET /api/launch/inbox) ---------- launchInbox: [ { id: "n1", kind: "payment", summary: "Halo Beauty sponsor deposit cleared ($12,000)", priority: "normal", entityKind: "sponsor", entityId: "halo", at: "12m", readAt: null }, { id: "n2", kind: "status", summary: "Maya Cole moved Confirmed → Advanced", priority: "normal", entityKind: "artist", entityId: "maya", at: "48m", readAt: null }, { id: "n3", kind: "flag", summary: "Vendor V-22 missing certificate of insurance", priority: "high", entityKind: "vendor", entityId: "v22", at: "2h", readAt: null }, { id: "n4", kind: "applicant", summary: "9 new crew applications (lighting, audio)", priority: "low", entityKind: "crew", entityId: "batch", at: "3h", readAt: "seen" }, { id: "n5", kind: "status", summary: "Founders phase sold 41% of allocation", priority: "normal", entityKind: "tickets", entityId: "phase1", at: "5h", readAt: "seen" }, { id: "n6", kind: "flag", summary: "Block stage rigging quote over budget by $4.2k", priority: "high", entityKind: "budget", entityId: "rig", at: "1d", readAt: "seen" }, ], // ---------- PIPELINES (GET /api/launch/pipeline?audience=) ---------- // One flat collection; audience + stage partition it into the right board. pipelineStages: ["Inquiry", "Review", "Confirmed", "Advanced"], pipelineItems: [ // artist { id: "a-1", audience: "artist", name: "Maya Cole", stage: "Advanced", owner: "Casey", value: "Main · Sat", meta: "Soul · Tampa", updatedAt: "48m" }, { id: "a-2", audience: "artist", name: "Pillar Funk", stage: "Confirmed", owner: "Casey", value: "Frequency", meta: "Funk · Miami", updatedAt: "1d" }, { id: "a-3", audience: "artist", name: "Cane River", stage: "Confirmed", owner: "Casey", value: "Main · Sun", meta: "Country · Tampa",updatedAt: "2d" }, { id: "a-4", audience: "artist", name: "The Anchors", stage: "Review", owner: "Casey", value: "Headliner?", meta: "Rock · Orlando", updatedAt: "3h" }, { id: "a-5", audience: "artist", name: "Quad Aux", stage: "Inquiry", owner: "Casey", value: "—", meta: "Hip-Hop · Jax", updatedAt: "5h" }, // sponsor { id: "s-1", audience: "sponsor", name: "Halo Beauty", stage: "Advanced", owner: "Taylor", value: "$24,000", meta: "Brand Partner", updatedAt: "12m" }, { id: "s-2", audience: "sponsor", name: "Drift Beverages", stage: "Confirmed", owner: "Taylor", value: "$40,000", meta: "Presenting", updatedAt: "1d" }, { id: "s-3", audience: "sponsor", name: "Northwave Tech", stage: "Review", owner: "Taylor", value: "$18,000", meta: "Brand Partner", updatedAt: "6h" }, { id: "s-4", audience: "sponsor", name: "Treasure Coast CU",stage: "Inquiry", owner: "Taylor", value: "—", meta: "Cultural", updatedAt: "2d" }, // vendor { id: "v-1", audience: "vendor", name: "Smoke & Sear BBQ", stage: "Confirmed", owner: "Morgan", value: "V-08", meta: "Food", updatedAt: "1d" }, { id: "v-2", audience: "vendor", name: "Coastal Threads", stage: "Confirmed", owner: "Morgan", value: "V-14", meta: "Apparel", updatedAt: "2d" }, { id: "v-3", audience: "vendor", name: "Neon Ink Tattoo", stage: "Review", owner: "Morgan", value: "—", meta: "Experience", updatedAt: "4h" }, { id: "v-4", audience: "vendor", name: "Glass & Grain", stage: "Inquiry", owner: "Morgan", value: "—", meta: "Retail", updatedAt: "1d" }, // crew { id: "c-1", audience: "crew", name: "A. Rivera", stage: "Confirmed", owner: "Morgan", value: "Lighting", meta: "ETCP cert", updatedAt: "3h" }, { id: "c-2", audience: "crew", name: "J. Okafor", stage: "Review", owner: "Morgan", value: "Audio", meta: "12 yrs", updatedAt: "5h" }, { id: "c-3", audience: "crew", name: "9 new applicants", stage: "Inquiry", owner: "Morgan", value: "Batch", meta: "Mixed roles", updatedAt: "3h" }, // partner { id: "p-1", audience: "partner", name: "Clean Earth Initiative", stage: "Advanced", owner: "Kam", value: "10% pledge", meta: "Cause", updatedAt: "1d" }, { id: "p-2", audience: "partner", name: "City of Fort Pierce", stage: "Confirmed", owner: "Kam", value: "Permits", meta: "Civic", updatedAt: "2d" }, { id: "p-3", audience: "partner", name: "Treasure Coast Vets", stage: "Review", owner: "Kam", value: "Wellness", meta: "Nonprofit", updatedAt: "1d" }, ], // ---------- TALENT ADVANCE (GET /api/launch/talent-advance) ---------- talentAdvance: [ { id: "ta1", artist: "Maya Cole", stage: "Main", setTime: "Sat 8:00 PM", fee: "$6,000", travel: "booked", hospitality: "done", techNeeds: "received", contract: "signed", status: "ready" }, { id: "ta2", artist: "Pillar Funk", stage: "Frequency", setTime: "Fri 9:30 PM", fee: "$4,200", travel: "pending", hospitality: "pending", techNeeds: "received", contract: "signed", status: "in-progress" }, { id: "ta3", artist: "Cane River", stage: "Main", setTime: "Sun 6:00 PM", fee: "$3,800", travel: "n/a", hospitality: "done", techNeeds: "pending", contract: "out", status: "in-progress" }, { id: "ta4", artist: "The Anchors", stage: "Main", setTime: "Sat 10:00 PM",fee: "$9,500", travel: "pending", hospitality: "pending", techNeeds: "pending", contract: "drafting", status: "at-risk" }, ], // ---------- MARKETING ---------- // CommsCalendarPost{scheduledAt, channel, body, status} — GET /api/launch/comms commsCalendar: [ { id: "cc1", scheduledAt: "May 31", channel: "Instagram", title: "Phase 1 tickets teaser", status: "approved", owner: "Jordan" }, { id: "cc2", scheduledAt: "Jun 1", channel: "Email", title: "Founders phase on sale", status: "approved", owner: "Jordan" }, { id: "cc3", scheduledAt: "Jun 2", channel: "TikTok", title: "Lineup hint reel", status: "draft", owner: "Jordan" }, { id: "cc4", scheduledAt: "Jun 4", channel: "Instagram", title: "Sponsor spotlight: Drift", status: "scheduled", owner: "Taylor" }, { id: "cc5", scheduledAt: "Jun 6", channel: "Email", title: "Vendor village preview", status: "draft", owner: "Jordan" }, { id: "cc6", scheduledAt: "Jun 9", channel: "Press", title: "Maya Cole headliner exclusive", status: "draft", owner: "Casey" }, ], // ContentStudioAsset{title, type, stage, owner, due} — GET /api/launch/content-studio contentStudio: [ { id: "a1", title: "Phase 1 ticket key art", type: "Graphic", stage: "published", owner: "Jordan", due: "May 28" }, { id: "a2", title: "Lineup teaser reel", type: "Video", stage: "approved", owner: "Jordan", due: "Jun 2" }, { id: "a3", title: "Sponsor sizzle: Drift", type: "Video", stage: "in-progress", owner: "Taylor", due: "Jun 5" }, { id: "a4", title: "Vendor village map graphic", type: "Graphic", stage: "in-progress", owner: "Morgan", due: "Jun 7" }, { id: "a5", title: "Clean Earth impact card", type: "Graphic", stage: "brief", owner: "Jordan", due: "Jun 10" }, { id: "a6", title: "Weekend recap template", type: "Deck", stage: "brief", owner: "Casey", due: "Jun 14" }, ], // Planners — emailSequences + outreach (community/press) folded together. emailSequences: [ { id: "e1", name: "Founders phase on-sale", audience: "Full list · 24k", sends: 3, status: "active", nextSend: "Jun 1" }, { id: "e2", name: "Abandoned checkout", audience: "Cart · auto", sends: 2, status: "active", nextSend: "rolling" }, { id: "e3", name: "Vendor village recruit", audience: "Local biz · 1.2k", sends: 4, status: "scheduled", nextSend: "Jun 6" }, { id: "e4", name: "Volunteer call", audience: "Treasure Coast", sends: 2, status: "draft", nextSend: "—" }, ], outreach: [ { id: "o1", kind: "Press", contact: "Billboard FL desk", status: "replied", owner: "Casey", note: "Wants headliner exclusive" }, { id: "o2", kind: "Press", contact: "TC Palm features", status: "sent", owner: "Casey", note: "Local angle pitch" }, { id: "o3", kind: "Community", contact: "Fort Pierce Main St.", status: "confirmed", owner: "Kam", note: "Storefront wristband promo" }, { id: "o4", kind: "Community", contact: "St. Lucie schools", status: "sent", owner: "Kam", note: "Student volunteer drive" }, ], // Public surfaces QA + claims checker — GET /api/launch/public-surfaces publicSurfaces: [ { id: "ps1", page: "Homepage", url: "/", status: "live", claim: "10% of every ticket to Clean Earth", mapsTo: "Clean Earth page", owner: "Jordan" }, { id: "ps2", page: "Tickets", url: "/tickets", status: "live", claim: "5 stages, 75+ artists", mapsTo: "Lineup", owner: "Jordan" }, { id: "ps3", page: "Lineup", url: "/lineup", status: "qa", claim: "Full schedule live", mapsTo: "Schedule page", owner: "Casey" }, { id: "ps4", page: "Auditions", url: "/auditions", status: "live", claim: "Vote with credits", mapsTo: "Fan dashboard", owner: "Jordan" }, { id: "ps5", page: "Partners", url: "/partners", status: "qa", claim: "Activation tiers", mapsTo: "Sponsor intake", owner: "Taylor" }, { id: "ps6", page: "Vendors", url: "/vendors", status: "draft",claim: "Apply for a booth", mapsTo: "Vendor intake", owner: "Morgan" }, ], // ---------- FINANCE (GET /api/launch/budget) ---------- // amounts in cents. kind: revenue|cost. budgetCategories: [ { id: "b1", kind: "revenue", label: "Ticket sales", targetCents: 6000000, currentCents: 700000 }, { id: "b2", kind: "revenue", label: "Sponsorships", targetCents: 3000000, currentCents: 600000 }, { id: "b3", kind: "revenue", label: "Vendor fees", targetCents: 1000000, currentCents: 200000 }, { id: "b4", kind: "cost", label: "Talent + production", targetCents: 120000000, currentCents: 71500000 }, { id: "b5", kind: "cost", label: "Venue + infrastructure",targetCents: 64000000, currentCents: 38000000 }, { id: "b6", kind: "cost", label: "Marketing", targetCents: 42000000, currentCents: 24800000 }, { id: "b7", kind: "cost", label: "Staffing + crew", targetCents: 36000000, currentCents: 14200000 }, ], budgetInvoices: [ { id: "i1", kind: "receivable", counterparty: "Drift Beverages", category: "Sponsorships", amountCents: 4000000, dueDate: "Jun 15", status: "pending" }, { id: "i2", kind: "receivable", counterparty: "Halo Beauty", category: "Sponsorships", amountCents: 1200000, dueDate: "Paid", status: "paid" }, { id: "i3", kind: "receivable", counterparty: "Northwave Tech", category: "Sponsorships", amountCents: 1800000, dueDate: "Jul 1", status: "draft" }, { id: "i4", kind: "payable", counterparty: "Apex Staging", category: "Venue + infrastructure", amountCents: 2850000, dueDate: "Jun 20", status: "pending" }, { id: "i5", kind: "payable", counterparty: "The Anchors (dep.)",category: "Talent + production", amountCents: 4750000, dueDate: "Jun 10", status: "pending" }, { id: "i6", kind: "payable", counterparty: "Coastal Power Co.", category: "Venue + infrastructure", amountCents: 920000, dueDate: "Paid", status: "paid" }, ], // ---------- ON-SITE (mobile-first) ---------- dayOfStages: [ { id: "st1", stage: "Main", status: "live", current: "Maya Cole", next: "Cane River", nextAt: "9:00 PM", headcount: 4200 }, { id: "st2", stage: "Frequency", status: "live", current: "Pillar Funk",next: "Quad Aux", nextAt: "9:30 PM", headcount: 1800 }, { id: "st3", stage: "Runway", status: "changeover", current: "—", next: "Sable Hours", nextAt: "8:45 PM", headcount: 900 }, { id: "st4", stage: "Lounge", status: "live", current: "DJ Vetiver", next: "Bluedrift", nextAt: "10:00 PM",headcount: 600 }, { id: "st5", stage: "Block", status: "hold", current: "—", next: "Cypher set", nextAt: "TBD", headcount: 0 }, ], crewCallSheets: [ { id: "cs1", shift: "Stage lighting · Main", callTime: "Sat 10:00 AM", location: "Main backstage", contact: "A. Rivera · 555-0142", day: "Sat" }, { id: "cs2", shift: "Hospitality · Green room",callTime: "Sat 12:00 PM", location: "Pavilion tent", contact: "Casey · 555-0188", day: "Sat" }, { id: "cs3", shift: "Gate + wristband", callTime: "Fri 2:00 PM", location: "Main entrance", contact: "Morgan · 555-0170", day: "Fri" }, { id: "cs4", shift: "Audio · Frequency", callTime: "Sun 11:00 AM", location: "Frequency FOH", contact: "J. Okafor · 555-0155", day: "Sun" }, ], incidents: [ { id: "inc1", kind: "Medical", stage: "Main", severity: "P2", status: "resolved", at: "7:42 PM", notes: "Heat exhaustion, treated on-site." }, { id: "inc2", kind: "Crowd", stage: "Frequency",severity: "P3", status: "open", at: "8:15 PM", notes: "Density at rail, added staff." }, { id: "inc3", kind: "Vendor", stage: "Village", severity: "P3", status: "open", at: "8:31 PM", notes: "Power trip at row C." }, ], weather: [ { id: "w1", day: "Fri Sep 18", forecast: "Clear", temp: "84°", wind: "8 mph", precip: "5%", trigger: "none" }, { id: "w2", day: "Sat Sep 19", forecast: "PM thunderstorms", temp: "87°", wind: "14 mph", precip: "60%", trigger: "Lightning hold plan armed" }, { id: "w3", day: "Sun Sep 20", forecast: "Partly cloudy", temp: "85°", wind: "10 mph", precip: "20%", trigger: "none" }, ], ticketPhases: [ { id: "tp1", phase: "Founders", status: "live", sold: 41, allocation: 1000, goLive: "Live", price: "$149" }, { id: "tp2", phase: "Phase 1", status: "ready", sold: 0, allocation: 3000, goLive: "Jun 15", price: "$179" }, { id: "tp3", phase: "Phase 2", status: "pending", sold: 0, allocation: 4000, goLive: "Jul 20", price: "$219" }, { id: "tp4", phase: "Gate", status: "pending", sold: 0, allocation: 2000, goLive: "Sep 18", price: "$260" }, ], venueZones: [ { id: "z1", label: "Main Stage", type: "stage", x: 22, y: 34 }, { id: "z2", label: "Frequency", type: "stage", x: 58, y: 28 }, { id: "z3", label: "Runway", type: "stage", x: 78, y: 48 }, { id: "z4", label: "Lounge", type: "stage", x: 40, y: 62 }, { id: "z5", label: "Block", type: "stage", x: 66, y: 72 }, { id: "z6", label: "Vendor Village", type: "vendor", x: 30, y: 48 }, { id: "z7", label: "Wellness Zone", type: "wellness",x: 50, y: 80 }, { id: "z8", label: "Command", type: "command", x: 12, y: 16 }, ], // ---------- WORKSPACE ---------- // NOTE: each teammate's `open` count is LIVE-DERIVED from launchTasks // (owner match, status != done) in TeamRoster — seed `open` is fallback only. launchTeam: [ { id: 1, name: "Kam Sandberg", role: "Festival Director", load: "high", color: "#C49800", open: 9 }, { id: 2, name: "Jordan Lee", role: "Marketing Lead", load: "high", color: "#B5006A", open: 12 }, { id: 3, name: "Taylor Brooks", role: "Sponsor Coordinator", load: "med", color: "#007A8A", open: 9 }, { id: 4, name: "Morgan Diaz", role: "Production Manager", load: "high", color: "#4C1285", open: 14 }, { id: 5, name: "Casey Nguyen", role: "Artist Relations", load: "med", color: "#00A8BC", open: 11 }, ], checklists: [ { id: "ch1", label: "Confirm all 5 stage power plans", owner: "Morgan", due: "Jun 16", cadence: "once", done: false }, { id: "ch2", label: "Sponsor assets received + approved", owner: "Taylor", due: "Jun 12", cadence: "once", done: false }, { id: "ch3", label: "Weekly social calendar published", owner: "Jordan", due: "Mondays",cadence: "weekly", done: true }, { id: "ch4", label: "Ticket phase readiness review", owner: "Kam", due: "Fridays",cadence: "weekly", done: false }, { id: "ch5", label: "Vendor COI + permits on file", owner: "Morgan", due: "Jun 20", cadence: "once", done: false }, { id: "ch6", label: "Artist travel + hospitality locked", owner: "Casey", due: "Aug 15", cadence: "once", done: false }, ], launchFiles: [ { id: "f1", type: "folder", name: "Sponsor contracts", parentId: null, items: 12, sizeBytes: 0, updatedAt: "1d" }, { id: "f2", type: "folder", name: "Stage plots", parentId: null, items: 5, sizeBytes: 0, updatedAt: "2d" }, { id: "f3", type: "folder", name: "Brand + creative", parentId: null, items: 38, sizeBytes: 0, updatedAt: "4h" }, { id: "f4", type: "file", name: "Run of show v3.pdf", parentId: null, items: 0, sizeBytes: 2400000, updatedAt: "3h", mime: "pdf" }, { id: "f5", type: "file", name: "Site map FINAL.pdf", parentId: null, items: 0, sizeBytes: 8800000, updatedAt: "1d", mime: "pdf" }, { id: "f6", type: "file", name: "Budget master.xlsx", parentId: null, items: 0, sizeBytes: 540000, updatedAt: "6h", mime: "xlsx" }, ], // 20-week production timeline (Timeline + Dependency view toggle) timeline: [ { week: "T-16", label: "Lineup + ticket phase 1", engine: "content", status: "doing", milestones: ["Headliners signed", "Phase 1 on-sale"] }, { week: "T-14", label: "Sponsor activations lock", engine: "sponsors", status: "todo", milestones: ["Footprints approved", "Assets due"] }, { week: "T-10", label: "Production design freeze", engine: "day-of", status: "todo", milestones: ["Stage plots", "Power plan"] }, { week: "T-6", label: "Phase 2 + vendor village", engine: "tickets", status: "todo", milestones: ["Phase 2 on-sale", "Vendors confirmed"] }, { week: "T-2", label: "Crew + call sheets", engine: "day-of", status: "todo", milestones: ["Crew booked", "Call sheets out"] }, { week: "T-0", label: "Festival weekend", engine: "day-of", status: "todo", milestones: ["Sep 18-20", "Gates open"] }, ], recap: { published: false, metrics: { attendance: 0, ticketRevenueCents: 0, sponsorRecapsSent: 0, cleanEarthCents: 0 }, highlights: [], }, // ---------- PROJECT-MANAGER SYNC (GET /api/launch/pm-integrations) ---------- // Two-way connectors. Each connector maps LCC surfaces (engines / tasks / // pipelines / timeline) onto that platform's NATIVE hierarchy. `mapping` // values are chosen from `containers`. direction: push|pull|two-way. // frequency: realtime|15m|hourly|manual. conflict: lcc|platform|recent. pmIntegrations: [ { id: "clickup", name: "ClickUp", key: "clickup", color: "#7B68EE", hierarchy: "Space · Folder · List · Task", connected: true, account: "ARGT Workspace", who: "kam@argt.com", direction: "two-way", frequency: "realtime", conflict: "recent", lastSync: "2 min ago", scope: { tasks: true, engines: true, pipelines: true, timeline: false }, containers: ["Space", "Folder", "List", "Task", "Status", "Gantt view", "Custom Field"], mapping: { root: "Space", engines: "Folder", tasks: "List", pipelines: "Status", timeline: "Gantt view" }, log: [ { at: "2 min ago", dir: "in", text: "Pulled 3 task updates from ClickUp" }, { at: "18 min ago", dir: "out", text: "Pushed 'Lock headliner contracts' status → ClickUp" }, { at: "1 h ago", dir: "out", text: "Created Folder 'Sponsors' in ARGT 2026 Space" }, ] }, { id: "asana", name: "Asana", key: "asana", color: "#F06A6A", hierarchy: "Project · Section · Task", connected: true, account: "ARGT 2026", who: "ops@argt.com", direction: "two-way", frequency: "15m", conflict: "lcc", lastSync: "12 min ago", scope: { tasks: true, engines: true, pipelines: false, timeline: true }, containers: ["Team", "Project", "Section", "Task", "Board column", "Timeline view", "Custom Field"], mapping: { root: "Project", engines: "Section", tasks: "Task", pipelines: "Board column", timeline: "Timeline view" }, log: [ { at: "12 min ago", dir: "out", text: "Synced 8 tasks into Asana sections" }, { at: "40 min ago", dir: "in", text: "Pulled due-date change on 'Founders cascade'" }, ] }, { id: "trello", name: "Trello", key: "trello", color: "#0079BF", hierarchy: "Board · List · Card", connected: true, account: "ARGT Launch", who: "kam@argt.com", direction: "two-way", frequency: "realtime", conflict: "recent", lastSync: "just now", scope: { tasks: true, engines: true, pipelines: true, timeline: false }, containers: ["Board", "List", "Card", "Label", "Checklist", "Calendar Power-Up"], mapping: { root: "Board", engines: "Label", tasks: "Card", pipelines: "List", timeline: "Calendar Power-Up" }, log: [ { at: "just now", dir: "out", text: "Moved 'Approve sponsor footprints' → Confirmed list" }, { at: "25 min ago", dir: "in", text: "Pulled new card from Artists pipeline board" }, ] }, { id: "basecamp", name: "Basecamp", key: "basecamp", color: "#2E9E5B", hierarchy: "Project · To-do list · To-do", connected: false, account: "", who: "", direction: "two-way", frequency: "hourly", conflict: "platform", lastSync: "—", scope: { tasks: true, engines: true, pipelines: false, timeline: true }, containers: ["Project", "To-do list", "To-do", "Card Table", "Column", "Schedule"], mapping: { root: "Project", engines: "To-do list", tasks: "To-do", pipelines: "Card Table", timeline: "Schedule" }, log: [] }, ], // ---------- PM RECONCILIATION QUEUE (GET /api/launch/pm-reconcile) ---------- // Divergences a two-way sync can't auto-resolve, surfaced for admin review. // type: conflict (edited both sides) | inbound (new in tool) | outbound // (not pushed) | deleted (removed in tool) | unmapped (no engine match). // `fields` lists diverging values for conflicts; others carry `summary`. pmReconcile: [ { id: "rc1", platform: "clickup", type: "conflict", taskTitle: "Lock headliner contracts", engine: "content", fields: [ { label: "Status", lcc: "Blocked", ext: "In progress" }, { label: "Due", lcc: "Jun 5", ext: "Jun 8" } ], detected: "4 min ago" }, { id: "rc2", platform: "asana", type: "conflict", taskTitle: "Approve sponsor activation footprints", engine: "sponsors", fields: [ { label: "Owner", lcc: "Taylor", ext: "Jordan" }, { label: "Status", lcc: "In progress", ext: "Done" } ], detected: "15 min ago" }, { id: "rc3", platform: "trello", type: "inbound", taskTitle: "Design Frequency stage backdrop", engine: "content", summary: "New card added to the Content list in Trello", detected: "22 min ago" }, { id: "rc4", platform: "clickup", type: "outbound", taskTitle: "Confirm 5-stage power + rigging plan", engine: "day-of", summary: "Created in LCC, not yet pushed to ClickUp", detected: "31 min ago" }, { id: "rc5", platform: "trello", type: "deleted", taskTitle: "Publish week-of social calendar", engine: "social", summary: "Card archived in Trello but still active in LCC", detected: "1 h ago" }, { id: "rc6", platform: "asana", type: "unmapped", taskTitle: "Photographer call sheet", engine: null, summary: "Pulled from Asana with no matching engine", detected: "1 h ago" }, ], // ---------- LAUNCH SETTINGS (GET /api/launch/settings) ---------- launchSettings: { festival: { name: "ARGT 2026", tagline: "Three days. Five stages. One coast.", startDate: "2026-09-18", endDate: "2026-09-20", gatesOpen: "13:00", venue: "Harbour Pointe", address: "Fort Pierce, FL", capacity: "10,000", artists: "75+", presentedBy: "The Private Plane", beneficiary: "Clean Earth Initiative", pledgePct: 10, stageNames: ["Main", "Frequency", "Runway", "Lounge", "Block"], }, branding: { accent: "magenta", theme: "Obsidian", logo: null }, alerting: { channels: { Email: true, SMS: true, Slack: true, Push: false }, events: { "Engine status change": true, "New high-priority flag": true, "Payment cleared": true, "Daily digest": true, "Incident P1/P2": true }, digestTime: "8:00 AM", escalation: { P1: "Call + SMS", P2: "SMS", P3: "In-app" }, }, integrations: [ { id: "ig1", name: "Stripe", purpose: "Payments + payouts", status: "connected", detail: "acct_ARGT2026 · live mode" }, { id: "ig2", name: "Mailgun", purpose: "Email sequences", status: "connected", detail: "send@argt.com · 24k contacts" }, { id: "ig3", name: "Twilio", purpose: "Day-of SMS + radio", status: "connected", detail: "+1 772 555 0100" }, { id: "ig4", name: "Cloudinary",purpose: "Media library", status: "connected", detail: "42 GB stored" }, { id: "ig5", name: "Slack", purpose: "Incident alerts", status: "action", detail: "#argt-ops · reauth needed" }, { id: "ig6", name: "Google Drive", purpose: "File workspace", status: "off", detail: "Not connected" }, ], roles: [ { id: "r1", name: "Kam Sandberg", access: "Owner", scope: "All engines" }, { id: "r2", name: "Jordan Lee", access: "Admin", scope: "Marketing, Digital" }, { id: "r3", name: "Taylor Brooks", access: "Editor", scope: "Sponsors, Finance" }, { id: "r4", name: "Morgan Diaz", access: "Editor", scope: "On-Site, Vendors" }, { id: "r5", name: "Casey Nguyen", access: "Editor", scope: "Content, Talent" }, ], storage: { usedGb: 42, totalGb: 200, retentionDays: 365 }, }, // ---------- ACCESS CONTROL (GET /api/launch/access) ---------- // Who can open which destination. Settings (festival config, invites, // roles, integrations) is restricted to superadmin/assigned roles. // In the fold this is enforced server-side; the UI hides what you can't open. launchAccess: { currentRole: "Owner", // demo control; real value comes from the session roles: ["Owner", "Admin", "Operator"], // sidebar destinations each role may open access: { Owner: ["today", "pipelines", "marketing", "finance", "onsite", "workspace", "settings"], Admin: ["today", "pipelines", "marketing", "finance", "onsite", "workspace", "settings"], Operator: ["today", "pipelines", "marketing", "finance", "onsite", "workspace"], }, invites: [ { id: "inv1", email: "alex@argt.com", role: "Editor", status: "pending", sent: "2d" }, { id: "inv2", email: "robin@argt.com", role: "Viewer", status: "pending", sent: "5d" }, ], }, // ---------- UNIVERSAL ---------- settingsProfile: { displayName: "Kam Sandberg", email: "kam@example.com", phone: "" }, settingsNotifications: { "Email — status changes": true, "Email — weekly digest": true, "SMS — urgent only": false, "Push — festival weekend": true, }, // ---------- DOWNLOAD / FILE-ACTION LEDGER ---------- // Tracks "downloaded / added to wallet / opened" actions so file-style // buttons give real feedback instead of being inert. In prod these map to // signed-URL fetches / wallet-pass generation. fileActions: {}, }; // ----- store internals ----- const clone = (o) => JSON.parse(JSON.stringify(o)); let state = load(); const subs = new Set(); function load() { try { const raw = JSON.parse(localStorage.getItem(LS_KEY) || "null"); if (raw && raw.__v === VERSION && raw.data) { // merge seed → stored so new collections appear after an update return Object.assign(clone(SEED), raw.data); } } catch (e) {} return clone(SEED); } function persist() { try { localStorage.setItem(LS_KEY, JSON.stringify({ __v: VERSION, data: state })); } catch (e) {} } const DB = { get(coll) { return state[coll]; }, set(coll, v) { const next = typeof v === "function" ? v(state[coll]) : v; state = Object.assign({}, state, { [coll]: next }); persist(); subs.forEach((fn) => fn()); return next; }, update(coll, fn) { return DB.set(coll, fn(state[coll])); }, subscribe(fn) { subs.add(fn); return () => subs.delete(fn); }, reset() { state = clone(SEED); persist(); subs.forEach((fn) => fn()); }, seed: SEED, }; window.ARGT_DB = DB; // ----- argtPing: lightweight global toast for file / calendar / external // actions that are live-only in the mock (download, add-to-wallet, open-in- // maps, message-production, request-changes). In the fold these handlers // call the real signed-URL / wallet / messaging endpoints. ----- window.argtPing = function argtPing(msg, coll) { if (coll) { try { DB.update("fileActions", (m) => Object.assign({}, m, { [coll]: Date.now() })); } catch (e) {} } try { const el = document.createElement("div"); el.setAttribute("role", "status"); el.style.cssText = "position:fixed;left:50%;bottom:28px;transform:translateX(-50%) translateY(8px);z-index:600;display:flex;align-items:center;gap:10px;padding:12px 18px;border-radius:999px;background:#3a2e60;border:1px solid #d82884;box-shadow:0 16px 40px rgba(0,0,0,.5);color:#f8f6ff;font:600 13.5px/1.3 'DM Sans',system-ui,sans-serif;max-width:calc(100vw - 32px);opacity:0;transition:opacity .18s,transform .18s;"; const dot = document.createElement("span"); dot.textContent = "✓"; dot.style.cssText = "width:22px;height:22px;flex:0 0 auto;border-radius:50%;display:grid;place-items:center;background:#d82884;color:#fff;font-size:12px;"; el.appendChild(dot); el.appendChild(document.createTextNode(msg)); document.body.appendChild(el); requestAnimationFrame(() => { el.style.opacity = "1"; el.style.transform = "translateX(-50%) translateY(0)"; }); setTimeout(() => { el.style.opacity = "0"; setTimeout(() => el.remove(), 220); }, 2600); } catch (e) {} }; // ----- React binding: subscribe + re-render + persist ----- window.useDB = function useDB(coll) { const [, force] = React.useReducer((x) => x + 1, 0); React.useEffect(() => DB.subscribe(force), []); const setValue = React.useCallback((v) => DB.set(coll, v), [coll]); return [DB.get(coll), setValue]; }; })();