Private
Public Access
1
0
Commit Graph

63 Commits

Author SHA1 Message Date
Catherine Renelle 8f5a931951 Allow dark mode theme script via CSP hash
The inline script in app.html that applies the dark mode class before
paint is not covered by SvelteKit's nonce system. Whitelist it by
its SHA-256 hash instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:20:22 -04:00
Catherine Renelle f641e65c1f Add cross-origin isolation security headers
- Cross-Origin-Embedder-Policy: credentialless (allows Google Fonts)
- Cross-Origin-Opener-Policy: same-origin (isolates browsing context)
- Cross-Origin-Resource-Policy: same-origin (prevents cross-origin loads)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:17:29 -04:00
Catherine Renelle 2d4c3a57da Replace unsafe-inline with CSP nonces for script-src
SvelteKit now handles script-src with automatic nonces via its
built-in CSP support. The hooks handler merges extra directives
(style-src, font-src, img-src, etc.) onto SvelteKit's nonce-based
policy for page responses, and sets a full CSP for API responses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:16:45 -04:00
Catherine Renelle b05521add6 Add Permissions-Policy security header
Disables browser APIs not needed by the app: camera, microphone,
geolocation, payment, USB, magnetometer, gyroscope, accelerometer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:15:27 -04:00
Catherine Renelle 827f0394ef Add API key management UI to account settings
Users can create, view, and delete API keys from their profile.
Keys are shown once on creation with a copy button. List shows
key prefix, creation date, and last used date.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:44:16 -04:00
Catherine Renelle d8b3935fc5 Add API key authentication for programmatic access
- New ApiKey model in Prisma schema (tenant + user scoped)
- Keys are SHA-256 hashed, only shown once on creation
- Bearer token auth in hooks.server.ts (alongside session cookies)
- CRUD endpoint at /api/account/api-keys (max 10 per user)
- Keys prefixed with pnc_ for easy identification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:34:56 -04:00
Catherine Renelle 44e5af6c2b Enrich Discord webhook embeds with move details and card links
Card moved events now show from/to column names. Card created/updated
embeds link directly to the card. Card updated shows which fields
changed. Card deleted shows the card title. Base URL resolved from
tenant hostname for full links.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:05:17 -04:00
Catherine Renelle b6d65b7c31 Add Discord webhook formatting and dispatch logging
Discord webhooks require a specific payload format (embeds), not raw
JSON. Auto-detect Discord URLs and send colored embeds with card/board
details. Also adds logging for webhook dispatch debugging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:00:06 -04:00
Catherine Renelle a57f83c5cd Wire up webhook dispatch for all board/column/card events
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 10:41:47 -04:00
Catherine Renelle e8c70bde87 Add missing favicon.svg
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 10:15:20 -04:00
Catherine Renelle 15f8e8218a Allow Google Fonts in CSP for Tailwind's Inter font
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 10:14:15 -04:00
Catherine Renelle 0852d5a804 Add CSP/HSTS headers, attachment extension whitelist, and upload rate limiting
- Add Content-Security-Policy and Strict-Transport-Security headers
- Whitelist allowed file extensions on attachment uploads
- Add rate limiting to password change (5/5min) and file uploads (20/60s)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:25:02 -05:00
Catherine Renelle d418c367cb Security hardening and fix all compile warnings
Security fixes:
- Validate theme background image URLs against whitelist pattern
- Add board permission check to Socket.IO join-board handler
- Disable raw HTML passthrough in markdown parser (XSS prevention)
- Add UUID validation on avatar and branding route params (path traversal)
- Add security headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy)
- Validate webhook URLs (HTTPS only, block internal addresses)
- Add import payload size limit (5MB)
- Remove server uptime from health endpoint
- Make seed password configurable via SEED_ADMIN_PASSWORD env var
- Patch DOMPurify dependency vulnerability via npm audit fix

Warning fixes:
- Convert $state(prop) to $effect.pre sync pattern (state_referenced_locally)
- Add for/id pairings to form labels (a11y_label_has_associated_control)
- Add svelte-ignore for intentional autofocus usage (a11y_autofocus)
- Add ARIA roles to interactive/overlay divs (a11y_no_static_element_interactions)
- Add aria-label to icon-only buttons (a11y_consider_explicit_label)
- Add keyboard handler alongside click events (a11y_click_events_have_key_events)
- Fix non-reactive fileInput declaration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:36:47 -05:00
Catherine Renelle 8f79de1df6 Remove background picker from board settings
Background customization is available in the Branding section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 10:15:41 -05:00
Catherine Renelle 55c9a60a0e Fix tab switcher text size consistency across Board/Calendar/Gantt
Calendar and Gantt used text-sm while Board used text-xs, causing
the tab container to change size when switching views.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 10:07:32 -05:00
Catherine Renelle 2fbd3bc93d Add Gantt chart view with card dependencies and start dates
Adds a new Gantt chart board view with custom SVG timeline rendering,
card-to-card dependency tracking with cycle detection, and a startDate
field on cards. Includes zoom controls (day/week/month), dependency
arrows, column-grouped task list, today marker, and real-time updates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 10:03:11 -05:00
Catherine Renelle 85bda718cc Fix dark mode text color in tag picker dropdown
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 23:54:59 -05:00
Catherine Renelle df0e8909f2 Fix checklist item ordering and add move up/down buttons
The BASE_CHARS in fractional-index.ts had digits after letters
(A-Za-z0-9), but PostgreSQL sorts digits before letters (0-9A-Za-z),
causing items to appear out of order once positions reached the digit
range. Reordered BASE_CHARS to match DB collation.

Also added up/down arrow buttons on checklist items so users can
reorder them within the list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 23:43:38 -05:00
Catherine Renelle bbc95a5bfc Fix dark mode prose text color in card descriptions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 23:21:48 -05:00
Catherine Renelle df602ab559 Fix branding page 500 on hard refresh: guard document access during SSR
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:20:04 -05:00
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