- Settings layout with sidebar nav (Profile, MCP Server, Users)
- Profile page: display name, email, password, sessions
- MCP page: API key CRUD, JSON config with copy button, LLM prompt
- Config auto-populates with actual API key when one is created
- Remove duplicate Settings link from sidebar
- Users page integrated into settings nav (admin only)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Shared notes-service.ts with userId-scoped queries for DRY
- McpServer with tools: list/get/create/update/trash/restore/
archive/unarchive/delete notes, search, list tags, pin,
reorder, upload image
- Streamable HTTP endpoint at POST /api/mcp
- Session management with GET/DELETE handlers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- API key generation with SHA-256 hashing and crumbs_ prefix
- User-scoped key validation, listing, and deletion
- Bearer token auth in hooks.server.ts for /api/mcp paths
- Populates event.locals.user from API key for downstream scoping
- 13 unit tests covering CRUD, validation, and user isolation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add `api_keys` table with userId foreign key to schema
- Add `@modelcontextprotocol/sdk` and `zod` dependencies
- Add auto-create SQL and test helpers for api_keys table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add userId check to /api/notes/reorder (was completely unprotected)
- Scope syncNoteTags by userId to prevent cross-user tag pollution
- Verify attachmentId belongs to noteId in attachment operations (IDOR fix)
- Remove DEFAULT 0 from userId columns so missing userId fails loudly
- Update test helpers and test data to provide required userId
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move settings routes into (app) layout group for header/sidebar
- Replace all gray/white/dark-mode Tailwind classes with CSS variables
- Use rounded-sm, card-shadow, and parchment color tokens throughout
- Fix PasswordStrengthMeter to use themed colors
- Fix page titles from "KeepNotes" to "Crumbs"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The HTML minlength="8" attribute triggered native browser validation
before the JS handler could run, preventing the custom error-message
element from appearing. JS already validates password length.
Also install missing zxcvbn and arctic dependencies from phase2 merge.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The drag handle was positioned top-right, overlapping with the pin
bookmark icon on pinned notes. Move it to top-left instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Make the Tiptap editor fill the full wrapper height using flexbox so
tapping anywhere in the content area focuses the editor, not just the
small text area at the top.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use opacity-based visibility (max-md:opacity-100) for image hover
actions so they're always accessible on touch devices
- Always show ImageUpload with delete/star when attachments exist,
not just when in image upload mode
- Replace drag-and-drop zone with compact "Add images" button on mobile
- Add showDropZone prop to ImageUpload for conditional drop zone display
- Clean up unused lightbox state from NoteEditor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add globalSetup to clean test DB before each run. Split Playwright into
two projects: auth-setup (serial, runs first) and app (parallel, depends
on auth-setup). Skip rate limiting in test environment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix null vs undefined in GitHub OAuth, use arctic's
createAuthorizationURLWithPKCE for OIDC, loosen api-utils type
signature to avoid SvelteKit route-specific generics, add @types/zxcvbn.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Login page loads enabled providers from server and shows "or continue
with" divider + branded buttons for Google/GitHub/OIDC. Also handles
rate limit 429 and OAuth no_account error display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dynamic [provider] routes for Google, GitHub, and OIDC. Stores state and
PKCE verifier in httpOnly cookies. Callback validates code, finds/links
user by provider ID or email (invite-only), and creates session.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Google, GitHub, and generic OIDC provider modules using arctic v3.
Providers are auto-enabled when env vars are set. Google/GitHub use PKCE,
OIDC uses OpenID Connect discovery.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Track session metadata (createdAt, userAgent, ip, lastUsedAt). Add API
for listing and revoking sessions. Settings page shows active sessions
with "Revoke" per session and "Log out everywhere else" option.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add PasswordStrengthMeter component showing visual bar and feedback.
Integrated in setup, settings change-password, and admin create-user forms.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5 failed attempts per IP triggers 15-minute lockout. Uses loginAttempts
table added in Phase 1. Returns 429 with Retry-After header.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update unit test helpers with full multi-user schema, fix auth tests to
include email field, and improve e2e tests with specific card targeting
and force clicks for hover-revealed buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix session expiry check (seconds vs milliseconds mismatch in raw SQL),
conditionally render app chrome only for authenticated users, use full
page reload after login/setup for proper session propagation, remove
HTML minlength to allow JS validation, fix store to remove notes on
trash/archive, and make auth tests race-condition safe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move migration logic (ALTER TABLE) before CREATE INDEX statements so
that user_id columns exist on old schemas before indexes reference them.
Disable foreign keys during schema setup to avoid constraint issues.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each user gets their own IDB database (keepnotes-{userId}), preventing
data leaks between users on the same device. Add initDb(userId) called
on mount and destroyDb() for logout cleanup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- GET/POST /api/admin/users — list and create users (admin only)
- PATCH/DELETE /api/admin/users/[id] — update role/reset password, delete user
- PUT /api/auth/password — change own password
All admin routes guarded by requireAdmin().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add layout.server.ts to pass event.locals.user to the client.
Header now shows user avatar initial with dropdown menu
(Settings link, Log out button).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add getUserId/requireAdmin helpers in api-utils.ts. All notes, tags,
search, sync, and attachment routes now filter by userId to ensure
complete data isolation between users. Sync server accepts userId
parameter for push/pull operations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Login page now requires email + password. Setup page adds email and
optional display name fields. API endpoints updated to pass email
to verifyPassword/setupUser and explicit userId to createSession.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
validateSession now returns user data. Middleware sets event.locals.user
on every authenticated request. Add /api/auth/oauth to public paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Define App.Locals.user interface for session user data.
Add User type to shared types (mirrors DB columns minus passwordHash).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add email, displayName, role, authProvider, providerId to users table.
Add userId foreign key to notes, tags, attachments, syncLog tables.
Add loginAttempts table for rate limiting. Include migration logic
to detect old single-user schema and backfill existing data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
loadNotes() crashed entirely if IndexedDB was unavailable because
getAllNotes() was called outside try/catch. Non-OK API responses
(401, 500) were silently ignored across loadNotes, createNote, and
sync operations — users saw empty data with no feedback.
Changes:
- Wrap all IDB calls in try/catch so the app works without IndexedDB
- Show toast on non-OK API responses in loadNotes and createNote
- Redirect to /login on 401 responses
- Make sync pull/push resilient to IDB unavailability
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DBs created before the image upload feature had no thumbnail_path column
in the attachments table. Since CREATE TABLE IF NOT EXISTS is a no-op for
existing tables, the column was never added, causing silent insert failures.
Add idempotent ALTER TABLE migration for thumbnail_path and surface upload
errors via toast notifications instead of swallowing them silently.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Images are hidden from card thumbnails by default. Users explicitly
feature images via a star toggle in the upload panel, and only featured
images appear in the card header strip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clicking a thumbnail in the editor, closed-panel view, or note card
opens a full-screen overlay with the full-size image. Closes on Escape,
background click, or X button. Escape is scoped so it won't close the
editor underneath.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of disabling the image button for unsaved notes, clicking it
now auto-saves the note first (with title "Untitled" if empty), then
opens the upload panel. This removes friction from the upload flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use static test-image.png fixture instead of dynamic beforeAll creation
- Add thumbnail_path column to auto-create SQL in db/index.ts
- Hover on thumbnail before clicking remove button (group-hover:block CSS)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Bump IDB version to 2, add pendingAttachments object store with noteId index
- Add CRUD helpers: addPendingAttachment, getPendingAttachments, removePendingAttachment
- ImageUpload stores blobs in IDB when offline, displays via blob URLs
- Show pending sync indicator (RefreshCw icon) on not-yet-uploaded images
- Add pushPendingAttachments to sync client, runs after note push
- Pending attachments auto-upload on reconnect via existing online event listener
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Import ImageUpload into NoteEditor with attachment state management
- Add $effect to fetch attachments for existing notes loaded from IDB
- Add upload/remove handlers and image toggle button in toolbar
- Show ImageUpload panel between content and formatting toolbar
- Add full-bleed thumbnail strip at top of NoteCard (up to 3 images)
- Use &thumb=1 URL for card previews with lazy loading
- Show +N badge when more than 3 attachments
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add fetchAttachmentsForNotes() batch helper mirroring fetchTagsForNotes pattern
- Include attachments in all note API responses (list, single, sync)
- Fix ImageUpload.svelte URL bug (path-based → query param)
- Add client-side image optimization (resize, compress, WebP conversion)
- Add thumbnailPath column to attachments schema with migration
- Update saveAttachment/deleteAttachment for thumbnail file handling
- Update attachment API: accept thumbnail in POST, serve via &thumb=1 in GET
- Add Cache-Control immutable header for served attachments
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply the same max-md:opacity-100 pattern from NoteCard to Checklist
drag handles and remove buttons, making them visible on touch devices.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On touch devices, hover states don't work, so the pin/archive/delete
buttons were invisible. Now they're always visible on screens below the
md breakpoint and only hover-toggled on desktop.
https://claude.ai/code/session_013DdAk1yj6r3VF6Ze4ycidp
- Increase gap between checkbox and text input (gap-1 → gap-2)
- Disable markdown toggle button in checklist mode
- Default to raw markdown mode when opening checklist notes as text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add X button to done/completed checklist items, matching the
existing remove button on active items.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use dragHandleZone with grip icon instead of whole-card dragging,
so card interactions (checkboxes, pin, archive) still work
- Scope pinned/unpinned grids to separate dnd types to prevent
cross-zone drag bugs
- Add h-full to flip wrapper and NoteCard for equal card heights
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Completed items now consistently appear below unchecked items in both
the editor and the note card preview. Replaces the flaky two-state
hide/show toggle with a simple expand/collapse for the done section.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>