# Phase 32: Setup Sharing System - Context **Gathered:** 2026-04-13 **Status:** Ready for planning ## Phase Boundary Setup owners can toggle visibility between private, link-shared, and public. Share links use secret tokens with configurable expiration and revocation. Schema includes full future-proofing for person-specific shares, write permissions, and collaborative editing — but only read-only link sharing is enforced in this phase. ## Implementation Decisions ### Visibility Model - **D-01:** Three visibility levels: `private` (owner only), `link` (accessible via share token, not discoverable), `public` (discoverable on feed/profiles) - **D-02:** Replace `isPublic: boolean` column on `setups` table with `visibility: text` column (`private`/`link`/`public`). Column on table for query speed — discovery feed queries `WHERE visibility = 'public'` - **D-03:** Setting visibility to `private` deactivates (does not delete) all share links. Switching back to `link` reactivates them - **D-04:** Share links use secret tokens — the setup's numeric ID alone is not sufficient for link-shared access ### Share Links - **D-05:** Multiple share links can coexist per setup, each independent with its own token, expiration, and revocation status - **D-06:** Share URLs: `/s/{token}` (short URL for sharing) AND `/setups/:id?share={token}` (both work, short URL is primary for sharing) - **D-07:** Default link expiration: 14 days. Options when creating: 7 days, 14 days, 30 days, infinite - **D-08:** Each link can be individually revoked without affecting other links - **D-09:** Only read-only link shares are functional in this phase. Write permission exists in schema but is not enforced ### Schema - **D-10:** Full `shares` table created now: id, setupId, token, permission (read/write), expiresAt (nullable = infinite), userId (nullable — null = link share, set = person-specific share), createdAt, revokedAt (nullable) - **D-11:** Person-specific shares (userId column) exist in schema but are not used in this phase - **D-12:** Write permission column exists but write-access is not enforced — no mutation permission checks ### Share UX - **D-13:** Share modal (Google Docs style) is the single UI for managing visibility AND share links - **D-14:** Share icon button replaces the current globe public/private toggle on setup detail page. Icon reflects current visibility state via color/icon variation - **D-15:** Modal contains: visibility picker (private/link/public), create share link with expiration picker, active share links list with copy/revoke actions - **D-16:** Desktop and mobile use the same share icon button opening the same modal ### Public Setup Presentation - **D-17:** Link-shared setup viewer UX: Claude's discretion — will pick based on existing setup detail page patterns (subtle shared context vs. identical to public view) - **D-18:** No changes to discovery feed or profile page visuals in this phase - **D-19:** Discovery feed query updated from `isPublic = true` to `visibility = 'public'` — same behavior, new column ### Claude's Discretion - Viewer experience for link-shared setups (shared banner/badge vs. clean view) — pick what fits the existing design patterns ### Folded Todos None — no relevant todos matched this phase's scope. ## Canonical References **Downstream agents MUST read these before planning or implementing.** No external specs — requirements fully captured in decisions above. ### Existing Implementation - `src/db/schema.ts` — Current `setups` table with `isPublic` boolean (line 118-127) - `src/server/services/setup.service.ts` — Setup CRUD with `isPublic` handling - `src/server/services/discovery.service.ts` — Discovery feed query using `isPublic = true` - `src/server/services/profile.service.ts` — `getPublicSetupWithItems()` for public viewing - `src/client/routes/setups/$setupId.tsx` — Setup detail page with current globe toggle (lines 177-203) - `src/client/hooks/useSetups.ts` — `usePublicSetup` hook (line 67) - `src/shared/schemas.ts` — Zod schemas with `isPublic` field (lines 88, 93) ## Existing Code Insights ### Reusable Assets - Setup detail page (`setups/$setupId.tsx`): Has desktop + mobile button patterns for the share button replacement - `useSetups` hooks: Mutation patterns for `updateSetup` — extend for visibility changes - `LucideIcon` component: Icons like `share-2`, `link`, `globe`, `lock` available for visibility states - Modal patterns: Used elsewhere in the app (thread creation, item add) — reuse for share modal ### Established Patterns - Service layer with DI (`db` as first param) for testability - Zod validation on route handlers via `@hono/zod-validator` - React Query mutations with cache invalidation - Detail pages (not panels) for complex interactions ### Integration Points - `src/db/schema.ts`: New `shares` table + modify `setups` table (isPublic → visibility) - `src/server/routes/setups.ts`: New share link CRUD endpoints - `src/server/routes/`: New `/s/:token` route for short share URLs - `src/server/services/setup.service.ts`: Update queries from isPublic to visibility - `src/server/services/discovery.service.ts`: Update feed query - `src/server/services/profile.service.ts`: Update public setup query - `src/client/routes/setups/$setupId.tsx`: Replace globe toggle with share button + modal - `src/shared/schemas.ts`: New share schemas, update setup schemas ## Specific Ideas - Share modal inspired by Google Docs share dialog — visibility picker at top, share links list below - When visibility is set to `private`, share links become inactive but aren't deleted — switching back to `link` reactivates them - Multiple shares coexist: e.g., one permanent read link + one 14-day read link simultaneously - Future: person-specific shares should influence discovery algorithm (deferred) ## Deferred Ideas - **Person-specific shares influencing discovery feed algorithm** — when direct shares exist between users, factor that into feed ranking. Belongs in a future personalization/social phase. - **Write-access share enforcement** — collaborative editing requires conflict resolution, real-time sync, and mutation permission checks. Belongs in a dedicated collaborative editing phase. - **Person-specific share UI** — inviting specific users by username/email to a setup. Needs user search/lookup. Future phase. --- *Phase: 32-setup-sharing-system* *Context gathered: 2026-04-13*