11 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick | 260406-j44 | execute | 1 |
|
true |
|
Purpose: Enable developers to quickly stand up a fully-populated dev environment with realistic data spanning all entity types — global items, tags, user collections, threads, setups, and settings.
Output: Two new files (dev-seed-data.ts for data, dev-seed.ts for the runner) and a db:seed:dev npm script.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@CLAUDE.md @src/db/schema.ts @src/db/seed-global-items.ts @src/db/global-items-seed.json @tests/helpers/db.ts @src/db/index.tsFrom src/db/schema.ts:
- users: { id (serial PK), logtoSub (text, unique), displayName (text), avatarUrl (text), bio (text) }
- categories: { id (serial PK), name (text), icon (text), userId (int FK users) } — unique(userId, name)
- items: { id (serial PK), name, weightGrams, priceCents, categoryId (FK), userId (FK), notes, productUrl, imageFilename, imageSourceUrl, quantity (default 1), globalItemId (FK nullable), purchasePriceCents }
- threads: { id (serial PK), name, status (default "active"), resolvedCandidateId, categoryId (FK), userId (FK) }
- threadCandidates: { id (serial PK), threadId (FK cascade), name, weightGrams, priceCents, categoryId (FK), notes, productUrl, imageFilename, imageSourceUrl, status (default "researching"), pros, cons, sortOrder, globalItemId (FK nullable) }
- setups: { id (serial PK), name, userId (FK), isPublic (default false) }
- setupItems: { id (serial PK), setupId (FK cascade), itemId (FK cascade), classification (default "base") }
- globalItems: { id (serial PK), brand, model, category, weightGrams, priceCents, imageUrl, description }
- tags: { id (serial PK), name (unique) }
- globalItemTags: { globalItemId (FK cascade), tagId (FK cascade) } — composite PK
- settings: { userId (FK), key (text), value (text) } — composite PK(userId, key)
From src/db/index.ts:
- db: drizzle instance connected to PostgreSQL via DATABASE_URL
From src/db/seed-global-items.ts (idempotent pattern to follow):
- Check
existing.length > 0before inserting - Accept optional
dbparameter with production db as default
Categories (8-10 with icons):
- Bags (briefcase), Shelter (tent), Sleep System (moon), Cooking (flame), Lighting (flashlight), Tools & Repair (wrench), Clothing (shirt), Water (droplets), Electronics (battery), Navigation (compass)
Global Items (35-45 items spanning categories). Use real bikepacking gear brands/models with realistic weights and prices. Examples per category:
- Bags: Revelate Designs Terrapin, Apidura Expedition Handlebar Pack, Ortlieb Frame-Pack, Rockgeist BarJam, Oveja Negra Superwedgie
- Shelter: Zpacks Duplex, Tarptent Stratospire, Durston X-Mid 1, Big Agnes Copper Spur HV UL1
- Sleep: Enlightened Equipment Enigma 20, Therm-a-Rest NeoAir XLite, Nemo Tensor Insulated, Sea to Summit Aeros Pillow
- Cooking: BRS-3000T, Soto Windmaster, Toaks 750ml, Snow Peak Ti-Mini Solo
- Lighting: Nitecore NU25, Lezyne Lite Drive, Fenix HL60R
- Tools: Park Tool IB-3, Lezyne CNC Chain Breaker, Gorilla Tape mini roll
- Clothing: Patagonia R1 Air, Frogg Toggs UL2 Rain Suit, Buff Merino Wool
- Water: Sawyer Squeeze, Katadyn BeFree, HydraPak Seeker 2L
- Electronics: Anker 10000 PD, Garmin inReach Mini 2
- Navigation: Wahoo ELEMNT BOLT, Caltopo printed maps holder
Each global item: { brand, model, category, weightGrams, priceCents, description } — use integers for priceCents (e.g., 67900 for $679.00).
Tags (reuse existing SEED_TAGS from seed-global-items.ts plus a few more):
- Existing tags are already seeded by
seedTags(), so do NOT re-seed them.
Tag assignments — array of { globalItemIndex, tagNames } mapping global items to tags by index position and tag name. Example: index 0 (Terrapin) gets ["saddlebag", "waterproof", "bikepacking"]. Assign 2-4 tags per global item.
User items (15-20 items for the dev user's collection):
- ~10 items linked to global items via
globalItemId(reference items). Use the index into the global items array. IncludepurchasePriceCentsfor some (actual price paid, sometimes different from MSRP). - ~5-7 standalone items with no globalItemId (custom/unique gear the user added manually)
- Spread across categories. Include notes on some, quantity > 1 on a couple.
Threads (3 threads):
- Active thread "Handlebar Bag Upgrade" in Bags category with 3 candidates (some catalog-linked via globalItemId index), statuses: researching/shortlisted/researching
- Active thread "Navigation Computer" in Electronics with 2 candidates
- Resolved thread "Camp Stove" in Cooking with 2 candidates, one marked "arrived"
Setups (2 setups):
- "Weekend Overnighter" — 6-8 items from the user's collection, mix of base/worn/consumable classifications, isPublic: true
- "Ultra-Light Day Ride" — 3-4 items, isPublic: false
Settings: weightUnit "g", currency "EUR"
Export everything as named constants with proper TypeScript types (using as const where appropriate for literal inference).
bunx tsc --noEmit src/db/dev-seed-data.ts 2>&1 | head -20
All seed data constants exported with proper types, no TypeScript errors
Structure:
- Import
dbfrom./index.ts, all schema tables from./schema.ts, all data from./dev-seed-data.ts, andseedGlobalItemsfrom./seed-global-items.ts - Main
seedDevData()async function:
Idempotency check: Query users table for a user with logtoSub = "dev-user-seed". If found, log "Dev seed data already exists, skipping." and return early. This single check gates the entire script since all other data depends on this user.
Insertion order (respects FK constraints):
- Call
seedGlobalItems(db)first — reuse existing function to populate global_items and tags - Insert dev user:
{ logtoSub: "dev-user-seed", displayName: "Dev User", bio: "Bikepacking enthusiast" }— capture returned user for userId FK - Insert categories (with userId from step 2) — capture returned rows for categoryId mapping
- Look up tag IDs by name from tags table (they were seeded in step 1) — build
tagNameToIdmap - Insert global item tag assignments using
globalItemTagstable — use the global item IDs from step 1 and tag IDs from step 4. Note:seedGlobalItemsdoes not return IDs, so queryglobalItemstable to get IDs by brand+model matching after seeding. - Insert user items (with userId, categoryId, globalItemId references) — capture returned rows for setup_items
- Insert threads (with userId, categoryId) — capture returned IDs
- Insert thread candidates (with threadId, categoryId, globalItemId) — for the resolved thread, set
resolvedCandidateIdon the thread after inserting candidates - Insert setups (with userId) — capture returned IDs
- Insert setup_items (with setupId, itemId references from step 6)
- Insert settings (with userId)
- Log summary: "Dev seed complete: X global items, X tags, X user items, X threads, X setups"
Script entry point: At bottom of file:
seedDevData()
.then(() => process.exit(0))
.catch((err) => { console.error("Seed failed:", err); process.exit(1); });
package.json: Add "db:seed:dev": "bun run src/db/dev-seed.ts" to scripts section.
Use db.insert(...).values(...).returning() to capture IDs needed for FK references. Use db.insert(...).values(...) (no returning) for leaf tables.
Wrap everything in a try/catch. On error, log the error and re-throw. Do NOT use transactions (PostgreSQL serial IDs and the idempotency check make this safe enough for dev seeding).
bunx tsc --noEmit src/db/dev-seed.ts 2>&1 | head -20
- bun run db:seed:dev executes without error on a fresh (migrated) database
- Re-running logs "already exists, skipping" and exits cleanly
- Database contains: 1 dev user, 8+ categories, 35+ global items with tag assignments, 15+ user items (some catalog-linked), 3 threads with candidates, 2 setups with items, settings
<success_criteria>
- Script populates all entity types: users, categories, global items, tags, global item tag links, items (reference + standalone), threads, candidates (some catalog-linked), setups, setup_items, settings
- Idempotent: safe to run multiple times
- Data is realistic bikepacking gear with accurate weights/prices
- Foreign key relationships are all valid
bun run db:seed:devis the only command needed </success_criteria>