docs: add phase 32 plan summaries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-13 18:05:24 +02:00
parent 0b46eff243
commit 7eb5335a88
4 changed files with 151 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
# Plan 32-01 Summary: Schema Migration (isPublic -> visibility)
**Status:** Complete
**Commit:** edc9793
## What was done
1. **Schema changes** (`src/db/schema.ts`):
- Replaced `isPublic: boolean` with `visibility: text` (default "private") on setups table
- Added `shares` table with columns: id, setupId, token, permission, expiresAt, userId, createdAt, revokedAt
- Removed `boolean` import from drizzle-orm/pg-core
2. **Migration** (`drizzle-pg/0005_true_green_goblin.sql`):
- Creates shares table with FK constraints
- Adds visibility column with data migration (`UPDATE setups SET visibility = 'public' WHERE is_public = true`)
- Drops is_public column
3. **Full-stack isPublic -> visibility replacement** across 16 files:
- `src/shared/schemas.ts`: `z.enum(["private", "link", "public"])` replaces `z.boolean()`
- `src/server/services/setup.service.ts`: createSetup, getAllSetups, updateSetup
- `src/server/services/discovery.service.ts`: `eq(setups.visibility, "public")`
- `src/server/services/profile.service.ts`: Two occurrences updated
- `src/server/routes/account.ts`: Delete account reassignment query
- `src/client/hooks/useSetups.ts`: Types and mutation signatures
- `src/client/components/SetupCard.tsx`: Visibility badge (public=green, link=blue)
- `src/client/components/SetupsView.tsx`: Passes visibility prop
- `src/client/routes/setups/$setupId.tsx`: Temporary visibility badge with lock/link/globe icons
- `src/db/dev-seed.ts` and `src/db/dev-seed-data.ts`: Seed data updated
4. **Tests updated** across 4 test files (46 tests pass):
- `tests/services/profile.service.test.ts`
- `tests/services/discovery.service.test.ts`
- `tests/routes/discovery.test.ts`
- `tests/routes/profiles.test.ts`
- `tests/helpers/db.ts`: Added shares to truncation list
## Verification
- `bun run lint`: Passes (0 errors)
- All affected tests pass (46/46)
- Zero isPublic/is_public references in src/ (except unrelated `isPublicRoute` in __root.tsx)
- Zero isPublic references in tests/

View File

@@ -0,0 +1,43 @@
# Plan 32-02 Summary: Share Link Backend
**Status:** Complete
**Commit:** da159d1
## What was done
1. **Share service** (`src/server/services/share.service.ts`):
- `createShareLink`: 128-bit random base64url token, configurable expiration
- `getShareLinks`: Lists all shares for a setup (ownership verified)
- `revokeShareLink`: Sets revokedAt (ownership verified via join)
- `validateShareToken`: Returns setupId/permission, rejects expired/revoked/nonexistent
- `deactivateShareLinks`: Bulk revoke all active links for a setup
- `reactivateShareLinks`: Clears revokedAt on non-expired shares
2. **Visibility transition side effects** (`src/server/services/setup.service.ts`):
- `updateSetup` now detects visibility transitions and calls deactivate/reactivate
- Uses dynamic import to avoid circular dependency
3. **New function** `getSetupWithItemsById` for share-token-authorized access (no user/visibility check)
4. **API routes** (added to `src/server/routes/setups.ts`):
- `POST /api/setups/:id/shares` — Create share link (auth required)
- `GET /api/setups/:id/shares` — List share links (auth required)
- `DELETE /api/setups/:id/shares/:shareId` — Revoke share link (auth required)
5. **Public endpoints** (added to `src/server/index.ts`):
- `GET /api/shared/:token` — Access setup via share token (no auth)
- `GET /s/:token` — Short URL redirect to `/setups/:id?share=:token`
- Auth middleware skip for `/api/shared/` and rate limiting applied
6. **Share schema** (`src/shared/schemas.ts`):
- `createShareLinkSchema` with `expiresInDays: 7 | 14 | 30 | null`
7. **Tests** (`tests/services/share.service.test.ts`):
- 16 tests covering all service functions and visibility transitions
- All pass (62/62 across 5 affected test files)
## Verification
- `bun run lint`: Passes
- All share service tests pass (16/16)
- All affected tests pass (62/62 across 5 files)

View File

@@ -0,0 +1,33 @@
# Plan 32-03 Summary: Share Modal UI
**Status:** Complete
**Commit:** 7003e99
## What was done
1. **Share hooks** (`src/client/hooks/useShares.ts`):
- `useShareLinks(setupId)` — Query hook for fetching share links
- `useCreateShareLink(setupId)` — Mutation with query invalidation
- `useRevokeShareLink(setupId)` — Mutation with query invalidation
2. **ShareModal component** (`src/client/components/ShareModal.tsx`):
- Visibility picker with three options (private/link/public) — immediate API call on change
- Color-coded options: gray (private), blue (link), green (public)
- Share link creation with expiration dropdown (7/14/30 days, no expiration)
- Active links list with copy-to-clipboard and revoke actions
- Deactivation warning when links exist and switching to private
- Empty state "No share links yet"
- Escape key and overlay click to close
- Responsive: works on desktop and mobile
3. **Setup detail page update** (`src/client/routes/setups/$setupId.tsx`):
- Replaced static visibility badge with interactive share button
- Desktop: "Share" text + visibility icon
- Mobile: Icon-only with 44px touch target
- ShareModal rendered with visibility change wired to `updateSetup.mutate`
## Verification
- `bun run lint`: Passes
- ShareModal follows existing modal patterns (overlay, escape key, z-50)
- Colors match UI-SPEC: gray-500/gray-50, blue-600/blue-50, green-700/green-50

View File

@@ -0,0 +1,33 @@
# Plan 32-04 Summary: Shared Setup Viewer
**Status:** Complete
**Commit:** 0b46eff
## What was done
1. **useSharedSetup hook** (`src/client/hooks/useSetups.ts`):
- Fetches `/api/shared/:token` with retry disabled (404 = invalid token)
- Returns same SetupWithItems type as other setup hooks
2. **Route search params** (`src/client/routes/setups/$setupId.tsx`):
- Added `validateSearch` with Zod schema for `share` query param
- Three-way data source: share token > authenticated owner > public viewer
3. **Shared setup banner**:
- Blue banner with link icon: "Shared setup" shown when share token present
- Positioned above the sticky header bar
4. **Error state for invalid tokens**:
- Shows "Link not available" with link icon and descriptive text
- Renders instead of the normal page when shared fetch errors
5. **Read-only mode**:
- `showOwnerControls` computed from `!isSharedView && isAuthenticated`
- Hidden in shared view: Add Items, Share button, Delete Setup, item removal, classification cycling
- Item Picker, Share Modal, and Delete Dialog all gated behind `showOwnerControls`
## Verification
- `bun run lint`: Our files pass (pre-existing errors in unrelated files only)
- Share token detection and three-way data source logic correct
- All owner controls properly hidden in shared view