Add PLANS.md and MEMORY.md to .gitignore and untrack PLANS.md
These are local planning/memory files that should not be in the repository. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,3 +24,7 @@ Thumbs.db
|
|||||||
# Vite
|
# Vite
|
||||||
vite.config.js.timestamp-*
|
vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
|
|
||||||
|
# Project planning (local only)
|
||||||
|
PLANS.md
|
||||||
|
MEMORY.md
|
||||||
|
|||||||
@@ -1,512 +0,0 @@
|
|||||||
# Pounce — Implementation Plans (Phases 2–9)
|
|
||||||
|
|
||||||
> Reference doc for implementing remaining features. Each phase is self-contained
|
|
||||||
> with file paths, code strategies, and acceptance criteria.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 2: Row-Level Security & Multi-Tenancy Hardening
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
Enforce tenant isolation at the database layer so even application bugs can't leak data across tenants.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
1. **Apply RLS policies to the live database**
|
|
||||||
- File: `scripts/setup-rls.sql` (already written)
|
|
||||||
- Run via `docker exec` on the db container, or add to `docker-entrypoint.sh` after `prisma db push`
|
|
||||||
- Every tenant-scoped table gets `ENABLE ROW LEVEL SECURITY` + a policy checking `current_setting('app.current_tenant_id')`
|
|
||||||
|
|
||||||
2. **Wire up the Prisma RLS client extension**
|
|
||||||
- File: `src/lib/server/rls.ts` (already written but unused)
|
|
||||||
- `forTenant(tenantId)` wraps queries in a transaction that does `SET LOCAL app.current_tenant_id = '<id>'`
|
|
||||||
- `bypassRLS()` for site admin cross-tenant operations
|
|
||||||
- Update all API routes and server load functions to use `forTenant(locals.tenant.id)` instead of raw `prisma`
|
|
||||||
|
|
||||||
3. **Create a shared helper for tenant-scoped DB access**
|
|
||||||
- File: `src/lib/server/db.ts` — add `export function tenantDb(locals: App.Locals)` that returns `forTenant(locals.tenant!.id)`
|
|
||||||
- All routes call `tenantDb(locals)` instead of importing `prisma` directly
|
|
||||||
|
|
||||||
4. **Test multi-tenant isolation**
|
|
||||||
- Access via two different hostnames (two tenants auto-created)
|
|
||||||
- Create boards on each — verify they don't appear on the other
|
|
||||||
- Verify API endpoints can't fetch cross-tenant data by ID
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- All API routes use tenant-scoped Prisma client
|
|
||||||
- Direct SQL query with wrong tenant_id returns 0 rows
|
|
||||||
- Two separate hostnames show fully isolated data
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 3: Roles & Permissions Enforcement
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
Enforce GlobalRole (SITE_ADMIN, USER), TenantRole (ADMIN, MEMBER), and BoardMemberRole (OWNER, EDITOR, VIEWER) throughout the app.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
1. **Create route guards**
|
|
||||||
- File: `src/lib/server/guards.ts`
|
|
||||||
- `requireAuth(locals)` — throws 401 if not logged in
|
|
||||||
- `requireTenantAdmin(locals)` — throws 403 if not tenant ADMIN
|
|
||||||
- `requireSiteAdmin(locals)` — throws 403 if not SITE_ADMIN
|
|
||||||
- `requireBoardAccess(locals, boardId, minRole?)` — checks membership
|
|
||||||
|
|
||||||
2. **Apply guards to all API routes**
|
|
||||||
- Board CRUD: owners can delete, editors can modify, viewers read-only
|
|
||||||
- Column/Card CRUD: inherit from board membership
|
|
||||||
- Already partially done in routes — audit each for consistency
|
|
||||||
|
|
||||||
3. **Public board anonymous access**
|
|
||||||
- `GET /api/boards/[boardId]` — if `visibility === 'PUBLIC'`, allow without auth
|
|
||||||
- Board view page server load — same check (already done, verify)
|
|
||||||
- Board listing — anonymous users see only PUBLIC boards (already done, verify)
|
|
||||||
|
|
||||||
4. **Board member management UI**
|
|
||||||
- File: `src/routes/boards/[boardId]/members/+page.svelte`
|
|
||||||
- API: `POST/DELETE /api/boards/[boardId]/members`
|
|
||||||
- Add members by email (must be registered on same tenant)
|
|
||||||
- Change member role (OWNER/EDITOR/VIEWER)
|
|
||||||
- Remove members
|
|
||||||
- Only OWNER can manage members
|
|
||||||
|
|
||||||
5. **Tenant admin panel (basic)**
|
|
||||||
- File: `src/routes/admin/+page.svelte` (guarded by tenantRole === 'ADMIN')
|
|
||||||
- List all users in tenant, change their tenantRole
|
|
||||||
- List all boards in tenant
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- VIEWER cannot create/edit/delete cards or columns
|
|
||||||
- Non-members cannot access PRIVATE boards
|
|
||||||
- Anonymous can view PUBLIC boards but not edit
|
|
||||||
- Board owner can add/remove/change member roles
|
|
||||||
- Tenant admin can see all boards and manage users
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 4: Rich Card Features
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
Cards get labels, categories, markdown descriptions, due dates, assignees, checklists, comments, and file attachments.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
1. **Tags/Labels system**
|
|
||||||
- API: `CRUD /api/tags` (tenant-scoped)
|
|
||||||
- API: `POST/DELETE /api/boards/[boardId]/columns/[columnId]/cards/[cardId]/labels`
|
|
||||||
- UI: Color picker for tag creation, label pills on cards
|
|
||||||
- Card modal: add/remove labels section
|
|
||||||
- File: `src/lib/components/TagPicker.svelte`
|
|
||||||
|
|
||||||
2. **Categories (board grouping)**
|
|
||||||
- API: `CRUD /api/categories` (tenant-scoped)
|
|
||||||
- Board listing page: group boards by category, filter dropdown
|
|
||||||
- Board create/edit: optional category selector
|
|
||||||
|
|
||||||
3. **Markdown description editor**
|
|
||||||
- Card modal: replace plain textarea with markdown editor
|
|
||||||
- Use `marked` (already installed) for rendering
|
|
||||||
- Toggle between edit and preview modes
|
|
||||||
- File: `src/lib/components/MarkdownEditor.svelte`
|
|
||||||
|
|
||||||
4. **Due dates with urgency indicators**
|
|
||||||
- Card modal: date picker input for due date
|
|
||||||
- Card thumbnail: colored badge (green = future, yellow = soon, red = overdue)
|
|
||||||
- API: PATCH card with `dueDate` field (already supported)
|
|
||||||
- Use `date-fns` (already installed) for relative time
|
|
||||||
|
|
||||||
5. **Assignees**
|
|
||||||
- Card modal: dropdown to assign board members
|
|
||||||
- API: `POST/DELETE /api/boards/[boardId]/columns/[columnId]/cards/[cardId]/assignees`
|
|
||||||
- Show avatar circles on card thumbnails (already rendering if present)
|
|
||||||
|
|
||||||
6. **Checklists**
|
|
||||||
- Card modal: add checklists with items, toggle completion
|
|
||||||
- API: `CRUD /api/boards/[boardId]/columns/[columnId]/cards/[cardId]/checklists`
|
|
||||||
- API: `CRUD .../checklists/[checklistId]/items`
|
|
||||||
- Progress bar on card thumbnail showing X/Y items done
|
|
||||||
- File: `src/lib/components/Checklist.svelte`
|
|
||||||
|
|
||||||
7. **Comments**
|
|
||||||
- Card modal: comment list + add comment form (markdown)
|
|
||||||
- API: `CRUD /api/boards/[boardId]/columns/[columnId]/cards/[cardId]/comments`
|
|
||||||
- Show author name, avatar, timestamp, edit/delete own comments
|
|
||||||
- File: `src/lib/components/CommentList.svelte`
|
|
||||||
|
|
||||||
8. **File attachments**
|
|
||||||
- Card modal: drag-drop or file picker to upload
|
|
||||||
- API: `POST /api/boards/[boardId]/columns/[columnId]/cards/[cardId]/attachments` (multipart)
|
|
||||||
- API: `GET /api/attachments/[id]` to download
|
|
||||||
- Store in `/app/uploads` Docker volume (already mounted)
|
|
||||||
- Show file list with name, size, download link
|
|
||||||
- File: `src/lib/components/Attachments.svelte`
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- All features visible in the card modal
|
|
||||||
- Labels appear as colored pills on board view cards
|
|
||||||
- Due date badge with color coding
|
|
||||||
- Checklist progress bar on card thumbnails
|
|
||||||
- Comments with markdown rendering
|
|
||||||
- File upload/download working via Docker volume
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 5: Real-Time Updates (Socket.IO)
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
Multiple users viewing the same board see live updates: card moves, new cards, column changes, comments, presence.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
1. **Socket.IO server integration**
|
|
||||||
- File: `server.js` (production) — already has basic setup
|
|
||||||
- File: `src/socket/index.ts` — auth middleware, room management (already written)
|
|
||||||
- Add Vite dev middleware for Socket.IO (simple HTTP server attach in dev)
|
|
||||||
|
|
||||||
2. **Client-side socket connection**
|
|
||||||
- File: `src/lib/stores/socket.ts` (already written)
|
|
||||||
- Connect on app load (layout), disconnect on unload
|
|
||||||
- Join board room when entering board view, leave when exiting
|
|
||||||
|
|
||||||
3. **Broadcast events from API routes**
|
|
||||||
- After every write operation (create/update/delete), emit to the board room
|
|
||||||
- Events: `card:created`, `card:updated`, `card:moved`, `card:deleted`, `column:created`, `column:updated`, `column:moved`, `column:deleted`, `comment:created`, etc.
|
|
||||||
- File: `src/lib/server/realtime.ts` — helper `broadcast(boardId, event, data)`
|
|
||||||
- Import and call from each API route's POST/PATCH/DELETE handler
|
|
||||||
- In dev, use a global event emitter; in prod, use Socket.IO directly
|
|
||||||
|
|
||||||
4. **Client-side event handlers on board view**
|
|
||||||
- File: `src/routes/boards/[boardId]/+page.svelte`
|
|
||||||
- Listen for socket events and update local `columns` state
|
|
||||||
- Handle: new cards appearing, cards moving, columns reordering, deletions
|
|
||||||
- Ignore events triggered by the current user (deduplicate via socket ID)
|
|
||||||
|
|
||||||
5. **Optimistic UI with rollback**
|
|
||||||
- Card moves: update local state immediately, send API request
|
|
||||||
- If API fails: revert to previous state, show toast error
|
|
||||||
- Other users see the final state from the socket event
|
|
||||||
|
|
||||||
6. **Presence indicators**
|
|
||||||
- Track which users are viewing a board (via socket room)
|
|
||||||
- Show avatar dots in board header: "Also viewing: Alice, Bob"
|
|
||||||
- Events: `user-joined`, `user-left` (already emitted in socket/index.ts)
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- Open two browser tabs on the same board
|
|
||||||
- Move a card in tab A → appears in tab B within 1 second
|
|
||||||
- Add a column in tab B → appears in tab A
|
|
||||||
- Presence shows both tabs' users
|
|
||||||
- If API fails, optimistic update rolls back
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 6: Activity Log & Notifications
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
Track all significant actions, provide activity feeds, and notify users of relevant events.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
1. **Activity logging service**
|
|
||||||
- File: `src/lib/server/activity.ts`
|
|
||||||
- `logActivity(boardId, userId, action, metadata?, cardId?)` — writes to `activities` table
|
|
||||||
- Actions: `board.created`, `card.created`, `card.moved`, `card.updated`, `card.deleted`, `column.created`, `column.deleted`, `comment.added`, `member.added`, `member.removed`
|
|
||||||
- Call from every API route after successful writes
|
|
||||||
|
|
||||||
2. **Activity feed API**
|
|
||||||
- `GET /api/boards/[boardId]/activity` — paginated, returns recent activity for a board
|
|
||||||
- `GET /api/boards/[boardId]/columns/[columnId]/cards/[cardId]/activity` — card-specific
|
|
||||||
- Include user name, action description, timestamp, link
|
|
||||||
|
|
||||||
3. **Board activity sidebar**
|
|
||||||
- File: `src/lib/components/ActivityFeed.svelte`
|
|
||||||
- Toggleable sidebar on board view showing recent actions
|
|
||||||
- "Alice moved 'Fix login bug' from To Do to In Progress — 5 min ago"
|
|
||||||
|
|
||||||
4. **Card activity in modal**
|
|
||||||
- Show activity timeline in card modal below comments
|
|
||||||
- Interleave comments and activity chronologically
|
|
||||||
|
|
||||||
5. **Notification generation**
|
|
||||||
- File: `src/lib/server/notifications.ts`
|
|
||||||
- Generate notifications for: assigned to card, mentioned in comment (@username), due date approaching (daily cron or on-access check)
|
|
||||||
- Write to `notifications` table
|
|
||||||
|
|
||||||
6. **Notification UI**
|
|
||||||
- Bell icon in navbar with unread count badge
|
|
||||||
- Dropdown showing recent notifications
|
|
||||||
- Click to navigate to relevant card/board
|
|
||||||
- Mark as read (individual + mark all)
|
|
||||||
- API: `GET /api/notifications`, `PATCH /api/notifications/[id]` (mark read), `POST /api/notifications/read-all`
|
|
||||||
- File: `src/lib/components/NotificationBell.svelte`
|
|
||||||
|
|
||||||
7. **Real-time notification push**
|
|
||||||
- When a notification is created, emit via Socket.IO to the target user
|
|
||||||
- User's socket joins `user:<userId>` room on connect
|
|
||||||
- Bell icon updates live without page refresh
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- Board sidebar shows chronological activity
|
|
||||||
- Card modal shows activity + comments interleaved
|
|
||||||
- Bell icon shows unread notification count
|
|
||||||
- Assigning a user to a card generates a notification
|
|
||||||
- Notifications appear in real-time via socket
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 7: Search, Filters & Templates
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
Find cards quickly with filters and search. Create boards from templates.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
1. **Board-level card filters**
|
|
||||||
- Filter bar above columns: by label, assignee, due date range
|
|
||||||
- Client-side filtering (hide non-matching cards, don't remove from state)
|
|
||||||
- File: `src/lib/components/BoardFilters.svelte`
|
|
||||||
- Filter state stored in URL search params for shareability
|
|
||||||
|
|
||||||
2. **Global search with PostgreSQL full-text search**
|
|
||||||
- Add `tsvector` column to `cards` table (or use generated column)
|
|
||||||
- Create GIN index on the tsvector
|
|
||||||
- Migration: `ALTER TABLE cards ADD COLUMN search_vector tsvector GENERATED ALWAYS AS (to_tsvector('english', coalesce(title,'') || ' ' || coalesce(description,''))) STORED;`
|
|
||||||
- `CREATE INDEX cards_search_idx ON cards USING gin(search_vector);`
|
|
||||||
- API: `GET /api/search?q=<query>` — returns matching cards with board/column info
|
|
||||||
- UI: Search bar in navbar, results dropdown with card titles + board names
|
|
||||||
- File: `src/lib/components/SearchBar.svelte`
|
|
||||||
|
|
||||||
3. **Board templates**
|
|
||||||
- System templates: "Basic Kanban" (To Do, In Progress, Done), "Scrum Sprint" (Backlog, Sprint, In Review, Done), "Bug Tracker" (New, Confirmed, In Progress, Resolved, Closed)
|
|
||||||
- Tenant templates: save any board as a template
|
|
||||||
- API: `GET /api/templates`, `POST /api/templates` (save board as template), `POST /api/boards?templateId=<id>` (create from template)
|
|
||||||
- Template data stored as JSON in `board_templates.template` column
|
|
||||||
- Board creation UI: "Start from template" option
|
|
||||||
- Seed system templates in `prisma/seed.ts`
|
|
||||||
|
|
||||||
4. **Archive/unarchive UI**
|
|
||||||
- Board listing: toggle to show archived boards
|
|
||||||
- Board header: archive/unarchive button (OWNER only)
|
|
||||||
- Card: archive button in modal (already `archived` field in schema)
|
|
||||||
- Archived cards hidden from board view (already filtered in queries)
|
|
||||||
- Board view: toggle to show archived cards (grayed out)
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- Filter cards by label → only matching cards visible
|
|
||||||
- Search "login" → finds cards with "login" in title or description
|
|
||||||
- Create board from "Basic Kanban" template → 3 columns pre-created
|
|
||||||
- Archive a card → disappears from board, visible in archive view
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 8: Polish & UX
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
Make the app feel production-quality with dark mode, keyboard shortcuts, responsive design, loading states, and accessibility.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
1. **Dark mode**
|
|
||||||
- Tailwind v4 dark mode via `class` strategy
|
|
||||||
- Toggle button in navbar (sun/moon icon)
|
|
||||||
- Persist preference in localStorage + cookie (for SSR)
|
|
||||||
- File: `src/lib/stores/theme.ts`
|
|
||||||
- Update `app.css` with dark variants for custom colors
|
|
||||||
- `<html>` element gets `class="dark"` from layout
|
|
||||||
|
|
||||||
2. **Keyboard shortcuts**
|
|
||||||
- `n` — new card (in focused column)
|
|
||||||
- `Escape` — close modal/cancel edit
|
|
||||||
- `b` — back to boards
|
|
||||||
- `/` — focus search bar
|
|
||||||
- `?` — show keyboard shortcuts help modal
|
|
||||||
- File: `src/lib/components/KeyboardShortcuts.svelte`
|
|
||||||
- Register in layout, context-aware (don't trigger in input fields)
|
|
||||||
|
|
||||||
3. **Responsive / mobile design**
|
|
||||||
- Board view: horizontal scroll on mobile (already works with overflow-x)
|
|
||||||
- Column width: responsive (narrower on small screens)
|
|
||||||
- Card modal: full-screen on mobile
|
|
||||||
- Navbar: hamburger menu on mobile
|
|
||||||
- Board listing: single column grid on mobile
|
|
||||||
|
|
||||||
4. **Loading skeletons**
|
|
||||||
- Board listing: card-shaped skeleton placeholders
|
|
||||||
- Board view: column skeleton placeholders
|
|
||||||
- Card modal: skeleton for async-loaded details
|
|
||||||
- File: `src/lib/components/Skeleton.svelte`
|
|
||||||
|
|
||||||
5. **Toast notifications**
|
|
||||||
- Success/error toasts for user actions (card created, error saving, etc.)
|
|
||||||
- Auto-dismiss after 3–5 seconds
|
|
||||||
- Stack in bottom-right corner
|
|
||||||
- File: `src/lib/components/Toast.svelte`, `src/lib/stores/toasts.ts`
|
|
||||||
|
|
||||||
6. **Error handling**
|
|
||||||
- Global error page: `src/routes/+error.svelte`
|
|
||||||
- API error responses: consistent JSON `{ error: string }` format
|
|
||||||
- Client-side fetch wrapper with automatic error toast
|
|
||||||
|
|
||||||
7. **Accessibility**
|
|
||||||
- ARIA labels on all icon-only buttons (partially done)
|
|
||||||
- Keyboard navigation for drag-and-drop (arrow keys to move cards)
|
|
||||||
- Focus management in modals (trap focus, restore on close)
|
|
||||||
- Screen reader announcements for drag-and-drop results
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- Dark mode toggles and persists across sessions
|
|
||||||
- All pages usable on a 375px mobile screen
|
|
||||||
- Keyboard shortcuts work (test: press `/` → search focuses)
|
|
||||||
- Loading skeletons appear on slow connections
|
|
||||||
- Toasts appear for create/delete/error actions
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 9: Admin & DevOps
|
|
||||||
|
|
||||||
### Goal
|
|
||||||
Admin dashboards for site-wide and per-tenant management. Production readiness.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
|
|
||||||
1. **Site Admin dashboard**
|
|
||||||
- Route: `src/routes/admin/site/+page.svelte` (guarded: SITE_ADMIN only)
|
|
||||||
- Cross-tenant statistics: total tenants, users, boards, cards
|
|
||||||
- Tenant list with user counts, board counts, created date
|
|
||||||
- Create/edit/delete tenants
|
|
||||||
- Impersonate user (login as any user for debugging)
|
|
||||||
- Uses `bypassRLS()` Prisma client
|
|
||||||
|
|
||||||
2. **Tenant Admin dashboard**
|
|
||||||
- Route: `src/routes/admin/+page.svelte` (guarded: tenantRole ADMIN)
|
|
||||||
- Tenant settings: name, allowed domains
|
|
||||||
- User management: list, change roles, deactivate
|
|
||||||
- Tag management: create/edit/delete tenant-scoped tags
|
|
||||||
- Category management: create/edit/delete categories
|
|
||||||
- Board overview: all boards with member counts
|
|
||||||
|
|
||||||
3. **Health check endpoint**
|
|
||||||
- Route: `src/routes/api/health/+server.ts`
|
|
||||||
- Returns `{ status: 'ok', db: true/false, uptime: seconds }`
|
|
||||||
- Check DB connectivity with a simple query
|
|
||||||
- Used by Docker HEALTHCHECK and monitoring
|
|
||||||
|
|
||||||
4. **Structured logging**
|
|
||||||
- Replace `console.log` with a logger (pino or simple structured wrapper)
|
|
||||||
- Log format: JSON with timestamp, level, message, metadata
|
|
||||||
- Request logging middleware in hooks.server.ts (method, path, status, duration)
|
|
||||||
|
|
||||||
5. **Rate limiting**
|
|
||||||
- In-memory rate limiter for auth endpoints (login, register)
|
|
||||||
- File: `src/lib/server/ratelimit.ts`
|
|
||||||
- 10 attempts per minute per IP for login
|
|
||||||
- 5 registrations per hour per IP
|
|
||||||
- Return 429 Too Many Requests
|
|
||||||
|
|
||||||
6. **Docker health check**
|
|
||||||
- Add `HEALTHCHECK` to Dockerfile pointing at `/api/health`
|
|
||||||
- Update `docker-compose.yml` with healthcheck for app service
|
|
||||||
|
|
||||||
7. **Backup documentation**
|
|
||||||
- File: `docs/backup.md`
|
|
||||||
- PostgreSQL: `pg_dump` command for the kanban database
|
|
||||||
- Uploads volume: `docker cp` or volume backup
|
|
||||||
- Restore procedure
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- Site admin can see all tenants and their stats
|
|
||||||
- Tenant admin can manage users and tags
|
|
||||||
- `/api/health` returns 200 with DB status
|
|
||||||
- Login rate-limited to 10/min per IP
|
|
||||||
- Docker health check passes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## File Structure After All Phases
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
├── hooks.server.ts
|
|
||||||
├── app.css
|
|
||||||
├── app.d.ts
|
|
||||||
├── app.html
|
|
||||||
├── socket/
|
|
||||||
│ └── index.ts
|
|
||||||
├── lib/
|
|
||||||
│ ├── server/
|
|
||||||
│ │ ├── db.ts
|
|
||||||
│ │ ├── auth.ts
|
|
||||||
│ │ ├── tenant.ts
|
|
||||||
│ │ ├── rls.ts
|
|
||||||
│ │ ├── permissions.ts
|
|
||||||
│ │ ├── guards.ts (Phase 3)
|
|
||||||
│ │ ├── validation.ts
|
|
||||||
│ │ ├── activity.ts (Phase 6)
|
|
||||||
│ │ ├── notifications.ts (Phase 6)
|
|
||||||
│ │ ├── realtime.ts (Phase 5)
|
|
||||||
│ │ └── ratelimit.ts (Phase 9)
|
|
||||||
│ ├── stores/
|
|
||||||
│ │ ├── socket.ts
|
|
||||||
│ │ ├── theme.ts (Phase 8)
|
|
||||||
│ │ └── toasts.ts (Phase 8)
|
|
||||||
│ ├── utils/
|
|
||||||
│ │ └── fractional-index.ts
|
|
||||||
│ └── components/
|
|
||||||
│ ├── CardModal.svelte
|
|
||||||
│ ├── TagPicker.svelte (Phase 4)
|
|
||||||
│ ├── MarkdownEditor.svelte (Phase 4)
|
|
||||||
│ ├── Checklist.svelte (Phase 4)
|
|
||||||
│ ├── CommentList.svelte (Phase 4)
|
|
||||||
│ ├── Attachments.svelte (Phase 4)
|
|
||||||
│ ├── ActivityFeed.svelte (Phase 6)
|
|
||||||
│ ├── NotificationBell.svelte (Phase 6)
|
|
||||||
│ ├── BoardFilters.svelte (Phase 7)
|
|
||||||
│ ├── SearchBar.svelte (Phase 7)
|
|
||||||
│ ├── Skeleton.svelte (Phase 8)
|
|
||||||
│ ├── Toast.svelte (Phase 8)
|
|
||||||
│ └── KeyboardShortcuts.svelte (Phase 8)
|
|
||||||
└── routes/
|
|
||||||
├── +layout.svelte
|
|
||||||
├── +layout.server.ts
|
|
||||||
├── +page.svelte
|
|
||||||
├── +error.svelte (Phase 8)
|
|
||||||
├── auth/
|
|
||||||
│ ├── login/+page.svelte
|
|
||||||
│ └── register/+page.svelte
|
|
||||||
├── boards/
|
|
||||||
│ ├── +page.svelte
|
|
||||||
│ ├── +page.server.ts
|
|
||||||
│ └── [boardId]/
|
|
||||||
│ ├── +page.svelte
|
|
||||||
│ ├── +page.server.ts
|
|
||||||
│ └── members/ (Phase 3)
|
|
||||||
│ └── +page.svelte
|
|
||||||
├── admin/ (Phase 3/9)
|
|
||||||
│ ├── +page.svelte
|
|
||||||
│ └── site/
|
|
||||||
│ └── +page.svelte
|
|
||||||
└── api/
|
|
||||||
├── health/+server.ts (Phase 9)
|
|
||||||
├── search/+server.ts (Phase 7)
|
|
||||||
├── tags/+server.ts (Phase 4)
|
|
||||||
├── categories/+server.ts (Phase 4)
|
|
||||||
├── templates/+server.ts (Phase 7)
|
|
||||||
├── notifications/+server.ts (Phase 6)
|
|
||||||
├── auth/...
|
|
||||||
└── boards/...
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implementation Order Recommendation
|
|
||||||
|
|
||||||
Phases can be partially parallelized:
|
|
||||||
- **Phase 2** first (RLS) — foundational security
|
|
||||||
- **Phase 3** next (Roles) — needed before multi-user features
|
|
||||||
- **Phase 4** (Rich Cards) — the biggest feature payload, can start during Phase 3
|
|
||||||
- **Phase 5** (Real-Time) — depends on Phase 4 for full value
|
|
||||||
- **Phase 6** (Activity/Notifications) — depends on Phase 5
|
|
||||||
- **Phase 7** (Search/Filters/Templates) — independent, can be done anytime after Phase 4
|
|
||||||
- **Phase 8** (Polish) — do alongside or after feature phases
|
|
||||||
- **Phase 9** (Admin/DevOps) — can start admin panels during Phase 3, finish last
|
|
||||||
Reference in New Issue
Block a user