Private
Public Access
1
0
Commit Graph

43 Commits

Author SHA1 Message Date
Catherine Renelle 8590fb0126 Center search bar to page midpoint in nav header
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 20:58:30 -05:00
Catherine Renelle 0e77c50411 Add board settings modal for editing board properties and deleting boards
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:35:00 -05:00
Catherine Renelle faa2608a47 Fix ColorPicker solid color issues, add per-field reset, regroup accents
ColorPicker fixes:
- Color picker now initializes to default color instead of black when
  field is cleared/empty
- Switching Solid<>Gradient no longer emits black; restores default color
  when switching back to Solid from a gradient value
- No-op guard prevents re-emitting when clicking the already-active mode
- Reset button now says "Reset to default" when a default is available
- Text input placeholder shows the default value

Branding page:
- Accent Colors regrouped: Primary+hover and Danger+hover are stacked
  together, Success and Warning standalone in a 4-column grid
- Mini preview fallbacks now use getDefault() helper instead of
  hardcoded values, keeping them in sync with the defaults map

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 17:52:52 -05:00
Catherine Renelle 8c9a5abc5a Fix branding: live updates on save, reset clears everything, show defaults
- Clear inline preview styles before persisting CSS on save to avoid
  specificity conflicts that required Ctrl+Shift+R
- Reset to Defaults now deletes uploaded images and clears logoText
- ColorPicker emits value on Solid/Gradient toggle for instant preview
- Show default color swatch with dashed border when field is cleared
- persistThemeCSS now handles background-image rules like server-side

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 17:33:34 -05:00
Catherine Renelle 795e7c14ff Fix branding page 500 error and make theme changes instant
1. Fix 500 on hard refresh: branding page load was querying tenant
   for logoUrl/logoText fields that may not exist in DB yet. Now
   uses locals.tenant data (from resolver) instead of a separate query.

2. Instant theme application: after saving, persistThemeCSS() generates
   CSS from the draft and writes it into the <style id="tenant-theme">
   element in the DOM. This means navigating to any page after saving
   immediately shows the new theme without a hard refresh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:58:32 -05:00
Catherine Renelle b1d994c9e4 Condense nav: profile dropdown replaces inline nav items
Desktop nav now shows only: theme toggle, notification bell, and
avatar+name. Clicking avatar opens a dropdown menu with My Work,
Profile, Admin, Site Admin, and Logout. Logged-out users see only
the theme toggle and a Login button.

Mobile nav mirrors the same menu items in the hamburger dropdown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:47:13 -05:00
Catherine Renelle ecd037ce5c Rearrange nav: logo left, search centered, nav items right
Use a 3-column CSS grid on desktop (auto | 1fr | auto) so the search
bar stays centered in the viewport while logo and nav items pin to
the edges. Mobile layout unchanged (logo left, hamburger right).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:39:39 -05:00
Catherine Renelle ce5310e7a0 Fix gradient backgrounds being overridden by background-image property
The layout had `background: var(--color-page-bg); background-image: ...`
which meant that when --color-page-bg was a gradient (which sets
background-image via the shorthand), the subsequent background-image
declaration would reset it to none.

Fix: use `background` shorthand only via CSS classes (.layout-page-bg,
.layout-nav-bg), and handle uploaded background images via class-level
overrides in generateTenantCSS instead of CSS vars.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:27:10 -05:00
Catherine Renelle 95ec8f30dd Fix branding not applying: move CSS vars out of @theme, inject after Tailwind
Tailwind v4's @theme block outputs CSS that came after the tenant theme
<style> tag, causing the defaults to win by source order. Two fixes:
- Move custom property defaults from @theme {} to :root {} so they're
  at the same cascade level as tenant overrides
- Inject tenant CSS before </head> instead of after <head> so it comes
  after all Tailwind output in the cascade

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:46:15 -05:00
Catherine Renelle 986c88143a Replace bulk select button with hover checkboxes, remove board background override
- Cards now show a checkbox on hover (top-right) for bulk selection,
  removing the need for a separate "Select" toggle button
- Removed BoardBackgroundPicker from board header since per-board
  backgrounds were overriding tenant branding
- Removed inline background style from board area so branding page
  backgrounds apply correctly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:58:46 -05:00
