docs(18): create phase plan for global items and public profiles
This commit is contained in:
190
.planning/phases/18-global-items-public-profiles/18-01-PLAN.md
Normal file
190
.planning/phases/18-global-items-public-profiles/18-01-PLAN.md
Normal file
@@ -0,0 +1,190 @@
|
||||
---
|
||||
phase: 18-global-items-public-profiles
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- src/db/schema.ts
|
||||
- src/shared/schemas.ts
|
||||
- src/shared/types.ts
|
||||
- src/db/global-items-seed.json
|
||||
autonomous: true
|
||||
requirements: [GLOB-01, GLOB-02, PROF-01, PROF-03]
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "globalItems table exists with brand, model, category, weightGrams, priceCents, imageUrl, description, createdAt columns"
|
||||
- "itemGlobalLinks junction table exists linking items to globalItems"
|
||||
- "users table has displayName, avatarUrl, bio nullable columns"
|
||||
- "setups table has isPublic boolean column defaulting to false"
|
||||
- "Zod schemas exist for global item search, item linking, profile update, and setup visibility"
|
||||
- "Types are inferred from Zod schemas and Drizzle tables, not manually duplicated"
|
||||
artifacts:
|
||||
- path: "src/db/schema.ts"
|
||||
provides: "globalItems, itemGlobalLinks tables + users profile cols + setups isPublic"
|
||||
contains: "globalItems"
|
||||
- path: "src/shared/schemas.ts"
|
||||
provides: "searchGlobalItemsSchema, linkItemSchema, updateProfileSchema"
|
||||
contains: "searchGlobalItemsSchema"
|
||||
- path: "src/shared/types.ts"
|
||||
provides: "GlobalItem, ItemGlobalLink, UpdateProfile, LinkItem types"
|
||||
contains: "GlobalItem"
|
||||
- path: "src/db/global-items-seed.json"
|
||||
provides: "Initial bikepacking gear catalog seed data"
|
||||
min_lines: 20
|
||||
key_links:
|
||||
- from: "src/shared/types.ts"
|
||||
to: "src/db/schema.ts"
|
||||
via: "Drizzle $inferSelect"
|
||||
pattern: "globalItems\\.\\$inferSelect"
|
||||
- from: "src/shared/types.ts"
|
||||
to: "src/shared/schemas.ts"
|
||||
via: "Zod z.infer"
|
||||
pattern: "z\\.infer.*updateProfileSchema"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Define all schema foundations for Phase 18: new database tables (globalItems, itemGlobalLinks), column additions to users (profile fields) and setups (isPublic), Zod validation schemas, TypeScript types, and seed data file.
|
||||
|
||||
Purpose: Every subsequent plan depends on these schema definitions. Defining contracts first prevents the scavenger hunt anti-pattern.
|
||||
Output: Updated schema.ts, schemas.ts, types.ts, and global-items-seed.json
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/18-global-items-public-profiles/18-CONTEXT.md
|
||||
@.planning/phases/18-global-items-public-profiles/18-RESEARCH.md
|
||||
|
||||
@src/db/schema.ts
|
||||
@src/shared/schemas.ts
|
||||
@src/shared/types.ts
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Schema tables and column additions</name>
|
||||
<files>src/db/schema.ts</files>
|
||||
<read_first>src/db/schema.ts</read_first>
|
||||
<action>
|
||||
Add `boolean` to the drizzle-orm/pg-core imports (per D-01, D-12).
|
||||
|
||||
Add the `globalItems` table per D-01:
|
||||
- `id: serial("id").primaryKey()`
|
||||
- `brand: text("brand").notNull()`
|
||||
- `model: text("model").notNull()`
|
||||
- `category: text("category")`
|
||||
- `weightGrams: doublePrecision("weight_grams")`
|
||||
- `priceCents: integer("price_cents")`
|
||||
- `imageUrl: text("image_url")`
|
||||
- `description: text("description")`
|
||||
- `createdAt: timestamp("created_at").defaultNow().notNull()`
|
||||
|
||||
Add the `itemGlobalLinks` junction table per D-02:
|
||||
- `id: serial("id").primaryKey()`
|
||||
- `itemId: integer("item_id").notNull().references(() => items.id, { onDelete: "cascade" }).unique()` — each user item links to at most one global item
|
||||
- `globalItemId: integer("global_item_id").notNull().references(() => globalItems.id, { onDelete: "cascade" })`
|
||||
|
||||
Extend the `users` table per D-08 — add three nullable text columns:
|
||||
- `displayName: text("display_name")`
|
||||
- `avatarUrl: text("avatar_url")`
|
||||
- `bio: text("bio")`
|
||||
|
||||
Extend the `setups` table per D-12 — add:
|
||||
- `isPublic: boolean("is_public").notNull().default(false)`
|
||||
|
||||
Place new tables after setupItems section. Export all new tables.
|
||||
|
||||
After schema changes, run `bun run db:generate` to create the migration, then `bun run db:push` to verify it applies cleanly.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>bun run db:generate 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- grep -q "globalItems" src/db/schema.ts
|
||||
- grep -q "itemGlobalLinks" src/db/schema.ts
|
||||
- grep -q "displayName" src/db/schema.ts
|
||||
- grep -q "isPublic" src/db/schema.ts
|
||||
- grep -q "boolean" src/db/schema.ts
|
||||
</acceptance_criteria>
|
||||
<done>All four schema additions (globalItems table, itemGlobalLinks table, users profile columns, setups isPublic) are defined and exported. Migration generated successfully.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Zod schemas, types, and seed data</name>
|
||||
<files>src/shared/schemas.ts, src/shared/types.ts, src/db/global-items-seed.json</files>
|
||||
<read_first>src/shared/schemas.ts, src/shared/types.ts</read_first>
|
||||
<action>
|
||||
**schemas.ts** — Add the following Zod schemas at the end of the file:
|
||||
|
||||
1. `searchGlobalItemsSchema` per D-04 and D-16:
|
||||
```
|
||||
z.object({ q: z.string().optional() })
|
||||
```
|
||||
|
||||
2. `linkItemSchema` per D-18:
|
||||
```
|
||||
z.object({ globalItemId: z.number().int().positive() })
|
||||
```
|
||||
|
||||
3. `updateProfileSchema` per D-08, D-21:
|
||||
```
|
||||
z.object({
|
||||
displayName: z.string().max(100).optional(),
|
||||
avatarUrl: z.string().optional(),
|
||||
bio: z.string().max(500).optional(),
|
||||
})
|
||||
```
|
||||
|
||||
4. Update the existing `updateSetupSchema` to include `isPublic` per D-12, D-14:
|
||||
Add `isPublic: z.boolean().optional()` to the existing schema object.
|
||||
|
||||
5. Update the existing `createSetupSchema` if it exists — add `isPublic: z.boolean().optional().default(false)`.
|
||||
|
||||
**types.ts** — Add type exports:
|
||||
- `export type GlobalItem = typeof globalItems.$inferSelect;` (import globalItems, itemGlobalLinks from schema)
|
||||
- `export type ItemGlobalLink = typeof itemGlobalLinks.$inferSelect;`
|
||||
- `export type SearchGlobalItems = z.infer<typeof searchGlobalItemsSchema>;`
|
||||
- `export type LinkItem = z.infer<typeof linkItemSchema>;`
|
||||
- `export type UpdateProfile = z.infer<typeof updateProfileSchema>;`
|
||||
|
||||
**global-items-seed.json** — Create per D-06, D-07. Array of 15-20 bikepacking gear items covering categories like bags (frame bags, handlebar bags, saddle bags), shelters (tents, bivvies, tarps), sleep systems (sleeping bags, pads), cooking, hydration, and lighting. Each object has: `brand`, `model`, `category`, `weightGrams`, `priceCents`, `description`. Use real product names and approximate specs (e.g., Revelate Designs Terrapin, Apidura Expedition Handlebar Pack, Sea to Summit Spark SP1, MSR PocketRocket 2, Nemo Tensor Ultralight). Do NOT include `id` or `createdAt`.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>bun run lint 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- grep -q "searchGlobalItemsSchema" src/shared/schemas.ts
|
||||
- grep -q "linkItemSchema" src/shared/schemas.ts
|
||||
- grep -q "updateProfileSchema" src/shared/schemas.ts
|
||||
- grep -q "GlobalItem" src/shared/types.ts
|
||||
- grep -q "UpdateProfile" src/shared/types.ts
|
||||
- test -f src/db/global-items-seed.json
|
||||
</acceptance_criteria>
|
||||
<done>Zod schemas cover global item search, item linking, profile update, and setup visibility. Types inferred from schemas and Drizzle tables. Seed file has 15-20 bikepacking items with real product names.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `bun run lint` passes with no errors
|
||||
- `grep -c "export const" src/db/schema.ts` shows new table exports
|
||||
- `bun run db:generate` creates a clean migration
|
||||
- Seed JSON is valid: `node -e "JSON.parse(require('fs').readFileSync('src/db/global-items-seed.json','utf8'))"`
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
Schema.ts has globalItems, itemGlobalLinks, user profile columns, and setup isPublic. Schemas.ts has all new Zod validators. Types.ts exports all new types. Seed JSON file exists with 15-20 items. Lint passes.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/18-global-items-public-profiles/18-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user