fix: tighten sharing and shadcn composition
CI / checks (push) Successful in 12m55s
CI / build (push) Successful in 15m16s

This commit is contained in:
ginnoir
2026-06-13 05:20:01 -05:00
parent e1774c802d
commit a312d4ce39
42 changed files with 1539 additions and 417 deletions
@@ -0,0 +1,141 @@
# React and shadcn Fixes Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Fix the security-sensitive share-link authorization gap and the highest-confidence shadcn Base UI composition issues from the audit.
**Architecture:** Add registry-level share authorization callbacks and require them in the generic share service before token creation and shared data loading. Update current modules to provide household/user-scoped authorization and share loaders, then align selected UI call sites with shadcn Base API.
**Tech Stack:** Next.js 15 App Router, TypeScript, Drizzle, shadcn/ui Base UI, Tailwind v4, Node test runner via `tsx --test`.
---
### Task 1: Share Authorization Helper
**Files:**
- Create: `tests/unit/share-authorization.test.ts`
- Create: `src/modules/_core/share-authorization.ts`
- Modify: `src/modules/_core/module.ts`
- [ ] **Step 1: Write the failing test**
Create tests for missing callbacks, denied callbacks, and allowed callbacks.
- [ ] **Step 2: Run test to verify it fails**
Run: `pnpm exec tsx --test tests/unit/share-authorization.test.ts`
Expected: failure because `share-authorization.ts` does not exist.
- [ ] **Step 3: Implement the helper and registry types**
Add `ShareContext`, `ensureEntityShareAuthorized`, `EntityTypeRegistration.canShareEntity`, and scoped `loadForShare` context typing.
- [ ] **Step 4: Run test to verify it passes**
Run: `pnpm exec tsx --test tests/unit/share-authorization.test.ts`
Expected: all tests pass.
### Task 2: Wire Authorization Into Share Service
**Files:**
- Modify: `src/modules/_core/share.ts`
- Modify: `src/app/s/[token]/page.tsx`
- [ ] **Step 1: Call `ensureEntityShareAuthorized` in `createShareLink`**
Require the active user and household to be authorized before token insertion.
- [ ] **Step 2: Pass household context into public share loading**
Call `entityReg.loadForShare(resolved.entityId, { householdId: resolved.householdId })`.
- [ ] **Step 3: Run typecheck**
Run: `pnpm typecheck`
Expected: type errors until module adapters are updated.
### Task 3: Add Module Share Adapters
**Files:**
- Modify: `src/modules/calendar/manifest.tsx`
- Modify: `src/modules/calendar/server/share-queries.ts`
- Modify: `src/modules/lists/manifest.tsx`
- Modify: `src/modules/lists/server/share-queries.ts`
- Modify: `src/modules/notes/manifest.tsx`
- Modify: `src/modules/notes/server/share-queries.ts`
- Modify: `src/modules/garden/manifest.tsx`
- Modify: `src/modules/garden/server/share-queries.ts`
- [ ] **Step 1: Implement `canShareEntity` for every shareable entity**
Use household scoping and existing private-calendar rules.
- [ ] **Step 2: Scope `loadForShare` queries by token household**
Require the public token household to match the entity household.
- [ ] **Step 3: Run typecheck**
Run: `pnpm typecheck`
Expected: pass.
### Task 4: Fix Base UI Select Composition
**Files:**
- Modify: `src/modules/calendar/components/calendar-shell.tsx`
- Modify: `src/components/theme-picker.tsx`
- [ ] **Step 1: Add `items` arrays and `SelectGroup` wrappers**
Keep existing labels and values; do not redesign layout.
- [ ] **Step 2: Run typecheck**
Run: `pnpm typecheck`
Expected: pass.
### Task 5: Targeted shadcn Menu and Icon Cleanup
**Files:**
- Modify: `src/components/dashboard-switcher.tsx`
- Modify: `src/components/dashboard-editor.tsx`
- Modify: `src/components/share-button.tsx`
- [ ] **Step 1: Wrap dropdown items in `DropdownMenuGroup`**
Preserve menu behavior.
- [ ] **Step 2: Replace icon sizing inside shadcn buttons/menu items**
Use `data-icon` where icons sit in `Button`; remove explicit `size-4 mr-*` from dropdown item icons.
- [ ] **Step 3: Run lint**
Run: `pnpm lint`
Expected: no new errors; existing warnings may remain.
### Task 6: Final Verification
**Files:**
- No direct edits.
- [ ] **Step 1: Run targeted test**
Run: `pnpm exec tsx --test tests/unit/share-authorization.test.ts`
Expected: pass.
- [ ] **Step 2: Run typecheck**
Run: `pnpm typecheck`
Expected: pass.
- [ ] **Step 3: Run lint**
Run: `pnpm lint`
Expected: exit 0; warnings only if pre-existing.
@@ -0,0 +1,35 @@
# React and shadcn Fixes Design
## Goal
Fix the audit findings that have security or correctness impact, and make a small targeted pass on shadcn Base UI composition without turning this into a broad visual rewrite.
## Approaches Considered
1. **Security-first, targeted UI cleanup.** Add a registry authorization hook for share links, implement it for current modules, fix Base `Select` usage, and clean up the compact dropdown/button issues found in the audit.
2. **Full shadcn migration sweep.** Replace all `.btn`, raw forms, raw colors, and hand-rolled overlays in one pass. This would touch many dirty files and blur behavior changes with style churn.
3. **Security only.** Fix share authorization and defer UI. This leaves known Base UI composition drift in place.
Chosen approach: **Option 1**. It fixes the exploitable path, handles the highest-confidence shadcn correctness issue, and leaves broad styling convergence to the existing shadcn-tier task docs.
## Architecture
Share authorization belongs in the entity registry, not in `_core` switch statements. Each shareable entity registration will expose `canShareEntity(id, ctx)` and the generic `createShareLink` action will require it to return true before inserting a token.
Public share rendering will also pass the token household into `loadForShare(id, ctx)` so loaders can scope database reads. This prevents a bad token row from loading an unrelated entity by id alone.
## UI Composition
The project uses shadcn `base-nova`, so `Select` roots need an `items` prop and `SelectItem` children should be wrapped in `SelectGroup`. The calendar and theme picker selects will be updated to that shape.
Compact menu/button drift will be cleaned where it does not require redesign: dropdown items should sit in `DropdownMenuGroup`, menu icons should rely on component icon sizing, and button icons should use `data-icon`.
## Testing
Add a small Node test around the new share authorization helper first. The test will prove that missing or false registry authorization rejects share creation and that approved entities pass through. Typecheck and lint will cover module hook signatures and Base UI prop usage.
## Out of Scope
- Full replacement of `.btn` and raw garden forms.
- Reworking command palette and quick-add sheet into shadcn dialogs.
- Measuring bundle deltas or adding dynamic imports for global overlays.