# ActaLog TODO > **Last Updated:** 2026-04-02 > **Current Version:** 1.2.1 (Build 44) --- ## Claude Instructions **This is the canonical TODO file for ActaLog.** All task tracking should be done here. ### Guidelines for Claude Code: 1. **Only track TODOs here** - Do not create TODO sections in other documentation files 2. **Active Tasks** - Items currently being worked on (move here when starting) 3. **Backlog** - Planned features, known bugs, and improvements not yet started 4. **Completed Releases** - Keep only the last 5 releases here; older releases are in CHANGELOG.md 5. **Periodic Cleanup** - When starting a new session, clean up completed items and archive old releases 6. **Technical Details** - Include file paths and implementation notes for completed work 7. **Priority Markers** - Use `[HIGH]`, `[MEDIUM]`, `[LOW]` for backlog items 8. **Bug Format** - `[BUG]` prefix for bug reports 9. **Code TODOs** - Periodically scan codebase for TODO/FIXME comments: ```bash grep -rn "TODO\|FIXME" --include="*.go" --include="*.vue" --include="*.js" . ``` ### File Relationships: - `TODO.md` - Active task tracking (this file) - `CHANGELOG.md` - Release history and change documentation - `ROADMAP.md` - High-level version planning and feature roadmap - Do NOT duplicate TODO content in ROADMAP.md or CHANGELOG.md --- ## Active Tasks *Items currently being worked on. Move items here from Backlog when starting.* ### Class Scheduling System *(Completed)* **Status:** Phase 1-4 Complete **Phase 1-3 (v0.26.0 migration):** - [x] Gym locations, class templates, schedule slots - [x] Class sessions with capacity management - [x] Coach assignments (per-gym role) - [x] Reservations with check-in flow **Phase 4 (v0.27.0 migration):** - [x] Documents - Required documents (waivers, liability forms) per gym - [x] User Documents - Track document completion status per user - [x] Class Packages - Credit packages (e.g., "10-Class Pack") - [x] User Credits - Credit balances with expiration tracking - [x] Waitlist - Queue management when classes are full - [x] Class Notifications - Reminders and waitlist promotions **Frontend Views:** - [x] `ScheduleView.vue` - Browse sessions, reserve, join/leave waitlist - [x] `MyCreditsView.vue` - User's credits, documents, waitlist entries - [x] `MyReservationsView.vue` - User's upcoming reservations - [x] `AdminPackagesView.vue` - Admin management for packages, documents, user credits - [x] `AdminSchedulingView.vue` - Admin session/template management **API Endpoints (Phase 4):** - Documents: `GET/POST/PUT/DELETE /api/admin/gyms/{id}/documents` - Packages: `GET/POST/PUT/DELETE /api/admin/gyms/{id}/packages` - Credits: `POST /api/admin/gyms/{id}/users/{id}/credits`, `GET /api/gyms/{id}/users/me/credits` - Waitlist: `POST/DELETE /api/sessions/{id}/waitlist`, `GET /api/users/me/waitlist` - User documents: `GET /api/gyms/{id}/users/me/documents` **Database Tables (6 new in v0.27.0):** - `documents`, `user_documents`, `class_packages`, `user_class_credits`, `waitlist_entries`, `class_notifications` **Bug Fix:** PurchaseCredits now correctly uses package credits when `package_id` is provided without explicit `credits` value. **Tested on:** SQLite, MariaDB (192.168.1.234), PostgreSQL (192.168.1.143) --- ### Delete Class with Sessions *(Completed)* **Status:** Complete (Build 31) - [x] Three delete modes for class templates: - `template_only` - Delete template only, sessions orphaned - `with_future_sessions` - Delete template + future sessions, keep past - `with_all_sessions` - Delete template + all sessions - [x] Cascade deletion (coaches, reservations, waitlist, notifications) - [x] Credit refunds for unconfirmed reservations - [x] User notifications for cancelled sessions - [x] New UI dialog with mode selection and session counts - [x] API: `DELETE /api/admin/scheduling/templates/{id}?mode=` **Files Modified:** - `internal/domain/scheduling.go`, `internal/domain/phase4.go` - Interface methods - `internal/repository/class_session_repository.go` - Bulk delete methods - `internal/repository/session_coach_repository.go` - DeleteBySessionIDs - `internal/repository/reservation_repository.go` - GetBySessionIDs, DeleteBySessionIDs - `internal/repository/waitlist_repository.go` - DeleteBySessionIDs - `internal/repository/credits_repository.go` - RefundCredit - `internal/service/scheduling_service.go` - DeleteTemplateWithMode - `internal/handler/scheduling_handler.go` - Mode parameter handling - `web/src/views/AdminSchedulingView.vue` - Delete dialog UI **Tested on:** SQLite, MariaDB, PostgreSQL --- ### Test Suite Cleanup *(Completed)* **Status:** Phase 1 Complete, Phase 2 Complete **Tracking:** See `docs/TEST_CLEANUP.md` for detailed summary **Phase 1 - Removed ~31 low-value tests:** - Struct field assignment tests (19) - Language feature tests (10) - Trivial helper tests (2) **Phase 2 - Removed ~267 panic-expectation tests:** - All handler test files cleaned (24 files total) - Panic tests that created nil dependencies removed - Validation tests and mock-based tests preserved - All tests pass with proper coverage ### CI/Lint Fixes (Deferred) **Status:** golangci-lint set to `continue-on-error` in `.github/workflows/ci.yml:37` The following lint issues need to be resolved to re-enable strict linting: 1. **goconst warnings** - Repeated strings in SQL queries (LIMIT, OFFSET, ORDER BY) - Files: `internal/repository/movement_repository.go`, others - Decision: Either make constants or add exclusion 2. **Remaining gofmt issues** - Some files may still have formatting issues - Run: `gofmt -w ./...` and review changes 3. **Other minor issues** - Review full golangci-lint output for any remaining items **To re-enable strict linting:** 1. Fix or exclude remaining issues 2. Remove `continue-on-error: true` from `.github/workflows/ci.yml:37` --- ## Backlog ### High Priority #### Comprehensive Benchmark Endpoint *(Completed v0.22.0)* - [x] `[HIGH]` **Create `/api/benchmark` endpoint for system-wide performance testing** - Exercises database, serialization, business logic, and concurrency through synthetic operations - Uses isolated `benchmark_data` table (never touches real user data) - Auto-cleanup after runs, user-scoped data isolation - JWT authentication required - **Backend implementation:** - [x] Domain model (`internal/domain/benchmark.go`) - BenchmarkData entity, result structs, repository interface - [x] Migration 0.22.0 (`internal/repository/migrations.go`) - benchmark_data table with indexes - [x] Migration 0.23.0 - Extended fields for stress testing (large_text, json_blob, uuid) - [x] Repository (`internal/repository/benchmark_repository.go`) - CRUD + batch operations - [x] Service (`internal/service/benchmark_service.go`) - 18+ benchmark operations - [x] Handler (`internal/handler/benchmark_handler.go`) - POST /benchmark, GET /benchmark/status - [x] Route registration (`cmd/actalog/main.go`) - wire up handler - **Benchmark operations:** - Database: Insert, BulkInsert(100), SelectByID, SelectByKey, SelectList, SelectFiltered, Update, Delete - Serialization: Marshal/Unmarshal small & large JSON - Business Logic: 1RM calculations (1000x), validation, string/date operations - Concurrent (optional): 10 parallel reads, 5 writes, mixed operations - **Configurable record count:** - [x] `?records=N` query parameter (default: 1000, max: 500000) - [x] Complex benchmark data (5-10KB text, nested JSON blobs) - [x] Server timeout configuration for large record counts - **Benchmark tool integration (`actalog-benchmark` v0.7.0):** - [x] Add `/api/benchmark` caller (`internal/metrics/benchmark_api.go`) - [x] Add BenchmarkAPIResult to types.go - [x] Update reporters to include benchmark API results - [x] Add `--benchmark-records` flag for configurable record count - [x] Comparison reports include server-side benchmark results #### Subscription System (Backend Complete - v0.14.0, Frontend Complete - v0.17.0) - [x] `[HIGH]` **Frontend Subscription Status Display** - [x] Add subscription status badge to user profile/settings (SubscriptionStatusBadge.vue in SettingsView) - [x] Show expiration date for paid subscriptions - [x] Display "Permanent Free" badge for permanent users - [x] Show organization subscriptions the user benefits from - [x] `[HIGH]` **Admin Subscription Management UI** - [x] Admin panel for viewing all user subscriptions (AdminSubscriptionsView.vue) - [x] Admin panel for viewing all organization subscriptions - [x] Create subscription form (CreateSubscriptionDialog.vue) - [x] Mark subscription as paid button/action (MarkAsPaidDialog.vue) - [x] Cancel subscription with reason input (CancelSubscriptionDialog.vue) - [x] View subscription history (SubscriptionDetailDialog.vue) - [x] List expiring subscriptions API (backend complete v0.19.0) - [x] List overdue/expired subscriptions API (backend complete v0.19.0) - [x] Frontend UI for expiring/expired subscription lists (AdminSubscriptionsView.vue tabs) - [x] `[HIGH]` **Read-Only Mode UI Feedback** - [x] Graceful handling of HTTP 402 Payment Required responses (subscription.js store) - [x] Show "Subscription Expired" banner when in read-only mode (SubscriptionExpiredBanner.vue in App.vue) - [x] Disable/hide create/edit buttons when subscription expired - [x] "Renew Subscription" call-to-action in banner - [ ] Toast notifications explaining why operations are blocked #### Front end Improvements - [x] `[HIGH]` **PWA** - [x] Icon saved to home screen is fuzzy - regenerated all icons from SVG with full RGBA color - [x] `[HIGH]` **Overall** - [x] Find more attractive icons for the navigation bar - replaced with Font Awesome icons (fa-house-chimney, fa-arrow-trend-up, fa-person-running, fa-circle-user) - [x] Allow notifications to be marked as read/unread (implemented in NotificationsView.vue) - [x] Develop a theme called "Sunrise" based on colors from sunset image (added to vuetify.js and theme.js) - [x] Remove the View all link on the Dashboard (removed from DashboardView.vue) - [x] Add more helper text to form controls throughout the app - Added markdown hints to textarea fields in WODCreateView, WODEditView, MovementCreateView, MovementEditView, WorkoutTemplateEditView, AdminAnnouncementsView (v0.22.0) - [x] `[HIGH]` **User-Customizable Fonts** *(Completed v0.19.0)* - Self-hosted web fonts with 10 options (including accessibility fonts) - Backend sync via user_settings table + localStorage cache - All fonts use SIL OFL 1.1 or Apache 2.0 (free for commercial use, self-hosting allowed) - **Font options:** - System Default, Inter, Roboto, Lato, Fira Sans, Lexend - OpenDyslexic (A11y), Atkinson Hyperlegible (A11y) - Source Serif Pro, JetBrains Mono - **Backend changes:** - [x] Add `font_family` field to `internal/domain/user_settings.go` - [x] Add migration 0.21.0 in `internal/repository/migrations.go` - [x] Update SQL queries in `internal/repository/user_settings_repository.go` - [x] Add default + audit logging in `internal/service/user_settings_service.go` - **Frontend changes:** - [x] Download fonts to `web/public/fonts/` (woff2 format) - [x] Create `web/src/assets/fonts.css` with @font-face declarations - [x] Create `web/src/stores/font.js` (font store) - [x] Update `web/src/stores/settings.js` (add fontFamily sync) - [x] Update `web/src/App.vue` (use CSS variable `--app-font-family`) - [x] Add font selector UI in `web/src/views/SettingsView.vue` - **Performance:** `font-display: swap`, service worker caching, only selected font loads #### Security (closed in v1.2.4 hardening branch) - [x] `[HIGH]` **Security Response Headers Middleware** *(Completed v1.2.4)* — Added `pkg/middleware/security_headers.go` setting X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS, and a project-tuned CSP. Wired after CORS in `cmd/actalog/main.go`. Tests in `security_headers_test.go` assert per-header values and that script-src stays free of `'unsafe-inline'`/`'unsafe-eval'`. - [x] `[HIGH]` **Avatar Upload Magic-Byte Validation** *(Completed v1.2.4)* — Replaced trust-the-header check with `http.DetectContentType()` over the first 512 bytes plus a `.jpg/.jpeg/.png/.gif/.webp` extension allowlist. Negative tests cover spoofed-Content-Type and disallowed-extension cases. #### Backend Improvements - [x] `[HIGH]` **Backup and Restore** make sure the backup functions keep up with the database schema changes (tested backup and restore round trips on SQLite, PostgreSQL, and MariaDB). - [x] Added schema metadata to backup format for type-aware restoration - [x] Implemented three restore modes: `replace`, `merge`, `skip` - [x] Natural key matching (users by email, movements by name, etc.) - [x] ID remapping for foreign key references during merge/skip - [x] `[HIGH]` **Duplicate Record Protection** - [x] All imports now protect against duplicate records: - [x] WOD Import: `skip_duplicates` and `update_duplicates` options - [x] Movement Import: `skip_duplicates` and `update_duplicates` options - [x] User Workout Import: Added `update_duplicates` option (v0.17.0) - [x] Wodify Import: Added `skip_duplicates` and `update_duplicates` options (v0.17.0) - [x] System restore supports merge/skip modes with natural key matching - [x] API returns detailed results (records created, updated, skipped) - [x] `[HIGH]` **Check for missing indexes** - 83 indexes defined in migrations (foreign keys and commonly queried fields covered) - [x] `[HIGH]` **Audit Log Enhancements** - Added 17+ helper methods for comprehensive audit coverage (logout, token refresh, profile updates, user deletion, organization CRUD, subscription lifecycle) - [x] `[HIGH]` **Database Query Optimization** - Added audit_logs indexes (migration 0.17.0), optimized GetUsageStats (3→1 query), GetActiveUsersThisMonth (3→2 queries), ListByUserWithDetails N+1 fix (6N+1→5 queries) - [x] `[HIGH]` **Error Handling Consistency** - Centralized error handling in internal/handler/errors.go with HTTPError type and 30+ service error mappings - [x] `[HIGH]` **Structured Logging** - Added JSON format support to pkg/logger with InfoWithFields, ErrorWithFields, and FieldLogger chaining - [x] `[HIGH]` **Comprehensive API Documentation** - OpenAPI/Swagger documentation at `/docs/swagger.json` (v0.22.0) - [x] `[HIGH]` **Implement Rate Limiting** - pkg/middleware/rate_limit.go with sliding window algorithm 5. **Documentation Website** - Build a dedicated user and admin guide website from Markdown documents - Use a static site generator (e.g., MkDocs, Docusaurus, VitePress, Hugo) to convert existing Markdown docs into an attractive HTML site with navigation, search, and theming - Separate user guide (workout logging, schedules, PRs, leaderboards) and admin guide (user management, scheduling config, backups, subscriptions) - Host alongside the app or as a standalone site ## Future Enhancements (Post-MVP) These features can be added after the core frontend is complete: 1. **Stripe Integration** (v0.15.0+) - Replace manual admin control with automated billing webhooks - Credit card payment processing - Automatic subscription renewal 2. **Email Notifications** (v0.15.0+) - Notify users 7/3/1 days before expiration - Notify users when subscription expires - Notify admins of failed payments 3. **Self-Service Portal** (v0.16.0+) - Users can upgrade/downgrade themselves - View payment history - Update payment method 4. **Usage Limits** (v0.16.0+) - Track API usage for free tier - Enforce limits on free subscriptions - Display usage metrics 5. **Bulk Operations** (v0.17.0+) - Admin can bulk-update subscriptions - Bulk extend expiration dates - Bulk cancel subscriptions 6. **Grace Period Configuration** (v0.17.0+) - Make grace period configurable per organization - Different grace periods for different subscription tiers #### Testing Coverage (81.6% Service Layer) - [x] `[HIGH]` **Subscription Service Tests** - Comprehensive test suite (internal/service/subscription_service_test.go) - [x] `[HIGH]` **Backup Service Tests** - 10 test functions with full restore mode coverage (internal/service/backup_service_test.go) - [x] `[HIGH]` **User Workout Service Tests** - Complete coverage with PR detection - [x] `[HIGH]` **Wodify Import Service Tests** - Duplicate handling and error recovery - [x] `[HIGH]` **Most Service Tests Complete** - 13 services at 100% coverage - [x] `[HIGH]` **Add handler unit tests** - Handler coverage at 72.6% - [x] benchmark_handler_test.go (17 tests, 53-100% coverage per method) - [x] auth_handler_test.go (63-100% coverage, comprehensive with mock service) - [x] user_workout_handler_test.go (32-100% coverage) - [x] movement_handler_test.go (59-100% coverage) - [x] wod_handler_test.go (84-100% coverage) - [x] subscription_handler_test.go (28-69% coverage) - [x] All other handlers have tests: settings, admin, performance, data_change_log, organization, etc. - [ ] `[MEDIUM]` **Improve user_service coverage** - Currently 61.9%, target 80%+ - [ ] `[MEDIUM]` **Improve import_service coverage** - Currently 60.8%, target 80%+ - [ ] `[LOW]` **Add repository unit tests** - All repository implementations #### Admin Features - [x] **Comprehensive User Edit Screen — Profile tab + framework (v1.3.0)** - Shipped: Profile tab, four-layer defense-in-depth, recovery tooling, full documentation - Plan: `docs/superpowers/plans/2026-04-28-admin-user-edit-v1.3.0-plan.md` - [x] `[HIGH]` **Admin: Create User flow on User Management screen (v1.3.2)** — `POST /api/admin/users` + "Create User" dialog. Tracked: [#217](https://github.com/johnzastrow/actalog/issues/217) *(Completed v1.3.2)* - [x] `[HIGH]` **Admin: edit full user details on Profile tab (v1.3.2)** — Profile tab Password Management card with admin-set password (separate from force-password-reset) *(Completed v1.3.2)* - [x] `[HIGH]` **Admin: break-glass CLI for protected users (v1.3.2)** *(Completed v1.3.2)* — `actalog admin force-edit-protected --email=X --field= [--value=...] --confirm`. Per-field audit events; identity-field changes drop+UPDATE+reinstall L3 triggers and re-run the boot invariant. Documented in `docs/security/PROTECTED_USERS.md` §"Break-glass CLI" - [ ] `[HIGH]` **User Edit Screen — Affiliations tab (v1.3.1)** — gym memberships, coach assignments per gym; add/remove org membership; manage `CoachAssignment` per `GymLocation` (assign/revoke coach role per gym); view `TemplateCoach` and `SessionCoach` rows that reference this user - [ ] `[HIGH]` **User Edit Screen — Subscriptions / Credits / Preferences / Activity tabs (v1.3.2)** — complete the remaining tabs deferred from v1.3.0: Subscriptions, Class Credits & Documents, Preferences (UserSettings), and read-only Activity & Audit summary - [x] `[HIGH]` **User Import/Export System** (Admin only) *(Completed v0.23.0)* - [x] Export users to CSV format (email, name) - [x] Import users from CSV (email, name, password) with preview/confirm workflow - [x] Preview workflow with validation - [x] Duplicate detection by email - [x] Batch password reset emails - select users from filterable list - **Backend files:** `internal/service/user_import_service.go`, `internal/handler/user_import_handler.go` - **Frontend:** `web/src/views/AdminUserImportExportView.vue` with 3 tabs (Import, Export, Password Reset) - **API endpoints:** - `POST /api/admin/users/import/preview` - Preview CSV import - `POST /api/admin/users/import/confirm` - Execute import - `GET /api/admin/users/export` - Download CSV - `GET /api/admin/users/filter` - List users with search/date filters - `POST /api/admin/users/batch-password-reset` - Send reset emails to selected users - [x] `[HIGH]` **Improved Duplicate Record Detection During Imports** (v0.17.0) - [x] Trap duplicate movements during import (check by name) - [x] Trap duplicate WODs during import (check by name) - [x] Trap duplicate user workouts during import (check by date/user/name) - [x] Trap duplicate Wodify workouts during import (check by date) - [x] Import options for handling duplicates: - [x] Skip duplicates (keep existing) - `skip_duplicates=true` - [x] Update duplicates (overwrite existing) - `update_duplicates=true` - [x] Detailed import result with created/updated/skipped counts - [ ] Frontend UI to review and select action for each duplicate - [ ] Batch duplicate resolution UI (apply same action to all) - [x] `[HIGH]` **Database Duplicate Detection and Cleaning Procedure** *(Completed v0.24.0)* - [x] Create admin tool to scan for existing duplicates in database - [x] Detect duplicate movements (case-insensitive name matching) - [x] Detect duplicate WODs (case-insensitive name matching) - [x] Detect duplicate user workouts (same user, same date, same name) - [x] Detect duplicate users (case-insensitive email matching) - [x] Detect duplicate workout templates (same name, same user) - [x] Generate duplicate report with: - Count of duplicates per entity type - List of duplicate groups with record IDs - FK reference counts for each record - [x] Safe merge/cleanup procedure: - Preview which records will be kept vs deleted - Automatically update foreign key references - Delete child records from duplicates (movements/WODs) - Preserve data integrity with transaction support - [x] Admin UI to review and approve cleanup (AdminDataQualityView.vue) - [x] Preview mode shows FK impact before confirming - [x] Audit log of all merge operations (duplicate_merge event type) - [x] **Data Quality Issue Detection** - 4 quality checks: - Orphaned FK references (error severity) - Empty required fields (error/warning severity) - Future workout dates (warning severity) - Invalid email formats (warning severity) - **Backend files:** `internal/service/data_quality_service.go`, `internal/handler/data_quality_handler.go` - **Frontend:** `web/src/views/AdminDataQualityView.vue` with 3 tabs (Overview, Duplicates, Data Issues) - **API endpoints:** - `GET /api/admin/data-quality/duplicates` - Scan all entities - `GET /api/admin/data-quality/duplicates/summary` - Quick summary - `GET /api/admin/data-quality/duplicates/{entity}` - Scan specific entity - `POST /api/admin/data-quality/duplicates/merge/preview` - Preview merge - `POST /api/admin/data-quality/duplicates/merge/confirm` - Execute merge - `GET /api/admin/data-quality/issues` - Scan for data quality issues ### High Priority #### Documentation & Marketing - [x] `[High]` **Enhance App Documentation with Screenshots** - [x] `[High]` Static site deployed to GitHub Pages (https://johnzastrow.github.io/actalog/) - [x] Home page with feature highlights and theme gallery - [x] For Admins page with subscription and announcement features - [x] For Developers page with tech stack, architecture, and deployment guide - [x] Performance & Benchmarks section added (v0.22.0) - minimum resources, load test results - [x] FAQ page - [x] Auto-deploy via GitHub Actions on push to main - [x] All 7 themes documented with screenshots (Myst added v0.24.0) - [x] Responsive design & PWA benefits explained in "Works Everywhere" section - [x] User flow guide added ("Your Workout Journey" 3-step visual guide) #### Performance & Analytics - [x] `[MEDIUM]` **Calendar View** - WorkoutCalendarView.vue with workout dots and month navigation - [x] `[MEDIUM]` **Timeline View** - WorkoutTimelineView.vue with chronological history - [x] `[MEDIUM]` **Progress Charts** - WeightProgressChart.vue and WorkoutFrequencyChart.vue components (not yet integrated into views) - [x] `[MEDIUM]` **Admin Metrics Dashboard** - User stats, workout counts, system health (v0.22.0) - [x] `[MEDIUM]` **1RM Percentage Display** - Performance page 1RM percentage tops out at 95%; needs to also show 100% of the maximum weight lifted - [x] `[MEDIUM]` **PR Leaderboards** - Opt-in community leaderboards (migration 0.33.0, leaderboard_opt_in setting, movement/WOD leaderboard API endpoints, LeaderboardView.vue) #### Testing - [x] `[MEDIUM]` **Add backup_service tests** - backup_service_test.go with 10 test functions covering create/restore/export - [x] `[MEDIUM]` **Add wodify_import_service tests** - wodify_import_service_test.go with duplicate handling - [ ] `[MEDIUM]` **Add export/import_service tests** - Currently at 60-83% coverage - [ ] `[MEDIUM]` **Add admin_handler tests** #### PWA Enhancements *(Audited v0.24.0)* - [x] `[MEDIUM]` **Lighthouse PWA audit completed** (Jan 2026) - Performance: 56/100 (throttled network), Best Practices: 100/100, SEO: 92/100 - PWA features verified: service worker, offline caching, installable manifest - Issues found: color contrast, meta viewport user-scalable, touch target sizes - [x] `[MEDIUM]` **Service worker cache analysis completed** - Total precache: 6.9MB (150+ entries) - Material Design Icons: 3.5MB (4 formats) → **Optimization: remove ttf/eot, keep woff2 only (394KB)** - Self-hosted accessibility fonts: 848KB (9 families, 22 files) - JavaScript: 1.5MB (properly chunked), CSS: 848KB - Runtime caching: API responses (NetworkFirst), fonts (CacheFirst), uploads (StaleWhileRevalidate) - [x] `[MEDIUM]` **Offline sync implementation reviewed** - IndexedDB storage for workouts, movements, pending sync queue - Axios interceptor saves POST/PUT /api/workouts offline when network unavailable - syncWithServer() replays pending operations when back online - User-controlled updates via UpdatePrompt.vue and pwa.js store - **Status: Fully implemented, works for workout logging** **Remaining PWA optimizations (deferred):** - [x] `[LOW]` **Remove unused MDI font formats** - Custom Vite plugin `mdiWoff2Only()` strips ttf/eot/woff - Dist size: 6.9MB → 3.8MB (45% reduction) - Precache: 6.9MB → 3.4MB (50% reduction) - Only woff2 (394KB) shipped to production - [x] `[LOW]` **Lazy-load accessibility fonts** - Fonts loaded on-demand when user selects them - Split fonts.css into 9 separate font family CSS files - Font store dynamically imports CSS via Vite's dynamic import - Fonts excluded from precache via globIgnores - Runtime caching (CacheFirst) caches fonts on first use - Precache: 3.4MB → 2.6MB (additional 24% reduction) - [x] `[LOW]` Fix accessibility issues (color contrast, touch targets) - Fixed label contrast (#666666 for 5.74:1 ratio), touch target sizes (24x24px min) #### Roles & Permissions - [x] `[HIGH]` **Coach Role** *(Completed Build 36)* - Added dedicated `coach` role (migration 0.32.0). Renamed `"user"` to `"athlete"`. Three-tier role system: athlete < coach < admin. `CoachOrAdmin` middleware protects `/api/coaches/` routes. Coaches bypass subscription checks. Coach Dashboard uses dedicated `/api/coaches/sessions/` endpoints with org-level access verification. Bottom nav shows Coach button for coach/admin roles when scheduling enabled. - **Admin all-sessions visibility:** Admins see ALL upcoming sessions across all gyms on Coach Dashboard (not limited to coach assignments). Added `GetAllUpcoming` repo method and `GetAllUpcomingSessions` service method; handler branches on role. - **Comprehensive role/access middleware tests:** 14 new test functions in `pkg/middleware/auth_test.go` and `pkg/middleware/subscription_test.go` covering all role permutations for `AdminOnly`, `CoachOrAdmin`, and `RequireActiveSubscription` middleware. Includes full JWT→middleware integration tests. - **Files modified:** `internal/domain/scheduling.go`, `internal/repository/class_session_repository.go`, `internal/service/scheduling_service.go`, `internal/handler/scheduling_handler.go`, `pkg/middleware/auth_test.go`, `pkg/middleware/subscription_test.go` - **Docker images pushed:** `ghcr.io/johnzastrow/actalog:dev`, `:latest`, `:1.1.0-beta` (Build 36) ### Low Priority #### Testing - [x] `[LOW]` **Add audit_log_service tests** - 100% coverage achieved - [x] `[LOW]` **Add wodify_import_service tests** - 100% coverage achieved #### Features - [x] `[MEDIUM]` **Admin Screen Consolidation (Partial)** - Grouped Profile screen's 16 admin links into 5 labeled categories (Users & Access, Scheduling, Communication, Data & System, Organizations) using `v-list-subheader` dividers. Removed disabled "System Reports" placeholder. Full tab consolidation of admin screens into complex tabbed views remains for future work. - [x] `[MEDIUM]` **Consistency Achievement Notifications** - Daily scheduler checks all users for milestones (50/100/200/300 workouts, 4+/week, day streaks 4/7/14/21/30, inactivity warnings). Migration 0.34.0 consistency_achievements table, dedup via UNIQUE constraint, notification icons in NotificationsView. - [ ] `[LOW]` **Push Notifications** - Workout reminders - [ ] `[LOW]` **Data Visualization** - Charts for PR progression - [ ] `[LOW]` **Social Features** - Share workouts (opt-in) - [x] `[MEDIUM]` **UI Styling Consistency Review (Partial)** - Replaced hardcoded `#2c3e50` inline color styles with Vuetify theme classes (`text-h6`, `text-subtitle-1`) in AdminDataQualityView (4 occurrences), AdminDataCleanupView (3), and AdminView (1) for dark mode compatibility. Remaining screens (WorkoutCalendarView, WorkoutTimelineView fixed headers; PerformanceView Chart.js config) flagged for future review. - [x] `[MEDIUM]` **Admin Breadcrumbs & Navigation Consistency (Partial)** - Fixed AdminSchedulingView to use shared AdminHeader component instead of custom gradient header, adding breadcrumb navigation (Admin > Scheduling) consistent with all other 17 admin views. Full audit of remaining admin views for navigation consistency remains for future work. #### Technical Debt - [ ] `[LOW]` **Multiple Save Issue** - TemplateEditDialog save() is being called 3x instead of 1x; investigate root cause (possibly related to Vue reactivity with Schedule tab slots) --- ## Known Bugs *Report bugs here with reproduction steps.* *(none currently)* --- ## Code TODOs *TODOs found in source code comments. These should be addressed or promoted to Backlog.* ### Backend (Go) | File | Line | Description | |------|------|-------------| | `internal/service/workout_service.go` | 396 | Add proper authorization through workout template ownership | | ~~`internal/service/import_service.go`~~ | ~~587, 701~~ | ~~Add duplicate detection using userWorkoutRepo.ListByUserAndDateRange~~ **DONE (v0.17.0)** | | `internal/handler/movement_handler.go` | 141 | Get user ID from context when auth middleware is added | ### Frontend (Vue) | File | Line | Description | |------|------|-------------| | `web/src/views/WorkoutsView.vue` | 372 | Navigate to template detail page | *Last scanned: 2026-01-09* **Note:** Calendar view (WorkoutCalendarView.vue) and PR notification system are implemented. --- ## Completed Releases ### v1.2.4 (2026-04-28 — Security Hardening, part two) **Status:** Released from `security/headers-and-uploads-2026-04-28`. Closes the two items deferred from v1.2.3. **Completed:** - [x] **Security** — Security response headers middleware (`pkg/middleware/security_headers.go`) sets X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS, and a project-tuned CSP on every response; wired after CORS in `cmd/actalog/main.go` - [x] **Security** — Avatar upload no longer trusts client `Content-Type`; uses `http.DetectContentType` over first 512 bytes plus extension allowlist (`internal/handler/user_handler.go`) - [x] **CI** — CI Failure Notify workflow now deduplicates issues per (workflow, branch) and auto-closes when a subsequent run on the same branch succeeds (`.github/workflows/ci-failure-notify.yml`) - [x] **Maintenance** — 8 Dependabot bumps merged (deploy-pages, setup-buildx, lib/pq, x/crypto, pgx, vue-ecosystem, go-sqlite3, dev-dependencies group); 2 closed with policy comments (Vuetify 4.0.5 watch-and-wait, axios 1.14.0 supply-chain) --- ### v1.2.3 (2026-04-03 — Security Hardening) **Status:** Released from `security/hardening-2026-04-03`. **Completed:** - [x] **Security** — Password policy raised to 12-char min + uppercase/lowercase/digit (`internal/service/user_service.go`); UI hints and client-side validation updated in RegisterView, SettingsView, ResetPasswordView, AdminUserImportExportView - [x] **Security** — `WriteError()` no longer leaks raw internal error strings to HTTP responses - [x] **Security** — DOMPurify 3.3.3 added to `MarkdownRenderer.vue`; all `v-html` output sanitized - [x] **Security** — `serialize-javascript` pinned to 7.0.5 via `package.json` overrides (RCE + DoS CVEs) - [x] **Security** — Rate limiter IP extraction fixed: leftmost XFF IP taken, RemoteAddr port stripped - [x] **Security** — `rate_limit_exceeded` audit events now emitted from auth and password-reset limiters - [x] **Security** — CORS allowlist now actually enforced — `pkg/middleware/cors.go` no longer echoes disallowed origins back as `Access-Control-Allow-Origin`; test asserts header absence for disallowed origins - [x] **Feature** — Admin organizations list shows member count and supports edit-from-list - [x] **CI** — golangci-lint upgraded to v2.11.4; config migrated to v2 format - [x] **CI** — Frontend unit tests added to CI pipeline; 11 new Vitest suites covering App shell, auth store, axios interceptor, and admin views - [x] **Docs** — `docs/OWASP_AUDIT_2026-04-03.md`, `docs/MATURITY_ASSESSMENT.md`, `docs/plans/SECURITY_HARDENING_PLAN.md` capture the audit and remediation plan --- ### v1.2.1 (2026-04-01) **Status:** Patch release — security fixes, dependency maintenance, CI hardening. **Completed:** - [x] **Security** — Pinned axios to 1.13.5 (supply chain attack mitigation, 2026-03-31 incident) - [x] **Security** — `npm audit fix`: patched brace-expansion, picomatch, undici, yaml - [x] **Fix** — Calendar view now fetches all workouts (was capped at 20, causing missing entries) - [x] **Fix** — Admin breadcrumb returning 404 - [x] **Fix** — Avatar upload click target; removed stale debug logging - [x] **Feature** — Calendar header shows workout count for viewed month - [x] **UI** — Nav bar icons switched to heavier filled MDI variants - [x] **CI** — `setup-go` uses `go-version-file: go.mod` (auto-tracks toolchain version) - [x] **CI** — Pinned `golangci-lint-action` to v6 (v9 dropped v1.x support) - [x] **CI** — Fixed date-sensitive test failure on first day of each month - [x] **Deps** — Go: x/crypto 0.48→0.49, pgx/v5 5.8→5.9, go-sqlite3 1.14.34→1.14.38, lib/pq 1.11→1.12 - [x] **Deps** — Frontend: Vue 3.5.28→3.5.31, vue-router 5.0.3→5.0.4, vitest 4.0→4.1, sass 1.97→1.98 - [x] **Deps** — GH Actions: docker/login-action 3→4, docker/metadata-action 5→6, docker/build-push-action 6→7, actions/checkout 4→6, super-linter 4→7 **Known issues:** - `vite-plugin-pwa` dependency chain (serialize-javascript CVE) — fix requires major downgrade to 0.19.8; deferred to next release --- ### v1.2.0-beta (2026-02-19) **Status:** PR Leaderboards, configurable beta logo, nav and UI polish. **Completed:** - [x] PR leaderboards and consistency achievement notifications - [x] Configurable beta logo via `LOGO_VARIANT` env variable - [x] Leaderboard search API response parsing fix and header nav icon - [x] Improved avatar upload UX --- ### v1.1.0-beta (2026-01-22) **Status:** Coach role, three-tier permissions, class deletion modes, scheduling UX. **Completed:** - [x] Three-tier role system: athlete < coach < admin (migration 0.32.0) - [x] `CoachOrAdmin` middleware; dedicated `/api/coaches/` routes - [x] Delete class template with configurable cascade (template only / future sessions / all sessions) - [x] Credit refunds and notifications on session cancellation - [x] Coach Dashboard — admins see all sessions across all gyms --- ### v0.24.0-beta (2026-01-14) **Status:** Data Quality & Duplicate Detection system with merge functionality. **Completed:** - [x] **Data Quality Admin Dashboard** - [x] `AdminDataQualityView.vue` with 3 tabs (Overview, Duplicates, Data Issues) - [x] Full database scan with summary cards - [x] Duplicates by entity type breakdown - [x] Data quality checks with issue counts - [x] **Duplicate Detection & Merge** - [x] Scan 5 entity types: movements, WODs, user_workouts, users, workouts - [x] Case-insensitive name/email matching - [x] Composite key matching for user_workouts (user_id + date + name) - [x] Preview merge with FK reference counts - [x] Safe merge with FK updates in transaction - [x] Audit logging of all merge operations - [x] **Data Quality Issue Detection** - [x] Orphaned FK references (error severity) - [x] Empty required fields (error/warning severity) - [x] Future workout dates (warning severity) - [x] Invalid email formats (warning severity) - [x] Filter chips for issue type filtering - [x] **Frontend UI Improvements** - [x] Quality check type cards with icons, descriptions, counts - [x] Zero-state display with success checkmarks - [x] Clickable cards to navigate to filtered views - [x] Data Quality link added to admin menu in ProfileView - [x] **Demo Mode Configuration** - [x] Added DEMO MODE section to .env.example - [x] Documented implemented vs planned features - [x] Current workaround instructions for basic demo setup **Files Created:** `internal/service/data_quality_service.go`, `internal/handler/data_quality_handler.go`, `web/src/views/AdminDataQualityView.vue` **Files Modified:** `cmd/actalog/main.go` (routes), `web/src/router/index.js` (route), `web/src/views/ProfileView.vue` (admin menu link), `.env.example` (demo mode) **API Endpoints:** - `GET /api/admin/data-quality/duplicates` - Scan all entities for duplicates - `GET /api/admin/data-quality/duplicates/summary` - Quick duplicate summary - `GET /api/admin/data-quality/duplicates/{entity}` - Scan specific entity type - `POST /api/admin/data-quality/duplicates/merge/preview` - Preview merge operation - `POST /api/admin/data-quality/duplicates/merge/confirm` - Execute merge - `GET /api/admin/data-quality/issues` - Scan for data quality issues --- ### v0.22.0-beta (2026-01-09) **Status:** Comprehensive benchmark endpoint with configurable stress testing. **Completed:** - [x] **Benchmark API Endpoint** - [x] `POST /api/benchmark` - Full system benchmark with 18+ operations - [x] `GET /api/benchmark/status` - Quick status check - [x] `DELETE /api/admin/benchmark/data` - Admin cleanup - [x] Isolated `benchmark_data` table (never touches production data) - [x] Auto-cleanup after runs - [x] **Configurable Record Count** - [x] `?records=N` query parameter (default: 1000, max: 500000) - [x] Complex benchmark data (5-10KB text, nested JSON, UUIDs) - [x] Migration 0.23.0 for extended benchmark fields - [x] **Server Timeout Configuration** - [x] Fixed EOF errors on long-running benchmarks - [x] Updated default SERVER_WRITE_TIMEOUT to 60s - [x] Buffered JSON response with explicit Content-Length - [x] **Benchmark Tool Integration (actalog-benchmark v0.7.0)** - [x] `--benchmark-records` flag for configurable record count - [x] Server-side benchmark comparison in reports - [x] Enhanced error display with word wrapping - [x] **Static Site Updates** - [x] Performance & Benchmarks section on For Developers page - [x] Updated version to 0.22.0-beta - [x] Added Myst theme (7 total themes) **Files Created:** `internal/domain/benchmark.go`, `internal/repository/benchmark_repository.go`, `internal/service/benchmark_service.go`, `internal/handler/benchmark_handler.go` **Files Modified:** `internal/repository/migrations.go` (0.22.0, 0.23.0), `configs/config.go`, `.env.example`, `site/tech.html`, `site/index.html` --- *For releases prior to v0.24.0, see [CHANGELOG.md](./CHANGELOG.md)* ## Future Considerations These are longer-term ideas that may or may not be implemented: - **Kubernetes manifests** - For larger deployments - **Mobile native apps** - React Native or Flutter wrappers - **API rate limiting** - For multi-tenant deployments - **Webhook integrations** - Connect to external services - **Multi-language support** - i18n framework --- ## Technical Debt Items to address when time permits: - [ ] Refactor large view components (DashboardView, PerformanceView) into smaller sub-components - [ ] Add comprehensive API documentation (OpenAPI/Swagger) - [ ] `[HIGH]` **Thread `context.Context` through the repository layer** — currently **0 of 373** repository functions accept a `context.Context`, so no DB call has a timeout, deadline, or cancellation path. A slow/stuck database (or a client that disconnects) can hang a request/goroutine indefinitely. This is why `noctx` is disabled in `.golangci.yml` (~851 violations). Phased plan: 1. **Plumb context inbound** — pass `r.Context()` from each handler into the service call it makes (services already run per-request; mostly signature changes). 2. **Add context to service method signatures** — thread the handler's context down to the repository calls (mechanical, compiles incrementally per service). 3. **Add `ctx` as the first parameter to repository methods** and switch `db.Query/Exec/QueryRow` → `db.QueryContext/ExecContext/QueryRowContext`. Do it repository-by-repository (start with the hottest: `user_workout_repository`, `database.go`) so each PR is reviewable. 4. **Enforce** — re-enable the `noctx` linter in `.golangci.yml` once the count hits zero; `only-new-issues` then prevents regressions. 5. **Optional** — set a sensible default request timeout (e.g. chi `middleware.Timeout`) once cancellation actually propagates, so timeouts return 503 instead of hanging. *Rationale: biggest remaining reliability gap (per `docs/MATURITY_ASSESSMENT.md`). Large but mechanical; safe to land in small per-layer PRs.* - [ ] `[MEDIUM]` **Report test coverage in CI** — coverage is measured ad hoc (`web` has `npm run test:coverage`; Go has `-cover`) but never collected in CI, so there's no per-PR number, trend, or floor. Recommended rollout: 1. **Report-only first** — add `go test -coverprofile=coverage.out ./internal/... && go tool cover -func=coverage.out | tail -1` and `vitest run --coverage` (v8 provider already in dev-deps), writing the totals to `$GITHUB_STEP_SUMMARY`. Zero friction, no new deps. 2. **Then ratchet** — store the current % as a baseline and fail if a PR drops below it (prevents backsliding without demanding a big jump); or use *diff coverage* (only require new/changed lines to be covered). 3. Avoid an external service (Codecov/Coveralls) unless the PR-comment UX is worth the added third-party token — it re-widens the supply-chain surface just tightened in v1.4. *Effort: small. Risk: ~zero in report-only mode. Existing targets to chase live in the Backlog (user_service 61.9%→80%, import_service 60.8%).* - [ ] `[MEDIUM]` **Decompose oversized backend files** — split by responsibility (behavior-preserving; same package, so no import/route churn). Lean on the unit + 3-DB integration suites to prove no behavior change, and do **one file per PR** so review stays trivial and `only-new-issues` lint stays quiet. Candidates: - `internal/service/backup_service.go` (~2.2k) — separate engine-specific serialization from restore/backup orchestration. - `internal/handler/scheduling_handler.go` (~1.8k, also a `gocyclo` offender) — split into `scheduling_sessions_handler.go` / `scheduling_reservations_handler.go` / `scheduling_templates_handler.go`. - `internal/service/data_quality_service.go` (~1.5k) — one file per check family, or a small check-interface + registry so each rule is independently testable. - *Note: `internal/repository/migrations.go` (~3.8k) is intentionally append-only/sequential — low value to split; leave it.* *Effort: medium, naturally incremental. Risk: low as mechanical extractions with tests green.* - [x] Improve error handling consistency across handlers (centralized in internal/handler/errors.go) - [x] Add structured logging throughout the codebase (JSON format support in pkg/logger) - [x] Review and optimize database queries with EXPLAIN (audit_logs indexes, N+1 fixes) --- ## Dependency Upgrade Watch ### Vuetify 4 Migration — Watch & Wait **Current:** Vuetify `^3.12.1` (pinned after accidental bump to 4.0.0 in Dependabot commit `039084d`) **Trigger conditions** — upgrade when ANY of these are true: - Vuetify 4.1.x or later is released (indicates post-launch stabilization) - Vuetify 3.x enters security-only or end-of-life maintenance - A feature we need is only available in Vuetify 4 **Watch:** - Vuetify GitHub releases: `https://github.com/vuetifyjs/vuetify/releases` - Vuetify 3 EOL announcement (none as of 2026-04-03) **Known breaking changes for this app** (catalogued 2026-04-03): | Area | Change | Fix Required | |------|--------|-------------| | CSS cascade | All Vuetify 4 CSS is in `@layer vuetify-components` — unlayered app CSS wins | Wrap `main.css` reset in `@layer reset { }` and remove `p, span, div { font-size: 14px }` from App.vue | | `v-main` padding | CSS reset `* { padding: 0 }` kills layout top/bottom padding | Keep existing `paddingTop`/`paddingBottom` in `mainStyle` (already fixed) | | `fill-height` | No longer sets `display: flex` or `align-items: center` — only `height: 100%` | Add `d-flex align-center` to 47 views using `v-container class="fill-height"` | | `app` prop | Removed from `v-app-bar`, `v-bottom-navigation` — layout registration is now automatic | Remove `app` prop from both (harmless but dead code) | | `v-bottom-navigation` | `v-model` controls selected tab only; `active` prop controls visibility separately | Audit any code that passed `v-model` expecting visibility control | **Full plan:** See memory file `vuetify4-upgrade-plan.md` --- *This file is maintained by Claude Code. See CHANGELOG.md for complete release history.*