Catherine Renelle 8c41b33313 Add 17 features: My Work view, card copy/numbering, calendar, bulk ops, custom fields, automations, webhooks, invites, import/export, and more
Features implemented across 6 batches:
- Batch A: Fix ColorPicker gradient sync, tenant custom logo, unarchive cards, board backgrounds
- Batch B: My Work view, card copy/duplicate, card numbering (BOARD-123)
- Batch C: Due date reminders (cron), card watching with notifications
- Batch D: Bulk card operations, column sorting, calendar view
- Batch E: Invite by link, board import/export (Pounce + Trello JSON)
- Batch F: Webhooks with HMAC signing, custom fields, automation rules engine

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 08:50:15 -05:00
Catherine Renelle 3a11ed01e9 Add tenant branding & theming system with admin UI
Tenant admins can now customize their workspace appearance: page/nav
backgrounds (solid, gradient, or image), column/card colors, borders,
text, opacity with glass blur, card corner radius, and accent colors.
Light and dark mode are configured separately. Theme CSS is injected
server-side via transformPageChunk to prevent FOUC.

Includes avatar components, account page updates, and pre-existing
type error fixes (Buffer, async onMount, InputJsonValue).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:56:39 -05:00
Catherine Renelle 029b467eae Fix stale nav after login/register: use full page navigation
goto() does client-side navigation which caches the layout data
(user is still null). Using window.location.href forces a full
server round-trip so the nav bar reflects the authenticated user.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 20:28:48 -05:00
Catherine Renelle 80641b6058 Fix deploy: add --accept-data-loss for search_vector column
prisma db push refuses to sync when the search_vector generated
column exists in the DB but not in the schema. The column is
managed by setup-search.sql which runs immediately after.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 20:12:46 -05:00
Catherine Renelle 420ff1e715 Hide SITE_ADMIN from tenant admin, add Site Admin nav link
- Tenant admin user list filters out SITE_ADMIN users (server-side)
- API guard prevents tenant admins from modifying SITE_ADMIN users
- Tenant admins cannot change their own role (prevents self-demotion)
- Nav bar shows separate "Site Admin" link for SITE_ADMIN users
- Both desktop and mobile nav updated

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 20:00:51 -05:00
Catherine Renelle 8c150e5c24 Allow SITE_ADMIN to login across all tenants
Login now falls back to a cross-tenant lookup for SITE_ADMIN users
when the email isn't found in the current tenant. Regular users
remain scoped to their own tenant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 19:52:18 -05:00
Catherine Renelle 04f5786cf6 Fix psql URI in entrypoint: strip Prisma query params
psql doesn't understand ?schema=public in the DATABASE_URL.
Strip query parameters before passing to psql for RLS, collation,
and search index scripts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 19:46:14 -05:00
Catherine Renelle 5f552a9883 Fix account settings: add invalidateAll, robust error handling
- Add invalidateAll() after profile save so nav bar updates immediately
- Wrap all async handlers in try/finally to prevent stuck loading states
- Make form onsubmit handlers async to properly propagate errors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 19:31:02 -05:00
Catherine Renelle 1419300baa Add account settings page with profile, password, and session management
- /account page: edit name/email, change password, view/revoke sessions
- PATCH /api/account: update profile or change password (verifies current)
- DELETE /api/account: revoke all other sessions
- Password change auto-revokes other sessions for security
- Username in nav now links to /account (desktop + mobile)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:22:34 -05:00
Catherine Renelle f91b8a4bd4 Fix tenant resolution: use Host header instead of ORIGIN-derived URL
SvelteKit's event.url.hostname is always derived from the ORIGIN env
var, so all requests resolved to the same tenant regardless of which
domain the user visited. Now reads X-Forwarded-Host or Host header
to get the actual domain for multi-tenant hostname isolation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:01:40 -05:00
Catherine Renelle 606c1b0652 Add drag handle icon to column headers
Shows a grip dots icon in the column header when the user can edit,
making it visually clear that columns are draggable. Also adds
cursor-grab/grabbing styles to the header.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 07:45:58 -05:00
Catherine Renelle 95f8e9a70b Fix column/card ordering: set COLLATE C on position columns
Postgres en_US.utf8 collation sorts case-insensitively, breaking the
lexicographic fractional indexing. Setting COLLATE "C" ensures pure
byte-order sorting. Applied via setup-collation.sql in entrypoint
after prisma db push.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 07:40:13 -05:00
Catherine Renelle 8a97d354fa Add system board templates seeded at startup
Four templates (Kanban, Simple, Sprint, Bug Tracking) with tenantId=null
are auto-seeded on first startup if none exist. Available to all tenants
in the board creation dropdown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 07:33:08 -05:00
Catherine Renelle 9b5459fa49 Seed default tags and categories for new tenants
New tenants auto-provisioned via hostname get 5 default tags (Bug,
Feature, Enhancement, Urgent, Documentation) and 4 categories
(Frontend, Backend, Design, Infrastructure).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 07:28:06 -05:00
Catherine Renelle 062832a1e3 Fix $state runtime error: rename rune stores to .svelte.ts
$state runes only work in .svelte and .svelte.ts files. The toasts and
theme stores used $state in plain .ts files, which compiled in dev but
crashed in production SSR. Renamed and updated all imports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 01:33:15 -05:00
Catherine Renelle 1ec64e4ad5 Update docker-compose.yml for git-based Portainer deployment
Switch from hardcoded credentials to env var substitution (DB_PASSWORD,
SESSION_SECRET, ORIGIN). Use production ports (3200:3000, 3201:5432) and
host.docker.internal for DB connectivity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 01:27:20 -05:00
Catherine Renelle 0bba161c12 Phase 9: Admin & DevOps — health check, rate limiting, logging, site admin, Docker healthcheck
- Health check endpoint (GET /api/health) with DB probe and uptime
- In-memory sliding window rate limiting on login (10/60s) and register (5/3600s)
- Structured logging with pino (request timing in hooks, Socket.IO events in server.js)
- Site admin dashboard with tenant stats, CRUD, and requireSiteAdmin guard
- Tenant admin enhanced with tag and category management UI
- Docker HEALTHCHECK in Dockerfile and docker-compose.yml
- Backup documentation (docs/backup.md)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 01:24:24 -05:00
Catherine Renelle 7559102479 Phase 8: Polish & UX — dark mode, toasts, keyboard shortcuts, responsive, accessibility
- Add dark mode with theme toggle, localStorage/cookie persistence, anti-FOUC script
- Add toast notification system with auto-dismiss and color-coded types
- Add api() fetch wrapper with auto JSON, X-Socket-ID, and error toasts
- Add keyboard shortcuts (/ search, b boards, ? help, n new card, Esc close)
- Add error page with status code and navigation
- Add focus trap utility and apply to CardModal with full ARIA dialog support
- Add hamburger menu for mobile, responsive columns, fullscreen card modal on mobile
- Add aria-labels to icon-only buttons and DnD live region
- Migrate all ~30 fetch calls to api() wrapper with success toasts
- Add dark: Tailwind variants to all 20+ pages and components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 01:09:17 -05:00
Catherine Renelle 6ed0349507 Phase 7: Search, filters, templates, and archive UI
Add full-text card search (PostgreSQL tsvector + GIN index) with navbar
SearchBar, client-side board filters (label/assignee/due date), board
templates (3 system templates + save-as-template API), and archive
toggle for both board listing and board view.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 00:42:20 -05:00
Catherine Renelle e5f2c64e14 Phase 6: Activity log and notifications
Add activity logging to all write API routes, notification system with
real-time delivery via Socket.IO, @mention parsing in comments, activity
feed sidebar on board page, per-card activity in card modal, and
notification bell with unread badge in the navbar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 00:26:15 -05:00
Catherine Renelle e61c549ddb Phase 5: Real-time updates via Socket.IO
Wire Socket.IO broadcast from all write API routes so board changes
propagate instantly to other connected clients. Add session-based auth
on socket connections, in-memory presence tracking, and a presence UI
in the board header showing who else is viewing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 00:03:13 -05:00
Catherine Renelle 095d9756a8 Phase 4: Rich card features — labels, checklists, comments, attachments, categories
Add full CRUD + UI for all card sub-resources (tags/labels, assignees, checklists
with items, comments with markdown, file attachments). Restructure CardModal into
a two-column layout with lazy-loaded data. Upgrade card thumbnails with named label
pills, urgency-colored due date badges, checklist progress indicators, and SVG icons.
Add board categories with filtering on the listing page. Include markdown rendering
with DOMPurify sanitization and .prose CSS styles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:38:31 -05:00
Catherine Renelle 9b5708af64 Phase 3: Roles & permissions enforcement with guards, member management, and admin panel
Centralize permission checks into guards.ts (requireAuth, requireBoardView,
requireBoardEditor, requireBoardOwner, requireColumnEditor, requireCardEditor,
requireBoardMemberManager, requireTenantAdmin) that fetch entities and check
permissions in a single call, replacing ~100 lines of duplicated inline checks
across all API routes. Adds board member management (add by email, change role,
remove with last-owner protection), tenant admin panel (user role toggle with
last-admin protection, board overview), and fixes missing view guard on card GET.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:13:29 -05:00
Catherine Renelle bd12160ebb Phase 2: Enforce Row-Level Security at the PostgreSQL level
- Rewrite rls.ts with withTenant()/withBypassRLS() using parameterized
  set_config() in interactive Prisma transactions (no SQL injection)
