docs(18): create phase plan for global items and public profiles
This commit is contained in:
205
.planning/phases/18-global-items-public-profiles/18-05-PLAN.md
Normal file
205
.planning/phases/18-global-items-public-profiles/18-05-PLAN.md
Normal file
@@ -0,0 +1,205 @@
|
||||
---
|
||||
phase: 18-global-items-public-profiles
|
||||
plan: 05
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on: ["18-03"]
|
||||
files_modified:
|
||||
- src/client/hooks/useProfile.ts
|
||||
- src/client/routes/users/$userId.tsx
|
||||
- src/client/routes/settings.tsx
|
||||
- src/client/routes/setups/index.tsx
|
||||
- src/client/components/ProfileSection.tsx
|
||||
- src/client/components/PublicSetupCard.tsx
|
||||
autonomous: false
|
||||
requirements: [PROF-01, PROF-02, PROF-03, PROF-04, PROF-05]
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "User can edit display name, avatar, and bio in settings page"
|
||||
- "Public profile page at /users/:id shows display name, avatar, bio, and public setups"
|
||||
- "Public profile page works without login (no auth required)"
|
||||
- "User can toggle a setup between public and private in the setup detail/edit view"
|
||||
- "Public setups appear on the owner's profile page; private ones do not"
|
||||
artifacts:
|
||||
- path: "src/client/hooks/useProfile.ts"
|
||||
provides: "usePublicProfile, useUpdateProfile hooks"
|
||||
exports: ["usePublicProfile", "useUpdateProfile"]
|
||||
- path: "src/client/routes/users/$userId.tsx"
|
||||
provides: "Public profile page"
|
||||
min_lines: 40
|
||||
- path: "src/client/components/ProfileSection.tsx"
|
||||
provides: "Profile edit form within settings"
|
||||
min_lines: 30
|
||||
- path: "src/client/components/PublicSetupCard.tsx"
|
||||
provides: "Card for setup shown on public profile"
|
||||
min_lines: 15
|
||||
key_links:
|
||||
- from: "src/client/routes/users/$userId.tsx"
|
||||
to: "src/client/hooks/useProfile.ts"
|
||||
via: "usePublicProfile hook"
|
||||
pattern: "usePublicProfile"
|
||||
- from: "src/client/hooks/useProfile.ts"
|
||||
to: "/api/users/:id/profile"
|
||||
via: "apiGet fetch"
|
||||
pattern: "apiGet.*users.*profile"
|
||||
- from: "src/client/routes/settings.tsx"
|
||||
to: "src/client/components/ProfileSection.tsx"
|
||||
via: "component import"
|
||||
pattern: "ProfileSection"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Build the user profile and public sharing client: profile edit section in settings, public profile page, setup visibility toggle, and public setup cards.
|
||||
|
||||
Purpose: Delivers the client-side experience for PROF-01 (profile edit), PROF-02 (public profile), PROF-03 (setup toggle), PROF-04 (public setup view), PROF-05 (profile lists public setups).
|
||||
Output: useProfile hook, public profile page, ProfileSection component, PublicSetupCard, updated settings and setup views
|
||||
</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/phases/18-global-items-public-profiles/18-CONTEXT.md
|
||||
@.planning/phases/18-global-items-public-profiles/18-RESEARCH.md
|
||||
@.planning/phases/18-global-items-public-profiles/18-03-SUMMARY.md
|
||||
|
||||
@src/client/routes/settings.tsx
|
||||
@src/client/routes/setups/index.tsx
|
||||
@src/client/hooks/useItems.ts
|
||||
@src/client/lib/api.ts
|
||||
|
||||
<interfaces>
|
||||
<!-- API endpoints from Plan 03: -->
|
||||
PUT /api/auth/profile { displayName?, avatarUrl?, bio? } -> updated user (auth required)
|
||||
GET /api/users/:id/profile -> { id, displayName, avatarUrl, bio, setups: [{ id, name, createdAt }] } (no auth)
|
||||
GET /api/setups/:id/public -> { id, name, isPublic, items: [...], totalWeight, totalCost } (no auth, 404 if private)
|
||||
|
||||
<!-- Setup now includes isPublic in responses from Plan 03 -->
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Profile hooks and profile edit UI</name>
|
||||
<files>src/client/hooks/useProfile.ts, src/client/components/ProfileSection.tsx, src/client/routes/settings.tsx</files>
|
||||
<read_first>src/client/routes/settings.tsx, src/client/hooks/useItems.ts, src/client/lib/api.ts</read_first>
|
||||
<action>
|
||||
**useProfile.ts** hook: Create at `src/client/hooks/useProfile.ts`.
|
||||
|
||||
1. `usePublicProfile(userId: number | null)` — `useQuery` with key `["profiles", userId]`, fetches `apiGet("/api/users/${userId}/profile")`, `enabled: userId != null`.
|
||||
|
||||
2. `useUpdateProfile()` — `useMutation` calling `apiPut("/api/auth/profile", data)`. On success, invalidate `["profiles"]` query key. Return mutation.
|
||||
|
||||
**ProfileSection.tsx**: Create at `src/client/components/ProfileSection.tsx`. Per D-09.
|
||||
|
||||
A form section that contains:
|
||||
- Display name text input (max 100 chars) with label
|
||||
- Bio textarea (max 500 chars) with character counter
|
||||
- Avatar: Show current avatar if set, with a "Change avatar" button that opens the existing ImageUpload component (per D-11, reuse existing image upload + MinIO storage). After upload, set avatarUrl to the returned filename (the route will handle presigned URL generation).
|
||||
- Save button calling `useUpdateProfile()` mutation
|
||||
- Success/error toast feedback (use existing toast pattern if available, otherwise simple inline message)
|
||||
|
||||
Pre-populate form with current profile data. On mount, fetch current user profile via an appropriate mechanism (could be from auth context or a dedicated endpoint).
|
||||
|
||||
**settings.tsx**: Read the existing settings page. Add a "Profile" section at the top (before API Keys and other settings). Import and render `<ProfileSection />`. The section should have a heading "Profile" with a brief description "Your public profile information."
|
||||
</action>
|
||||
<verify>
|
||||
<automated>bun run lint 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- grep -q "usePublicProfile" src/client/hooks/useProfile.ts
|
||||
- grep -q "useUpdateProfile" src/client/hooks/useProfile.ts
|
||||
- grep -q "ProfileSection" src/client/components/ProfileSection.tsx
|
||||
- grep -q "ProfileSection" src/client/routes/settings.tsx
|
||||
</acceptance_criteria>
|
||||
<done>Profile edit section in settings page with display name, bio, and avatar upload. Hooks handle fetch and mutation. Form saves correctly.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Public profile page and setup visibility toggle</name>
|
||||
<files>src/client/routes/users/$userId.tsx, src/client/components/PublicSetupCard.tsx, src/client/routes/setups/index.tsx</files>
|
||||
<read_first>src/client/routes/setups/index.tsx, src/client/hooks/useProfile.ts</read_first>
|
||||
<action>
|
||||
**users/$userId.tsx**: Create at `src/client/routes/users/$userId.tsx`. Per D-10.
|
||||
|
||||
Public profile page (no auth required to view):
|
||||
- TanStack Router: `createFileRoute("/users/$userId")` with params
|
||||
- Fetch profile with `usePublicProfile(Number(userId))`
|
||||
- Layout: Avatar (or placeholder icon), display name (or "User #{id}" fallback), bio text
|
||||
- Below profile: "Public Setups" heading with grid of PublicSetupCard components
|
||||
- Empty state if no public setups: "No public setups yet"
|
||||
- Loading skeleton while fetching
|
||||
- 404 handling if user not found
|
||||
|
||||
**PublicSetupCard.tsx**: Create at `src/client/components/PublicSetupCard.tsx`.
|
||||
|
||||
A card for setups shown on the public profile:
|
||||
- Setup name as heading
|
||||
- Created date formatted
|
||||
- Links to `/setups/${id}/public` for the public view (or you can create an inline expandable view)
|
||||
- Light card styling with subtle border/shadow, matching existing setup cards
|
||||
|
||||
**setups/index.tsx or setup detail**: Update the setup list or detail view to include the isPublic toggle per D-14.
|
||||
|
||||
- In the setup detail/edit view, add a toggle switch or checkbox labeled "Public" next to the setup name
|
||||
- When toggled, call the existing setup update mutation with `isPublic: true/false`
|
||||
- Show a small icon or badge on the setup list indicating public status (e.g., a globe icon or "Public" chip)
|
||||
- Default all existing setups to show as private (per D-12)
|
||||
</action>
|
||||
<verify>
|
||||
<automated>bun run lint 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- test -f "src/client/routes/users/\$userId.tsx"
|
||||
- grep -q "usePublicProfile" "src/client/routes/users/\$userId.tsx"
|
||||
- test -f src/client/components/PublicSetupCard.tsx
|
||||
- grep -q "isPublic\|public" src/client/routes/setups/index.tsx
|
||||
</acceptance_criteria>
|
||||
<done>Public profile page shows user info and public setups. Setup detail has visibility toggle. Public setups appear on profile. Private setups are hidden from profile.</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking">
|
||||
<name>Task 3: Verify profiles and public sharing UI</name>
|
||||
<files>none</files>
|
||||
<action>
|
||||
Human verification of user profiles and public sharing. Review what was built: profile edit in settings, public profile page, setup visibility toggle.
|
||||
|
||||
Steps to verify:
|
||||
1. Start dev server: `bun run dev`
|
||||
2. Go to Settings — should see a new "Profile" section at top
|
||||
3. Enter a display name and bio, save — should show success
|
||||
4. Upload an avatar image — should display
|
||||
5. Go to Setups, open a setup detail, find the "Public" toggle
|
||||
6. Toggle a setup to public
|
||||
7. Navigate to `/users/{your-user-id}` — should see profile with the public setup listed
|
||||
8. Open an incognito/private window (no auth)
|
||||
9. Visit the same `/users/{id}` URL — should show profile and public setup without login
|
||||
10. Toggle the setup back to private — it should disappear from the profile page
|
||||
</action>
|
||||
<verify>
|
||||
<automated>bun run build 2>&1 | tail -3</automated>
|
||||
</verify>
|
||||
<done>User approves profiles and sharing UI: profile edit works, public profile shows correct data, setup toggle works, unauthenticated access functions correctly.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `bun run lint` passes
|
||||
- `bun run build` succeeds
|
||||
- Visual verification: profile edit, public profile page, setup toggle, and public access
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
Profile can be edited in settings. Public profile page works without auth. Setup visibility toggle works. Public setups appear on profile, private ones don't. Avatar upload uses existing image infrastructure.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/18-global-items-public-profiles/18-05-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user