commits
- 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>
🪻 Generated with Crush
Co-Authored-By: Crush <crush@charm.land>
The classes tests were creating a separate test database file but the
functions being tested still used the production database, causing tests
to fail when production data existed.
Changed to match the pattern used in other tests (auth.test.ts, etc):
- Use production database
- Track created resources in beforeEach/afterEach
- Clean up all test data after each test
- Helper functions to create and track test users/classes
💖 Generated with Crush
Co-Authored-By: Crush <crush@charm.land>
- Migrate biome config to version 2.3.2
- Replace explicit any types with proper interfaces
- Remove non-null assertions with proper null checks
- Apply all auto-formatting fixes
💖 Generated with Crush
Co-Authored-By: Crush <crush@charm.land>
The audio endpoint now accepts both "pending" and "completed" status, allowing admins to preview pending recordings before transcription.
💘 Generated with Crush
Co-Authored-By: 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>
The classes tests were creating a separate test database file but the
functions being tested still used the production database, causing tests
to fail when production data existed.
Changed to match the pattern used in other tests (auth.test.ts, etc):
- Use production database
- Track created resources in beforeEach/afterEach
- Clean up all test data after each test
- Helper functions to create and track test users/classes
💖 Generated with Crush
Co-Authored-By: Crush <crush@charm.land>