- Add FORCE ROW LEVEL SECURITY on all 15 tenant-scoped tables
- Add __bypass__ sentinel and WITH CHECK clauses to every RLS policy
- Explicitly DISABLE RLS on tenants, tenant_hostnames, sessions
- Wrap all API route and page loader queries in withTenant()
- Wrap validateSession() in withBypassRLS() (joins RLS-protected users)
- Keep existing tenantId where-clause filters as optimization layer
- Add postgresql-client to Dockerfile and auto-apply RLS via entrypoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:54:26 -05:00
Catherine Renelle f6ddfcfc62 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>
2026-02-25 22:37:32 -05:00
Catherine Renelle da0cd816aa Add implementation plans for phases 2-9
Detailed task breakdowns, file paths, acceptance criteria,
and recommended execution order for all remaining phases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:34:31 -05:00
Catherine Renelle 80c17d4c6f Auto-create tenant for any hostname that reaches the app
DNS is the gatekeeper — if a request arrives, it was pointed
here intentionally. Every new hostname gets its own tenant
automatically, no manual setup or seeding required.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:30:05 -05:00
Catherine Renelle 7b540a37ee Rebrand to Pounce, the Open Source Kanban Solution
- Rename project from "kanban" to "pounce"
- Update landing page: "Pounce on your tasks"
- Replace navbar icon with cat paw
- Update seed hostname to pounce.catrenelle.com
- Write proper README with setup instructions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:24:43 -05:00
Catherine Renelle bdb8af6ca2 Add kanban.catrenelle.com to seed hostnames
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:13:27 -05:00
Catherine Renelle f90489c2ff Show prisma db push errors in entrypoint, add .gitattributes for LF
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:59:23 -05:00
Catherine Renelle b47cc8748d Add docker-entrypoint.sh to retry DB connection on startup
The app container starts before DNS resolution is ready,
causing prisma db push to fail. Entrypoint now retries
until the database is reachable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:45:13 -05:00
Catherine Renelle 2c0583d0e4 Fix Docker build: add native deps for bcrypt, simplify vite config
- Add python3/make/g++ to Alpine for bcrypt native compilation
- Remove Socket.IO vite plugin (uses SvelteKit aliases unavailable at config level)
- Use prisma db push instead of migrate deploy for initial setup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:05:45 -05:00
Catherine Renelle 2f398711c8 Initial implementation: multi-tenant Kanban board (Phase 1)
Complete Phase 1 foundation with working board, column, and card CRUD:
- SvelteKit + TypeScript + Tailwind CSS v4 + adapter-node
- Full Prisma schema with 18 tables (tenants, users, boards, columns, cards, etc.)
- Multi-tenant architecture with hostname-based tenant resolution
- Email/password auth with bcrypt + session cookies
- Board/Column/Card API routes with full CRUD
- Fractional indexing for drag-and-drop ordering
- Board view with svelte-dnd-action for column and card drag-and-drop
- Card modal with inline editing
- Auth pages (login, register)
- Board listing with create form
- RLS policies SQL script for tenant isolation
- Prisma RLS client extensions (forTenant/bypassRLS)
- Permission helpers (canEditBoard, canManageMembers, etc.)
- Socket.IO server setup (dev Vite plugin + production Express server)
- Client-side socket store for real-time updates
- Docker Compose (app + PostgreSQL 16) + multi-stage Dockerfile
- Database seed script (default tenant + admin user)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:58:49 -05:00