// ADR-0079 โ€” Personal Space Starter Pack v1 // Canonical catalog: 6 universal tables, 5 Tier-A agents, 4 Tier-B (locked) agents. // All schemas follow ADR-0041 column-type canon: select / multi-select / number / date / url / checkbox / text / textarea / datetime. export const STARTER_PROJECT_NAME = 'Home'; export const STARTER_PROJECT_ICON = '๐Ÿ '; // Tier-A โ€” visible by default in agent picker export const TIER_A_AGENT_SLUGS = ['tor', 'journal', 'planner', 'researcher', 'agent-smith']; // Tier-B โ€” hidden by default; unlocked via MASTERMIND / MESHOK promo OR Settings โ†’ Add Agent export const TIER_B_AGENT_SLUGS = ['architect', 'developer-ralph', 'frontend-developer', 'sysadmin']; // Promo codes that auto-unlock the entire Tier-B coding pack on /auth/register. // Kept in sync with backend/services/SignupService.js KNOWN_PROMO_COHORTS. export const TIER_B_UNLOCK_PROMOS = ['MASTERMIND', 'MESHOK']; /** * Six universal starter tables. * * Seeded with a handful of sample rows per table (see STARTER_TABLE_SEEDS * below) so new users see how each table is meant to work; rows can be * deleted at any time. Privacy Invariant ยง5 was relaxed at owner request * (chat 3266, 2026-05-31) โ€” empty tables read as "broken" for first-run UX. * * Each entry is consumed by StarterPackService.createStarterTable(). */ // `slug` matches the key the frontend Welcome widget reads from // widget.config.starter_tables_map and shared/starter-pack-copy.json's card.table_slug. // Do not rename without updating both sides. export const STARTER_TABLES = [ { slug: 'daily-log', name: '๐Ÿ“” Daily Log', description: 'Daily journal: mood, energy, note', icon: '๐Ÿ“”', columns: [ { name: 'date', display: 'Date', type: 'date', order: 0, is_required: 1, config: { default_today: true } }, { name: 'note', display: 'Note', type: 'textarea', order: 1 }, { name: 'mood', display: 'Mood', type: 'select', order: 2, config: { options: [ { label: '๐Ÿ˜Š great', value: 'great', color: '#22c55e' }, { label: '๐Ÿ™‚ good', value: 'good', color: '#84cc16' }, { label: '๐Ÿ˜ neutral', value: 'neutral', color: '#6b7280' }, { label: '๐Ÿ˜• meh', value: 'meh', color: '#f59e0b' }, { label: '๐Ÿ˜ข rough', value: 'rough', color: '#ef4444' } ] } }, { name: 'energy', display: 'Energy', type: 'number', order: 3, config: { min: 1, max: 5, step: 1 } } ] }, { slug: 'goals-and-projects', name: '๐ŸŽฏ Goals & Projects', description: 'Goals and projects: what you want to move forward', icon: '๐ŸŽฏ', columns: [ { name: 'title', display: 'Title', type: 'text', order: 0, is_required: 1 }, { name: 'type', display: 'Type', type: 'select', order: 1, config: { options: [ { label: 'goal', value: 'goal', color: '#8b5cf6' }, { label: 'project', value: 'project', color: '#3b82f6' } ] } }, { name: 'status', display: 'Status', type: 'select', order: 2, config: { options: [ { label: 'idea', value: 'idea', color: '#6b7280' }, { label: 'doing', value: 'doing', color: '#f59e0b' }, { label: 'paused', value: 'paused', color: '#94a3b8' }, { label: 'done', value: 'done', color: '#22c55e' } ] } }, { name: 'deadline', display: 'Deadline', type: 'date', order: 3 }, { name: 'why', display: 'Why', type: 'textarea', order: 4 } ] }, { slug: 'habits', name: '๐Ÿ” Habits', description: 'Habits and trackers', icon: '๐Ÿ”', columns: [ { name: 'name', display: 'Name', type: 'text', order: 0, is_required: 1 }, { name: 'target', display: 'Period', type: 'select', order: 1, config: { options: [ { label: 'daily', value: 'daily', color: '#22c55e' }, { label: 'weekly', value: 'weekly', color: '#3b82f6' }, { label: 'monthly', value: 'monthly', color: '#8b5cf6' } ] } }, { name: 'streak', display: 'Streak', type: 'number', order: 2, config: { min: 0, default: 0 } }, { name: 'last_done', display: 'Last done', type: 'date', order: 3 }, { name: 'active', display: 'Active', type: 'checkbox', order: 4, config: { default: true } } ] }, { slug: 'people', name: '๐Ÿ‘ฅ People', description: 'People you stay in touch with', icon: '๐Ÿ‘ฅ', columns: [ { name: 'name', display: 'Name', type: 'text', order: 0, is_required: 1 }, { name: 'role', display: 'Role', type: 'text', order: 1 }, { name: 'last_contact', display: 'Last contact', type: 'date', order: 2 }, { name: 'note', display: 'Note', type: 'textarea', order: 3 }, { name: 'tags', display: 'Tags', type: 'multi-select', order: 4, config: { options: [] } } ] }, { slug: 'ideas', name: '๐Ÿ’ก Ideas', description: 'Ideas, links, notes', icon: '๐Ÿ’ก', columns: [ { name: 'title', display: 'Title', type: 'text', order: 0, is_required: 1 }, { name: 'tag', display: 'Tags', type: 'multi-select', order: 1, config: { options: [] } }, { name: 'source_url', display: 'Source', type: 'url', order: 2 }, { name: 'note', display: 'Note', type: 'textarea', order: 3 }, { name: 'created_at', display: 'Created', type: 'datetime', order: 4, is_system: 1 } ] }, { slug: 'wishlist', name: '๐Ÿ“š Wishlist', description: 'Things to try, read, see', icon: '๐Ÿ“š', columns: [ { name: 'title', display: 'What', type: 'text', order: 0, is_required: 1 }, { name: 'type', display: 'Type', type: 'select', order: 1, config: { options: [ { label: 'book', value: 'book' }, { label: 'course', value: 'course' }, { label: 'place', value: 'place' }, { label: 'thing', value: 'thing' }, { label: 'experience', value: 'experience' }, { label: 'food', value: 'food' } ] } }, { name: 'status', display: 'Status', type: 'select', order: 2, config: { options: [ { label: 'want', value: 'want', color: '#8b5cf6' }, { label: 'in-progress', value: 'in-progress', color: '#f59e0b' }, { label: 'have', value: 'have', color: '#3b82f6' }, { label: 'done', value: 'done', color: '#22c55e' } ] } }, { name: 'note', display: 'Note', type: 'textarea', order: 3 }, { name: 'link', display: 'Link', type: 'url', order: 4 } ] } ]; // Underscore convention โ€” matches shared/widget-presets.json + frontend WidgetRenderer // (commit 8d704f83 registered as `welcome_dashboard`). Do not switch to hyphen. export const WELCOME_WIDGET_PRESET = 'welcome_dashboard'; export const WELCOME_WIDGET_TITLE = '๐Ÿ  Welcome'; export const WELCOME_WIDGET_POSITION = { x: 0, y: 0, w: 12, h: 6 }; export const FEATURE_FLAG_KEY = 'starter_pack_enabled'; /** * Sample rows per starter-table slug โ€” built per call so date fields stay * relative to "today" (registration day) and never drift stale on disk. * StarterPackService inserts each row's `data` JSON verbatim into * `table_rows.data`. Keep keys in sync with the matching table's columns * above (column.name โ†’ key). * * Date columns store 'YYYY-MM-DD'; datetime store ISO; multi-select store * string arrays; select store option value (not label). */ export function buildStarterTableSeeds() { const today = new Date(); const todayIso = today.toISOString(); const offsetDate = (days) => { const d = new Date(today); d.setUTCDate(d.getUTCDate() + days); return d.toISOString().slice(0, 10); }; return { 'daily-log': [ { date: offsetDate(0), note: 'Day one. Set up CRM, figuring out what goes where.', mood: 'good', energy: 4 }, { date: offsetDate(-1), note: 'Decided to keep a journal โ€” let\'s see how long it lasts.', mood: 'neutral', energy: 3 }, { date: offsetDate(-2), note: 'Slept badly, pulled the day through on coffee.', mood: 'meh', energy: 2 }, { date: offsetDate(-3), note: 'Long walk and met up with a friend. Recharged.', mood: 'great', energy: 5 }, { date: offsetDate(-7), note: 'Sick all week. Only now starting to feel human again.', mood: 'rough', energy: 1 } ], 'goals-and-projects': [ { title: 'Use CRM as a second brain', type: 'project', status: 'doing', deadline: offsetDate(14), why: 'Want one place for notes, goals and people.' }, { title: 'Read 12 books this year', type: 'goal', status: 'doing', deadline: offsetDate(150), why: 'Training attention and perspective.' }, { title: 'Save up for a vacation', type: 'goal', status: 'doing', deadline: offsetDate(90), why: 'Burned out โ€” need a reset.' }, { title: 'Launch a blog', type: 'project', status: 'idea', deadline: offsetDate(60), why: 'Share what I\'m learning.' }, { title: 'Get English to B2', type: 'goal', status: 'doing', deadline: offsetDate(180), why: 'Opens up work and content.' }, { title: 'Clean out the garage', type: 'project', status: 'paused', deadline: offsetDate(30), why: 'Chaos in the way of thinking.' } ], 'habits': [ { name: '10-min morning workout', target: 'daily', streak: 12, last_done: offsetDate(0), active: true }, { name: 'Read before bed', target: 'daily', streak: 5, last_done: offsetDate(-1), active: true }, { name: 'Duolingo English', target: 'daily', streak: 21, last_done: offsetDate(0), active: true }, { name: '5,000 steps walk', target: 'daily', streak: 0, last_done: offsetDate(-3), active: true }, { name: 'Sugar-free week', target: 'weekly', streak: 2, last_done: offsetDate(-2), active: true }, { name: '5-min meditation', target: 'daily', streak: 0, last_done: null, active: false } ], 'people': [ { name: 'Anton', role: 'college friend', last_contact: offsetDate(-7), note: 'Back from Georgia soon โ€” ask how the trip went.', tags: ['friend'] }, { name: 'Mom', role: 'mom', last_contact: offsetDate(-2), note: 'Birthday October 14th.', tags: ['family'] }, { name: 'Lena', role: 'designer colleague', last_contact: offsetDate(-14), note: 'Discuss the landing page rebrand.', tags: ['work'] }, { name: 'Dr. Ivanov', role: 'GP', last_contact: offsetDate(-45), note: 'Every six months โ€” general checkup.', tags: ['health'] }, { name: 'Igor', role: 'neighbor at the cabin', last_contact: offsetDate(-30), note: 'Helped with the fence โ€” invite him for tea.', tags: ['friend', 'local'] }, { name: 'Anna (mktg)', role: 'met at a conference', last_contact: offsetDate(-60), note: 'Promised a positioning consult.', tags: ['work', 'network'] } ], 'ideas': [ { title: 'Start a podcast with friends', tag: ['podcast'], source_url: '', note: 'Weekly, 30 minutes, one topic โ€” no filler.', created_at: todayIso }, { title: 'Habit: one letter a day', tag: ['habit', 'writing'], source_url: '', note: 'To anyone โ€” even future me.', created_at: todayIso }, { title: 'Productivity course โ€” after I figure it out myself', tag: ['business', 'education'], source_url: '', note: 'Only from real experience, not rewriting books.', created_at: todayIso }, { title: 'Minimalist travel bag', tag: ['design', 'travel'], source_url: '', note: 'One compartment, everything visible, fits under seat.', created_at: todayIso }, { title: 'Read "Deep Work" by Cal Newport', tag: ['book'], source_url: 'https://en.wikipedia.org/wiki/Deep_Work', note: 'Re-read at the start of each year.', created_at: todayIso }, { title: 'Post: "why I quit CRM three times"', tag: ['blog', 'writing'], source_url: '', note: 'Honest โ€” about failures, not success.', created_at: todayIso } ], 'wishlist': [ { title: 'Atlas Shrugged', type: 'book', status: 'want', note: 'Heard a million contradictory takes โ€” time to form my own.', link: '' }, { title: 'Rust course', type: 'course', status: 'want', note: 'Figure out why it beats Go for systems code.', link: 'https://www.rust-lang.org/learn' }, { title: 'Week in Georgia', type: 'place', status: 'want', note: 'Tbilisi + Kakheti. Don\'t tell Mom yet.', link: '' }, { title: 'AeroPress', type: 'thing', status: 'have', note: 'Bought it โ€” now learn to brew properly.', link: '' }, { title: 'Skydiving', type: 'experience', status: 'want', note: 'Once in a lifetime โ€” must do.', link: '' }, { title: 'Real ramen in Japan', type: 'food', status: 'want', note: 'Hokkaido, miso ramen โ€” they say it\'s a different beast.', link: '' } ] }; }