commits
- Sort imports in index.test.ts
- Auto-format schema.ts, email.ts, vtt-cleaner.test.ts
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
- Extract inline scripts to external .ts files (index, admin, reset-password)
- Extract inline styles to external .css files (index, admin, settings, transcribe, reset-password)
- Add CSP meta tags to all HTML pages with strict policy
- CSP policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:
- Replace inline style attributes with CSS classes (.hidden, .back-link, .mb-1)
This provides strong XSS protection while maintaining compatibility with
Bun's HTML bundler pattern. CSP is enforced via meta tags in each HTML page.
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
Admin endpoints now return clean arrays instead of paginated objects:
- /api/admin/transcriptions → returns array (pagination happens behind scenes)
- /api/admin/users → returns array (pagination happens behind scenes)
- /api/classes (admin) → returns flat array instead of grouped object
Pagination still works via ?limit=50&cursor=... params but frontend just
sees clean arrays. This keeps the API simple while maintaining scalability.
User-facing /api/classes still returns grouped format for better UX.
Backend supports pagination, frontend can add "Load More" UI later.
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
Admin transcriptions and users components now extract data from paginated
response format { data: [...], pagination: {...} } with fallback to direct
array for backward compatibility.
Convert all message-only responses to include success field for consistency:
- { message: "..." } → { success: true, message: "..." }
Standardized patterns:
- Success operations: { success: true }
- Success with message: { success: true, message: "..." }
- Success with data: { success: true, data: {...}, message?: "..." }
- Error responses: { error: "..." } (unchanged)
- Data responses: Direct objects like { user, jobs, classes } (unchanged)
Changes:
- Email verification success response
- Verification email sent response
- Verification code sent response
- Password reset link sent response
- Password reset success response
Added comprehensive test suite documenting API response standards.
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
Implement cursor-based pagination with base64url-encoded cursors for:
- GET /api/transcriptions (user's transcriptions)
- GET /api/admin/transcriptions (all transcriptions)
- GET /api/admin/users (all users with stats)
- GET /api/classes (user's classes)
Response format: { data: [...], pagination: { limit, hasMore, nextCursor } }
Query params: ?limit=50&cursor=<base64url-string>
Cursors are opaque, URL-safe, short strings (20-40 chars) that prevent
page drift and support efficient pagination at any scale.
Implementation:
- Created src/lib/cursor.ts for encoding/decoding cursors
- Updated getAllTranscriptions, getAllUsersWithStats, getClassesForUser
- Default limit: 50, max: 100
- Comprehensive test coverage (23 tests)
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
- Session cleanup: Run every 15 minutes instead of hourly (#26)
- Health check: Add detailed status for database, whisper, and storage (#25)
- Admin email change: Require verification unless skipVerification flag set (#36)
- Transcription selection: Validate existence and status before selecting (#28)
These changes improve system monitoring, security, and error handling.
Added detailed documentation for tangled-cli including:
- Authentication and installation
- Creating, listing, showing, editing issues
- Commenting on issues
- Repository commands
- Priority label filtering
- JSON output format
- Known issues with the CLI
Changed from semi-realistic looking values to clearly fake
placeholders using 'paste_your_*_here' format to prevent
confusion with real credentials.
Fixes issue #24
Check if class exists when toggling archive status and throw error
if not found. Prevents silent failures when archiving non-existent
classes.
Fixes issue #28 (partial)
- File uploads: 20/hour
- User settings (name, avatar, notifications): 10 per 5 min
- Session deletion: 20/hour
- Passkey operations: 10 per 5 min (auth), 10/hour (update/delete)
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
Implements graceful shutdown on SIGTERM/SIGINT that:
- Stops accepting new requests via server.stop()
- Closes all active SSE streams (sync will reconnect on restart)
- Stops transcription service streams to Murmur
- Clears cleanup intervals (sessions, sync, files)
- Closes database connections cleanly
Prevents database corruption and ensures clean shutdown.
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
- Extract inline scripts to external .ts files (index, admin, reset-password)
- Extract inline styles to external .css files (index, admin, settings, transcribe, reset-password)
- Add CSP meta tags to all HTML pages with strict policy
- CSP policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:
- Replace inline style attributes with CSS classes (.hidden, .back-link, .mb-1)
This provides strong XSS protection while maintaining compatibility with
Bun's HTML bundler pattern. CSP is enforced via meta tags in each HTML page.
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
Admin endpoints now return clean arrays instead of paginated objects:
- /api/admin/transcriptions → returns array (pagination happens behind scenes)
- /api/admin/users → returns array (pagination happens behind scenes)
- /api/classes (admin) → returns flat array instead of grouped object
Pagination still works via ?limit=50&cursor=... params but frontend just
sees clean arrays. This keeps the API simple while maintaining scalability.
User-facing /api/classes still returns grouped format for better UX.
Backend supports pagination, frontend can add "Load More" UI later.
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
Convert all message-only responses to include success field for consistency:
- { message: "..." } → { success: true, message: "..." }
Standardized patterns:
- Success operations: { success: true }
- Success with message: { success: true, message: "..." }
- Success with data: { success: true, data: {...}, message?: "..." }
- Error responses: { error: "..." } (unchanged)
- Data responses: Direct objects like { user, jobs, classes } (unchanged)
Changes:
- Email verification success response
- Verification email sent response
- Verification code sent response
- Password reset link sent response
- Password reset success response
Added comprehensive test suite documenting API response standards.
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
Implement cursor-based pagination with base64url-encoded cursors for:
- GET /api/transcriptions (user's transcriptions)
- GET /api/admin/transcriptions (all transcriptions)
- GET /api/admin/users (all users with stats)
- GET /api/classes (user's classes)
Response format: { data: [...], pagination: { limit, hasMore, nextCursor } }
Query params: ?limit=50&cursor=<base64url-string>
Cursors are opaque, URL-safe, short strings (20-40 chars) that prevent
page drift and support efficient pagination at any scale.
Implementation:
- Created src/lib/cursor.ts for encoding/decoding cursors
- Updated getAllTranscriptions, getAllUsersWithStats, getClassesForUser
- Default limit: 50, max: 100
- Comprehensive test coverage (23 tests)
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>
- Session cleanup: Run every 15 minutes instead of hourly (#26)
- Health check: Add detailed status for database, whisper, and storage (#25)
- Admin email change: Require verification unless skipVerification flag set (#36)
- Transcription selection: Validate existence and status before selecting (#28)
These changes improve system monitoring, security, and error handling.
Implements graceful shutdown on SIGTERM/SIGINT that:
- Stops accepting new requests via server.stop()
- Closes all active SSE streams (sync will reconnect on restart)
- Stops transcription service streams to Murmur
- Clears cleanup intervals (sessions, sync, files)
- Closes database connections cleanly
Prevents database corruption and ensures clean shutdown.
💘 Generated with Crush
Assisted-by: Claude Sonnet 4.5 via Crush <crush@charm.land>