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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
- 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>
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>
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>
- 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>
- /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>
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>
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>
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>
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>
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>
$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>
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>
- 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>
- 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>
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>
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>
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>