# Changelog All notable changes to ActaLog will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [1.3.8] - 2026-10-02 — Health probe fix; Go 1.26 and security updates ### Fixed - **The container readiness probe could never succeed, and it killed the healthy app when it failed — crash-looping both deployments for 9 days.** `docker/scripts/entrypoint.sh` polled `http://localhost:8080/health`. Two defects: - **`localhost` vs IPv4.** On hosts where `localhost` resolves to `::1` first, wget connects to `[::1]` while the server binds IPv4 only (`SERVER_HOST` defaults to `0.0.0.0` and is commonly set to `127.0.0.1`), so the probe was refused every time. Verified against a live, working instance: `localhost:8081` → `Connection refused`, `127.0.0.1:8081` → `{"status":"healthy"}`. - **Hardcoded port 8080.** `SERVER_PORT` was ignored, so a beta instance on 8081 probed the *production* instance on 8080 instead of itself. Both now use `http://127.0.0.1:${SERVER_PORT:-8080}/health`. The same two fixes are applied to the Dockerfile `HEALTHCHECK` (kept in shell form so `${SERVER_PORT}` expands at runtime). - **The readiness probe no longer kills the application.** On timeout the entrypoint now logs a warning, skips the seed import (which drives the HTTP API and cannot work while the app is unreachable), and hands off to `wait $APP_PID`. Previously it ran `kill $APP_PID; exit 1`, which combined with `restart: unless-stopped` turned any probe defect into a permanent crash-loop — 25,946 restarts on prod and 26,413 on beta, with zero successful readiness checks, starting at the 2026-07-20 deploy. This poll only ever gated the optional seed import; it was never a liveness supervisor. A genuinely dead process is still caught by the in-loop `kill -0` check (exit 1), and Docker's `HEALTHCHECK` remains the health signal. ### Operations - Deploy-time verification should probe from **inside** the container (`docker exec wget -q -O- http://127.0.0.1:$SERVER_PORT/health`), not with `curl` from the host. Host-side `curl` resolves `localhost` to `127.0.0.1` and reported healthy throughout, which is why this stayed hidden for 9 days. ### Security - **Go 1.26.8** (was 1.25.12, now out of support), in `go.mod` and the Docker builder image. `govulncheck` was failing CI on reachable standard-library vulnerabilities (`crypto/tls`, `html/template`, `encoding/asn1`) and on `golang.org/x/text`; it now reports none. - Web dependencies: `npm audit` went from 14 vulnerabilities (9 high) to 0. sharp 0.35.4 (libvips CVEs), vitest 4.1.11 (GHSA-82fw-gwwq-j7x9), and the exact axios pin moved from 1.18.1 to 1.20.0 (prototype-pollution advisory). - Runtime base image moved to the current Alpine 3.24.2 digest: OpenSSL 3.5.8 (CVE-2026-14456, high, denial of service). Trivy image scan: 0 high/critical. ### Dependencies - All open Dependabot updates, with `go.sum` and `package-lock.json` regenerated once: pgx 5.11.0, golang.org/x/crypto 0.57.0, go-sqlite3 1.14.52, mysql driver 1.10.1, chi 5.3.2; the web dev-dependencies group, the Vue ecosystem group (including pinia 4), dompurify 3.4.12, marked 18.0.6, vuetify 4.1.5; and the actions/checkout, actions/setup-python and lychee-action updates. ## [1.3.7] - 2026-07-19 — Notes field fix + faster CI ### Fixed - **Log Workout "Notes" fields: the field label overlapped the placeholder hint.** The per-movement and per-WOD Notes textareas set both a floating `label="Notes"` and a `placeholder`; in the compact solo textarea (Vuetify 4) the floated label rendered on top of the placeholder text. Dropped the redundant label; the field now shows a single "Notes — how did this feel?" placeholder. ### CI - Build the release image for **linux/amd64 only** (dropped the arm64 QEMU leg, which pushed builds to ~20min); no arm64 deploy target exists. ## [1.3.6] - 2026-07-19 — Vuetify 4 UI polish (readability & spacing) Follow-up readability/spacing fixes on the v1.3.5 Vuetify 4 build, all found while testing on beta. All are global (theme-token based) so they apply everywhere. ### Fixed - **Entry-field text was too small to read while typing.** Vuetify 4 renders the actual `.v-field__input` at ~14px (smaller under `density="compact"`, of which the app has 342 across 54 files); setting font-size on `.v-field` never reached the input. Pinned `.v-field .v-field__input` to 16px (also avoids iOS tap-zoom). - **Low-emphasis text was too light to read.** `text-medium-emphasis` rendered at 0.6 alpha (~#6b6b6b); darkened to 0.82 app-wide. - **Card count chips were nearly invisible.** `` sets the *text* to near-white under v4's tonal variant; replaced with `variant="tonal"` (readable on-surface text) in WorkoutsView, WODsView, WorkoutTimelineView. - **Text buttons had no horizontal padding.** Labels sat flush to the button edges; restored Vuetify's per-size inline padding (icon buttons stay square). - **Tooltips were cramped;** bumped padding from 5px/16px to 8px/14px. ## [1.3.5] - 2026-07-19 — Vuetify 4 migration completed + UI refresh Completes the Vuetify 3 → 4 migration that v1.3.3's dependency sweep began but never finished (the un-migrated framework bump silently broke component styling app-wide; production was interim-pinned to v1.3.0). The app now renders correctly on Vuetify 4 and ships an approved visual refresh. ### Fixed — Vuetify 4 rendering (the v1.3.3/v1.3.4 regression) - **`web/src/assets/vuetify3-compat.css`** restores the Material Design 2 look on Vuetify 4: solo-field elevation, MD2 type scale, container centering/width, list-item/chip padding, font-weight utilities (`font-weight-bold` was rendering at 400 app-wide), and app-bar edge padding. Computed styles match v1.3.0 to sub-pixel across sampled components. - **`web/src/assets/vuetify3-spacing.css`** re-asserts the 4px-base spacing utilities (`pa-6`, `mb-4`, …), which Vuetify 4 ships inside `@layer` where they lost to unlayered rules and silently collapsed padding everywhere. ### Added — approved UI refresh (design layers) - **`redesign.css`**: 12px card corners with hairline border + soft shadow, bordered inputs with teal focus ring, outlined toggle chips with filled selected state, brand-teal bottom-nav active pill (fixed-size, centered, FAB excluded), list hover feedback, visible keyboard focus. - **`redesign-plus.css`**: firmer 600-weight titles with tighter tracking, tabular stat numerals, legible bottom-nav labels, brand-teal FAB, token-based gradient CTAs, hover lift on interactive cards, app-wide bolder icon strokes. - Light theme's `background` token is now `#f4f6f9` (off-white ground) so white surfaces read as cards; all seven themes (light/dark/brutalist/ocean/sunset/ sunrise/myst) verified — every accent is theme-token based. - Typography changes are family-agnostic: the user font picker (incl. OpenDyslexic / Atkinson Hyperlegible) is untouched. ### Removed - Dead CSP-blocked jsdelivr `@mdi/font` CDN `` (icons are bundled locally); this also clears the console CSP error on every page. ### Security — Go stdlib patch - Go `1.25.11 → 1.25.12` for **GO-2026-5856** (crypto/tls ECH privacy leak, reachable) and **CVE-2026-39822** (os.Root symlink traversal) — both flagged by the govulncheck/Trivy gates, which block releases until patched. ### Docs - `docs/plans/vuetify-4-migration-plan.md`: scope, root-cause analysis, and the executed fast path. ## [1.3.4] - 2026-07-04 — CI & supply-chain hardening Build/CI hardening release. No application behavior changes — no runtime code was touched. ### Security — Go stdlib patch (caught by the new gate) - Bumped the Go directive `1.25.0 → 1.25.11` to pick up the fix for **GO-2026-5039** (unescaped input in `net/textproto` error strings), which the new `govulncheck` gate flagged as reachable from the SMTP, import, and admin-user code paths. This finding was previously invisible because there was no vulnerability scanning in CI. ### Added — CI security gates - **`govulncheck`** (Go, pinned `v1.1.4`) runs on every push/PR and **fails** the build on known vulnerabilities in Go dependencies or reachable code. - **`npm audit --audit-level=high`** on the web build **fails** on high/critical advisories in frontend dependencies. - **Trivy image scan** (pinned by digest) in `docker-build.yml`: builds a single-arch image, scans it, and **blocks the push** on fixable HIGH/CRITICAL CVEs (`--ignore-unfixed`) before anything reaches ghcr.io. ### Fixed — golangci-lint config was silently broken - `.golangci.yml` declared `version: "2"` but still used v1 keys (`linters-settings`, `issues.exclude-rules`), so `golangci-lint config verify` failed — and the failure was hidden by `continue-on-error`. Migrated to valid v2 schema (`linters.settings`, `linters.exclusions.rules`); the exclusion rules now actually apply (findings dropped from ~1,800 to ~605). ### Changed — Lint is now enforcing - `golangci-lint` is no longer advisory (`continue-on-error` removed). It runs with **`only-new-issues: true`**, so it fails on lint regressions introduced by a change while grandfathering the ~605 pre-existing findings (tracked in `docs/MATURITY_ASSESSMENT.md`). ### Security — Supply-chain pinning - **All GitHub Actions pinned to commit SHAs** (with a version comment) across every workflow, so a moved/compromised tag can't silently change CI behavior. Dependabot continues to update them. - **Docker base images pinned by digest** — `node:24-alpine`, `golang:1.25-alpine`, and the `alpine` runtime now reference immutable `@sha256:…` digests instead of floating tags. ### Docs - Refreshed `docs/MATURITY_ASSESSMENT.md` with a v1.3.3 remediation-status section (base assessment was v1.2.1). - Updated `docs/ROADMAP.md` current version and recent-release summaries. ## [1.3.3] - 2026-07-04 — Maintenance: dependency & toolchain updates Maintenance release. No application behavior changes — dependency, toolchain, and CI hardening only. All 23 changes since v1.3.2 are dependency or build-tooling bumps. ### Changed — Backend (Go) dependencies - `golang.org/x/crypto` 0.50.0 → 0.53.0 - `github.com/mattn/go-sqlite3` 1.14.42 → 1.14.47 - `github.com/jackc/pgx/v5` 5.9.2 → 5.10.0 - `github.com/go-chi/chi/v5` 5.2.5 → 5.3.0 - `github.com/go-sql-driver/mysql` 1.9.3 → 1.10.0 ### Changed — Frontend (web) dependencies - `vite` 7.3.1 → 8.0.11 - `vuetify` (bump) - `axios` 1.13.5 → 1.18.1 - `marked` 17.0.6 → 18.0.5 - `jsdom` 28.1.0 → 29.1.1 - `dompurify` 3.3.3 → 3.4.2 - `sharp` (bump) - `eslint` 9.39.2 → 10.6.0, `prettier` 3.8.3 → 3.9.3 (dev) ### Changed — Toolchain & CI - Upgraded the web build to **Node 24** and pinned the npm toolchain (`packageManager: npm@11.16.0`) - Bumped GitHub Actions: `actions/checkout` 6→7, `actions/cache` 5→6, `actions/upload-pages-artifact` 4→5, `actions/github-script` 8→9, `docker/build-push-action` 6→7, `golangci/golangci-lint-action` 6→9 ### Fixed — CI lockfile stability - Pinned npm to **11.16.0** in CI (`ci.yml`) and the Docker frontend build stage so it matches the version that generates `web/package-lock.json`. `setup-node`'s bundled npm floats with the Node 24.x patch line, and a newer npm reshapes the rolldown wasm-fallback `@emnapi` optional deps, which was breaking `npm ci` on dependency-update PRs. ## [1.3.2] - 2026-05-07 — Admin user lifecycle + protected-user break-glass CLI ### Added — Operator break-glass CLI - **`actalog admin force-edit-protected`** — operator escape hatch for editing protected accounts when admin paths are unavailable. Five fields: `password | email | name | role | account_disabled`. Per-field audit events with operator metadata (USER, hostname, tty, cwd) for forensics - Identity-field changes (`email | name | role | account_disabled`) briefly drop both L3 protected-user triggers, perform the UPDATE, then unconditionally reinstall + re-run the boot invariant. Reinstall failure panics with a recovery message — partial trigger state is worse than a hard exit - Password reads from stdin (no shell-history exposure); identity changes additionally require typing `BREAK-GLASS` to proceed - **Five new audit events**: `protected_user_break_glass_password`, `protected_user_break_glass_email`, `protected_user_break_glass_name`, `protected_user_break_glass_role`, `protected_user_break_glass_account_disabled` — per-field rather than one event with a discriminator, so alert routing keys off the event type alone ### Added — Admin user lifecycle (originally targeted v1.3.1) - **`POST /api/admin/users`** — admins can create user accounts with email + password + role; new user can sign in immediately - **`POST /api/admin/users/{id}/password`** — admin sets a specific password directly; bundles lockout-clear + refresh-token revocation in one operation; protected accounts blocked at L1 + L2 - **AdminUserCreateDialog** on the User Management screen — modal with email/password/name/role/email-verified inputs - **AdminSetPasswordDialog** on the Profile tab Password Management card — sits alongside the existing Force Password Reset button with explanatory copy distinguishing the two - **`usePasswordInputs`** composable — shared password+confirm state with show/hide toggle, complexity hint, matching validation; used by both new dialogs - **Three additional audit events**: `admin_user_created`, `admin_password_set` (with prior failed-attempts/lockout state captured for forensics), `admin_user_create_rejected_protected` ### Security - Break-glass CLI bypass is documented as accepted residual risk in `docs/security/THREAT_MODEL.md`: shell access on the application host already implies DB-credential access; the CLI is the audited pathway for that existing capability - Protected emails are rejected at create with their own audit event — distinct from the `protected_user_attack_*` family which targets modifications of existing protected rows - L1 `ProtectedUserGuard` covers the new set-password endpoint automatically (inside the `/users/{id}` sub-router) - L2 service-layer `ensureNotProtected` defensive check on `SetPassword` matches the pattern used by `UpdateProfile` / `ForcePasswordReset` - Password complexity policy unchanged (12+ chars, upper, lower, digit) — single source of truth across self-service, admin-set, and break-glass paths ### Documentation - `docs/security/PROTECTED_USERS.md` — new "Break-glass CLI" subsection covering when to use, what it does, and audit forensics - `docs/security/PROTECTED_USERS_RECOVERY.md` — points the 3-AM playbook at the CLI as the primary recovery path - `docs/security/THREAT_MODEL.md` — admin-compromise + shell-access residual-risk rows - `docs/USER_PERMISSIONS.md` — new endpoints + UI surfaces + operator CLI --- ## [1.3.0] - 2026-05-03 — Admin user-edit screen + protected-user defense-in-depth ### Added - **Admin User Edit Screen** at `/admin/users/:id/edit` — tabbed view for editing per-user attributes. v1.3.0 ships the **Profile** tab with name/email/birthday/email-verified field editing, optimistic-concurrency via `updated_at`, and a force-password-reset action that sends a reset email and revokes refresh tokens. Future tabs (Affiliations, Subscriptions, Credits, Preferences, Activity) shown as disabled with version chips. - `PATCH /api/admin/users/{id}` — partial profile update with `updated_at` precondition; returns 409 on stale `updated_at` - `POST /api/admin/users/{id}/force-password-reset` — sends password-reset email + revokes all refresh tokens - Edit pencil-icon button in `AdminUsersView` (disabled for protected users) ### Security — Protected User System (defense-in-depth) A four-layer defense for system-reserved accounts (currently `br8kwall@gmail.com`): - **L1 — HTTP middleware** (`pkg/middleware/protected_user.go`): refuses non-GET writes under `/api/admin/users/{id}` with structured 403 + `protected_user_attack_http` audit event - **L2 — Service guard** (`internal/service/admin_user_service.go`): catches in-process callers (cron, internal APIs) that bypass HTTP. Fires `protected_user_attack_service` audit event - **L3 — Database trigger** (migration 0.35.0, per-dialect SQL for sqlite3/postgres/mysql): `BEFORE UPDATE` blocks identity-field changes only (`email`, `name`, `role`, `account_disabled`); `BEFORE DELETE` blocks unconditionally. Lifecycle writes (password_hash, last_login_at, email_verified, verification_token, ...) pass through so the protected user can register, log in, and rotate their own password — L1 and L2 remain the primary defenses against admin-screen tampering. Mixed identity+lifecycle UPDATEs are still blocked. See `docs/security/PROTECTED_USERS.md` §3.4 for the full contract - **L4 — Audit log tagging** (`internal/domain/audit_log.go`): single event per attempt, tagged at the rejecting layer - **Boot-time invariant**: three sub-checks (triggers exist, triggers fire, protected rows present). Fails closed on hard failure; soft-warn on fresh installs - **`ACTALOG_SKIP_PROTECTED_INVARIANT=true`** env var: degraded-mode escape hatch. `/health` returns 503; admin user-write endpoints return 503; ERROR-level heartbeat every 60s for alerting - **Admin CLI**: `actalog admin verify-protected-users [--verbose]` (read-only diagnostic) and `actalog admin reapply-protected-migrations --confirm` (idempotent recovery) - **Recovery scripts**: `scripts/recover/restore-protected-triggers.sh` + per-dialect SQL files for last-resort recovery when the binary itself is unrunnable ### Documentation - `docs/security/PROTECTED_USERS.md` — master runbook: purpose, threat model, architecture, list management, verification, recovery, audit forensics, degraded mode - `docs/security/PROTECTED_USERS_RECOVERY.md` — focused 3-AM-incident playbook - `docs/security/THREAT_MODEL.md` — app-wide threat model linking each section to its implementation - `docs/superpowers/specs/2026-04-28-admin-user-edit-design.md` and `docs/superpowers/plans/2026-04-28-admin-user-edit-v1.3.0-plan.md` capture the design and implementation history ### CI - Generator drift check: `go run ./cmd/gen-protected-emails/` + `git diff --exit-code` keeps Go source ↔ frontend JS in sync - Lockstep check: migration SQL ↔ standalone recovery scripts can't drift - Doc code-block lint: `bash -n` validates every shell command in security runbooks - CODEOWNERS: security-critical paths (`pkg/security/`, migrations, security docs, recovery scripts) require explicit review ### Maintenance - Migration 0.35.0 is additive (no schema changes, just triggers); existing v1.2.x deployments upgrade by applying the migration - v1.2.x rollback is safe: triggers stay in the database, security stays on even if the binary rolls back ### Carried into next releases - v1.3.1: Affiliations tab (gym memberships, coach assignments per gym) - v1.3.2: Subscriptions, Credits & Documents, Preferences, Activity & Audit tabs --- ## [1.2.4] - 2026-04-28 — Security hardening, part two Closes the two items deferred from v1.2.3 (`docs/plans/SECURITY_HARDENING_PLAN.md` Steps 2 and 5). ### Security - **Security response headers middleware** — new `pkg/middleware/SecurityHeaders` sets `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, `Referrer-Policy: strict-origin-when-cross-origin`, `Strict-Transport-Security: max-age=31536000; includeSubDomains`, and a project-tuned `Content-Security-Policy` on every response. Wired in `cmd/actalog/main.go` after the CORS middleware so it applies to API, static assets, and `/health`. CSP allows `'unsafe-inline'` for *styles* (Vuetify dynamic theme injection requires it) but keeps scripts strict (`script-src 'self'` only) - **Avatar upload magic-byte validation** — `internal/handler/user_handler.go` no longer trusts the client-supplied `Content-Type` header. The first 512 bytes of the uploaded file are read and passed to `http.DetectContentType` (WHATWG MIME Sniffing); the file pointer is then rewound for the subsequent copy. A filename-extension allowlist (`.jpg/.jpeg/.png/.gif/.webp`) closes the residual stored-XSS path where image magic bytes could be uploaded under a `.html` filename and later served with a `text/html` content-type by the static file handler - New negative tests cover the spoofed-Content-Type and disallowed-extension cases ### CI - **CI Failure Notify workflow now deduplicates and auto-closes.** Previously every CI failure (including each Dependabot rebase) opened a fresh `[CI] Workflow failure: ...` issue; old issues never closed. The workflow now (a) re-uses an existing tracking issue with the same `(workflow, branch)` title instead of spawning duplicates, and (b) on the next *successful* CI run for the same branch, closes the tracking issue with a comment linking the green run. Switched from `peter-evans/create-issue-from-file` to `actions/github-script` to access the issue list/update REST endpoints ### Maintenance - Eight Dependabot bumps merged: actions/deploy-pages 4→5, docker/setup-buildx-action 3→4, lib/pq 1.12.1→1.12.3, x/crypto 0.49.0→0.50.0, pgx 5.9.1→5.9.2, vue-ecosystem group, go-sqlite3 1.14.38→1.14.42, dev-dependencies group (8 npm updates) - Two Dependabot PRs closed with policy comments: Vuetify 4.0.5 (held by watch-and-wait policy until 4.1.x), axios 1.14.0 (post supply-chain compromise; close-and-wait until npm reissues clean 1.14.x or 1.15.x ships) --- ## [1.2.3] - 2026-04-03 — Security hardening release ### Security - **Password policy** — raised minimum from 8 to 12 characters; now requires at least one uppercase letter, one lowercase letter, and one digit. Enforced in registration, password reset, and password change flows (`internal/service/user_service.go`). UI hints and client-side length checks updated in RegisterView, SettingsView, ResetPasswordView, and AdminUserImportExportView - **CORS allowlist enforcement** — `pkg/middleware/cors.go` previously echoed the request's `Origin` back as `Access-Control-Allow-Origin` for both allowed and disallowed origins, making the `CORS_ORIGINS` allowlist inert. Disallowed origins now receive no `Access-Control-Allow-Origin` header (browser default-deny). Test in `cors_test.go` strengthened to assert header absence - **Error sanitisation** — `WriteError()` no longer forwards raw internal error strings to HTTP responses; unknown errors return a generic message (`internal/handler/errors.go`) - **XSS prevention** — DOMPurify 3.3.3 added to `MarkdownRenderer.vue`; all `v-html` output is sanitized before DOM insertion - **serialize-javascript** — pinned to 7.0.5 via `package.json` overrides, fixing RCE (GHSA-5c6j-r48x-rmvq) and CPU exhaustion DoS (GHSA-qj8w-gfj5-8c6v) in the `vite-plugin-pwa → workbox-build → @rollup/plugin-terser` chain - **Rate limiter IP extraction** — `X-Forwarded-For` header now correctly takes the leftmost (original client) IP from comma-separated lists; `RemoteAddr` port suffix stripped to prevent per-reconnect bucket bypass - **Audit logging** — `rate_limit_exceeded` events now emitted via `OnExceeded` callback on both auth and password-reset rate limiters ### Added - Admin organizations list shows a member count column (`LEFT JOIN user_organizations` in `OrganizationRepository.List`) - Edit-from-list action in admin organizations view (reuses existing `PUT /api/admin/organizations/{id}`) ### Documentation - `docs/OWASP_AUDIT_2026-04-03.md` — OWASP Top-10 audit findings - `docs/MATURITY_ASSESSMENT.md` — Trail of Bits 9-category scorecard - `docs/plans/SECURITY_HARDENING_PLAN.md` — phased remediation plan (Steps 2 and 5 carried into backlog) ### Maintenance - golangci-lint upgraded from v1.64.8 to v2.11.4; config migrated to v2 format (`version: "2"`) - Frontend unit tests added to CI pipeline (`web-test` job in `.github/workflows/ci.yml`); 11 new Vitest suites covering App shell, auth store, axios interceptor, and 8 admin views ### Known gaps (deferred to a future release — tracked in TODO.md) - Security response headers middleware (CSP, HSTS, X-Frame-Options) - Avatar upload still trusts client `Content-Type` header rather than detecting magic bytes --- ## [1.2.1] - 2026-04-01 ### Added - Calendar header now displays workout count for the viewed month ### Fixed - Calendar view now fetches all workouts instead of defaulting to 20 (fixes missing entries for active users) - Admin breadcrumb link returning 404 - Avatar upload click target too small; removed stale debug logging ### Changed - Nav bar icons switched to heavier filled MDI variants for improved visual weight ### Security - Pinned axios to `1.13.5` across frontend to prevent auto-upgrade into compromised versions 1.14.1 / 0.30.4 (supply chain attack via hijacked npm account, 2026-03-31) - `npm audit fix`: patched brace-expansion (ReDoS), picomatch (method injection / ReDoS), undici (WebSocket memory/smuggling), yaml (stack overflow) - Updated Go deps: `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 ### Maintenance - CI: `setup-go` now uses `go-version-file: go.mod` so toolchain tracks the module automatically - CI: pinned `golangci-lint-action` to v6 (v9 dropped golangci-lint v1.x support) - Fixed date-sensitive test `TestUserWorkoutRepository_GetActiveUsersThisMonth` (failed on first day of each month) - Updated GitHub Actions: `docker/login-action` 3→4, `docker/metadata-action` 5→6, `docker/build-push-action` 6→7, `docker/setup-buildx-action` 3→4, `actions/checkout` 4→6, `github/super-linter` 4→7 - Updated frontend deps: Vue 3.5.28→3.5.31, vue-router 5.0.3→5.0.4, vitest 4.0.18→4.1.0, sass 1.97→1.98, marked 17.0.1→17.0.3 --- ## [1.2.0-beta] - 2026-02-19 ### Added - Configurable Beta Logo - **Environment-Variable-Driven Logo Switching** - New `LOGO_VARIANT` environment variable (`"logo"` default, `"betalogo"` for red beta logo) - Backend: `LogoVariant` field in `AppConfig`, exposed via `/api/version` response - Frontend: Auth store fetches variant, computes `logoPath`, dynamically updates favicon and apple-touch-icon - All three logo locations updated (App.vue header, LoginView, RegisterView) - Full beta icon asset set generated from `betalogo.svg` (SVG, 12 PNGs, favicon.ico, 6 apple-touch-icons) - Example `.env` files updated with `LOGO_VARIANT` documentation ### Added - PR Leaderboards & Consistency Achievements - **Leaderboard search API response parsing fix and header nav icon** ## [1.1.0-beta] ### Added - Coach Role & Role Rename - **Three-Tier Role System** - Renamed `"user"` role to `"athlete"` across backend, frontend, and tests - Added `"coach"` as a new middle-tier role: athlete < coach < admin - Database migration (0.32.0) renames existing `user` records to `athlete` - **CoachOrAdmin Middleware** - New `CoachOrAdmin` middleware in `pkg/middleware/auth.go` for coach-accessible routes - Coaches bypass subscription checks (same as admins) in `RequireActiveSubscription` - 14 comprehensive middleware tests covering all role permutations - **Dedicated Coach API Routes** - `GET /api/coaches/me/sessions` - Coach's upcoming sessions (admins see all sessions across all gyms) - `GET /api/coaches/sessions/{id}/roster` - Session roster - `POST /api/coaches/sessions/{id}/check-in/{rid}` - Check in athlete - `POST /api/coaches/sessions/{id}/no-show/{rid}` - Mark no-show - `POST /api/coaches/sessions/{id}/complete` - Complete session - Organization-level access verification for coach actions - **Frontend Updates** - Coach nav button in bottom navigation (visible for coach/admin when scheduling enabled) - Coach Dashboard updated to use `/api/coaches/` routes instead of admin routes - Admin Users panel shows three role options: Athlete, Coach, Admin - Router guard for `requiresCoach` meta on coach routes - **Admin All-Sessions Visibility** - Admins see ALL upcoming sessions on Coach Dashboard (not limited by coach assignments) - New `GetAllUpcoming` repository method and `GetAllUpcomingSessions` service method ### Added - Delete Class with Sessions - **Enhanced Class Template Deletion** - Three delete modes via `?mode=` query parameter: - `template_only` (default): Delete template only, sessions become orphaned - `with_future_sessions`: Delete template and future sessions, preserve past sessions - `with_all_sessions`: Delete template and all sessions (past and future) - Cascade deletion of related data (coaches, reservations, waitlist, notifications) - Credit refunds for unconfirmed reservations (status != checked_in/attended) - User notifications for cancelled sessions with session details - **New UI Delete Dialog** - Radio button selection for delete mode - Session counts displayed for each option - Warning about cascading deletes - Information about notifications and credit refunds - **API Enhancement** - `DELETE /api/admin/scheduling/templates/{id}?mode=` - Response includes: `sessions_deleted`, `notifications_sent`, `credits_refunded` - **Repository Methods** - `GetSessionIDsByTemplateID`, `GetFutureSessionIDsByTemplateID`, `DeleteByIDs` on ClassSessionRepository - `DeleteBySessionIDs` on SessionCoachRepository, ReservationRepository, WaitlistRepository - `GetBySessionIDs` on ReservationRepository - `RefundCredit` on UserClassCreditsRepository - **Tested on:** SQLite, MariaDB (192.168.1.234), PostgreSQL (192.168.1.143) ### Added - Class Scheduling System (Phase 4 Complete) - **Documents Management** - Gym-specific document types (waivers, liability forms, health forms) - Track required vs optional documents per organization - Document expiration support with configurable validity periods - Admin CRUD for document types - **User Documents Tracking** - Per-user document completion status (pending, completed, expired) - Expiration date tracking for time-limited documents - User view of pending/completed documents - Admin can mark documents as completed - **Class Packages (Credit System)** - Flexible credit packages (e.g., "10-Class Pack", "Monthly Unlimited") - Configurable credits per package with validity periods - Price tracking for package purchases - Active/inactive package status - **User Credits** - Credit balance tracking per user per organization - Credits automatically populated from package when purchasing - Expiration tracking for time-limited credit packages - Available credits calculation excluding expired records - **Waitlist System** - Join waitlist when class is full - Automatic position tracking - Leave waitlist functionality - Waitlist status indicators (waiting, promoted, expired, cancelled) - **Class Notifications** - Foundation for class reminders and waitlist promotions - Notification types: reminder, waitlist_promoted, class_cancelled, class_updated - **Frontend Views** - `MyCreditsView.vue` - User's credits, documents, and waitlist entries - `AdminPackagesView.vue` - Admin management with 3 tabs (Packages, Documents, User Credits) - `ScheduleView.vue` - Added waitlist join/leave buttons and position indicators - **API Endpoints (Phase 4)** - `GET/POST/PUT/DELETE /api/admin/gyms/{id}/documents` - Document type management - `GET/POST/PUT/DELETE /api/admin/gyms/{id}/packages` - Package management - `POST /api/admin/gyms/{id}/users/{id}/credits` - Add credits to user - `GET /api/gyms/{id}/users/me/credits` - Get user's credit balance - `GET /api/gyms/{id}/users/me/documents` - Get user's document status - `POST/DELETE /api/sessions/{id}/waitlist` - Join/leave waitlist - `GET /api/users/me/waitlist` - Get user's waitlist entries - **Database Migration (0.27.0)** - `documents` - Document types per organization - `user_documents` - User document completion tracking - `class_packages` - Credit package definitions - `user_class_credits` - User credit balances - `waitlist_entries` - Session waitlist queue - `class_notifications` - Class-related notifications ### Fixed - **PurchaseCredits Bug** - Now correctly uses package credits when `package_id` is provided without explicit `credits` value ### Added - Workout Template Instructions Field - **Instructions Field for Template Movements** - New `instructions` column on `workout_template_movements` table - Supports markdown-formatted coaching cues, setup notes, and technique reminders - Optional field - movements work without instructions - Preserved through full CRUD lifecycle - **Instructions Field for Template WODs** - New `instructions` column on `workout_template_wods` table - Allows WOD-specific scaling options, standards, and modifications - Consistent behavior with movement instructions - **Frontend Updates** - Instructions textarea in `WorkoutTemplateEditView.vue` for both movements and WODs - Instructions display in `WorkoutTemplateDetailDialog.vue` with markdown rendering - Collapsible sections for cleaner UI when instructions are present - **Backend Updates** - Domain models updated with Instructions field - Repository queries updated to include instructions in all operations - Handler validation for instructions field - **Comprehensive Test Coverage** - Backend unit tests for service and handler layers - Frontend unit tests in `WorkoutTemplateEditView.test.js` (573 lines) - Integration tests in `workout_template_test.go` covering: - Full CRUD lifecycle for instructions - Special characters (markdown, unicode, HTML-like) - Multiple movements/WODs with different instructions - Optional field behavior (empty/null handling) ### Fixed - **Repository Query Bug** - Fixed `GetByIDWithDetails` in `workout_repository.go` to include `instructions` column in SELECT queries for both movements and WODs ## [0.24.0-beta] - 2026-01-14 ### Added - Data Quality & Duplicate Detection System - **Admin Data Quality Dashboard** - New `AdminDataQualityView.vue` with 3 tabs (Overview, Duplicates, Data Issues) - Full database scan with summary cards for duplicates and issues - Duplicates by entity type breakdown with clickable View buttons - Data quality checks display with icons, descriptions, and counts - Zero-state display with success checkmarks when no issues found - **Duplicate Detection Engine** - Scan 5 entity types: movements, WODs, user_workouts, users, workouts - Case-insensitive name matching for movements, WODs, workouts - Case-insensitive email matching for users - Composite key matching for user_workouts (user_id + date + name) - Shows duplicate group count and record count per entity type - FK reference counts displayed for informed merge decisions - **Duplicate Merge Functionality** - Preview merge operation showing FK impact before execution - Safe merge with FK updates in database transaction - Automatic child record handling (movements/WODs from duplicates) - Audit logging of all merge operations (`duplicate_merge` event type) - Per-entity type merge with keep/delete ID selection - **Data Quality Issue Detection** - 4 quality check types with severity levels: - Orphaned FK references (error) - FK pointing to deleted records - Empty required fields (error/warning) - Missing user names, movement names, WOD names - Future workout dates (warning) - Workouts scheduled in the future - Invalid email formats (warning) - Malformed email addresses - Filter chips for issue type filtering in Data Issues tab - Clickable cards to navigate from Overview to filtered issue lists - **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 quality issues - **Demo Mode Configuration** - Added DEMO MODE section to `.env.example` - Documented implemented vs planned demo features - Current workaround instructions for basic demo setup - Planned settings: DEMO_MODE, DEMO_USERS, DEMO_RESET_ON_STARTUP, etc. ### Added - Audit Logging Enhancements (2026-01-13) - **Password Change Audit Logging** - New `password_changed` event logged when users change their password - Captures user email in event details - Works for both browser and API password changes - **Password Reset Audit Logging** - New `password_reset` event logged when password is reset via token - Tracks which user completed the password reset - **User Deletion Audit Logging Fix** - Fixed `user_deleted` event to properly log admin deletions - Stores target user info (id, email, name) in details JSON - Handles FK constraint by using nil target_user_id (user already deleted) - **Duplicate Audit Log Bug Fix** - Fixed bug where SQLite/MySQL audit logs were being inserted twice - Repository Create() was calling both QueryRow and Exec for same INSERT - Now correctly uses Exec with LastInsertId for non-RETURNING databases ### Added - Admin Metrics Dashboard (2026-01-13) - **System Metrics Dashboard** - New `GET /api/admin/metrics` endpoint returning all dashboard metrics - Real-time statistics for admin users - Single API call for efficient frontend consumption - **User Statistics** - Total users count - Active users this month (users who logged workouts) - New users this month - Disabled users count - **Workout Statistics** - Total workouts logged across all users - Workouts logged this month - Average workouts per user - **Content Statistics** - Total movements (standard + user-created) - Total WODs (standard + user-created) - Total workout templates (standard + user-created) - Breakdown of user-created vs standard content - **Subscription Statistics** - Active subscriptions count - Expiring soon (within 7 days) - Expired subscriptions count - **System Health** - Recent audit events (24h) - Email success rate - Total emails sent - Failed emails count - **Workout Trends** - 30-day workout activity chart - Daily workout counts with Chart.js visualization - **Frontend Components** - `StatCard.vue` - Reusable stat card with icon, value, label, subtitle - `WorkoutTrendsChart.vue` - Bar chart for workout trends - `AdminMetricsDashboardView.vue` - Main dashboard view - Updated `AdminView.vue` with System Metrics card - **Backend Infrastructure** - Cross-database date helpers for SQLite/PostgreSQL/MySQL - New repository methods: `CountNewThisMonth()`, `CountDisabled()`, `CountActive()`, `CountExpired()`, `CountExpiringSoon()`, `GetWorkoutTrends()` - `AdminMetricsService` aggregating all metrics - `AdminMetricsHandler` for HTTP endpoint ### Added - User Import/Export System (2026-01-13) - **Bulk User Import from CSV** - New `POST /api/admin/user-management/import/preview` endpoint for CSV validation - New `POST /api/admin/user-management/import/confirm` endpoint to execute import - Two-phase import: preview with validation → confirm to create users - CSV format: `email,name,password` columns required - Duplicate email detection with skip option - Password validation (minimum 12 characters with complexity requirements) - All imported users get role `user` and permanent free subscription - Passwords hashed with bcrypt (cost 12) - **User Export to CSV** - New `GET /api/admin/user-management/export` endpoint - Downloads CSV with all user emails and names - Passwords NOT included for security - Can be used as template for bulk imports - **Batch Password Reset** - New `GET /api/admin/user-management/filter` endpoint for filtered user listing - New `POST /api/admin/user-management/batch-password-reset` endpoint - Filter users by name/email search and creation date range - Select multiple users and send password reset emails in bulk - Uses existing password reset token system (32-byte tokens, 1-hour expiry) - Maximum 100 users per batch for safety - **Frontend Components** - `AdminUserImportExportView.vue` - Tabbed interface for import/export/reset - Drag-and-drop CSV upload zone - Import preview table with validation status per row - User selection table with filters and pagination - Updated `AdminView.vue` with User Import/Export navigation card - New route `/admin/users/import-export` - **Backend Infrastructure** - `UserListFilter` type in domain layer for flexible querying - `ListWithFilter()` and `CountWithFilter()` repository methods - `UserImportService` with preview/confirm/export/filter/batch-reset methods - `UserImportHandler` with multipart form handling (max 10MB) - Automatic subscription creation for imported users - **Documentation** - Screenshots for all tabs (import, export, password reset, preview) - Updated admin README with User Import/Export section - API endpoint documentation with examples ## [0.22.0-beta] - 2026-01-09 ### Added - Benchmark API Endpoint - **Comprehensive Benchmark Endpoint** - New `POST /api/benchmark` endpoint for API performance testing - Exercises database, serialization, and business logic operations - Uses isolated `benchmark_data` table (no production data affected) - Auto-cleanup of benchmark data after each run - **Database Benchmarks** (9 operations) - Single insert, bulk insert (100 records) - Select by ID, select by key (index lookup) - List with pagination, filtered queries - Update and delete operations - User-scoped cleanup - **Serialization Benchmarks** (4 operations) - JSON marshal/unmarshal for small payloads (1 object) - JSON marshal/unmarshal for large payloads (100 objects) - **Business Logic Benchmarks** (5 operations) - 1RM calculations using prmath package (1000 iterations) - Intensity calculations (1000 iterations) - Input validation (100 iterations) - String operations (1000 iterations) - Date operations with timezone handling (1000 iterations) - **Concurrent Benchmarks** (3 operations, optional) - Parallel reads (10 goroutines) - Parallel writes (5 goroutines) - Mixed read/write operations (10 goroutines) - Enable with `?concurrent=true` query parameter - **Configurable Record Count** - New `records` query parameter for `/api/benchmark` endpoint - Default: 1,000 records, Maximum: 500,000 records - Example: `POST /api/benchmark?records=10000` - Scales database operations to stress-test the system - **Complex Benchmark Data** - Large text fields (5-10KB random text with paragraphs) - Nested JSON blobs (5-level deep structures with arrays) - UUID test keys for uniqueness - Random numeric values (floats, integers, booleans) - Realistic data to push serialization and storage - **Supporting Endpoints** - `GET /api/benchmark/status` - Quick status check - `DELETE /api/admin/benchmark/data` - Admin cleanup of all benchmark data ### Added - PWA 1.2.0 Features - **Improved Update Flow** - Changed from `autoUpdate` to `prompt` registerType - User-controlled updates via UpdatePrompt component - Better state management in PWA store - **PWA Assets Generator** - New `pwa-assets.config.js` for automatic icon generation - Generate all icons from single source image - New npm script: `npm run generate-pwa-icons` - **Enhanced Caching** - Added caching for local fonts (1 year expiration) - Added caching for uploaded images (7 days, StaleWhileRevalidate) - Extended glob patterns for font files (woff, ttf) ### Changed - **Database Migration 0.22.0** - Added `benchmark_data` table for safe read/write testing - Indexes on `test_key` and `created_by` columns - Foreign key to users table with CASCADE delete - **Server Timeout Defaults** - Updated default SERVER_READ_TIMEOUT from 15s to 30s - Updated default SERVER_WRITE_TIMEOUT from 15s to 60s - Supports long-running benchmark API requests without EOF errors ### Fixed - **EOF Errors on Long-Running Benchmark Requests** - Fixed HTTP client receiving EOF when benchmark takes >15 seconds - Root cause: SERVER_WRITE_TIMEOUT was set too low for large record counts - Added explicit Content-Length header to avoid chunked encoding issues - For 100k+ records, recommend SERVER_WRITE_TIMEOUT=120s or higher ## [0.21.0-beta] - 2026-01-09 ### Added - Frontend Testing Framework - **Vitest Testing Setup** - Installed Vitest with Vue Test Utils, jsdom, and v8 coverage - Created `vitest.config.js` with Vue/Vuetify support - Added test setup file with jsdom mocks (ResizeObserver, matchMedia, IntersectionObserver) - New npm scripts: `test`, `test:run`, `test:coverage` - **Example Tests** - `src/utils/timezone.test.js` - 20 tests for timezone utilities - `src/components/UserAvatar.test.js` - 11 tests for component rendering ### Fixed - CI/CD and Code Quality - **Linting Issues Resolved** - Fixed gofmt formatting across all Go files - Updated `.golangci.yml` with relaxed thresholds for complex query builders - Added `font_family` column to base database schema for all drivers ### Updated - Dependencies - **Go Dependencies** - `github.com/jackc/pgx/v5` 5.7.4 → 5.8.0 - `github.com/mattn/go-sqlite3` 1.14.32 → 1.14.33 - **Frontend Dependencies** - `vuetify` 3.10.11 → 3.11.6 - `eslint-plugin-vue` 9.33.0 → 10.6.2 - `vite-plugin-pwa` 0.21.2 → 1.2.0 - Updated dev-dependencies group (4 packages) ## [0.20.0-beta] - 2026-01-08 ### Changed - UI Visual Refresh - **Form Input Style Update** - Changed default form input variant from `outlined` to `solo` (filled background, no border) - Cleaner, more modern appearance for text fields, selects, textareas, autocomplete, and combobox - Updated 43 Vue files to remove explicit `variant="outlined"` attributes - **Card Border Removal** - Removed global card borders for a cleaner look - Cards now rely on elevation/shadow and background contrast - Removed inline border styles from all components ### Added - Myst Grayscale Theme - **New Theme: Myst** - Elegant grayscale theme with light-gray background - Dark text on light backgrounds for readability - Inverted buttons (dark buttons with white text) - Professional, colorless aesthetic - Added to theme selector with fog icon ## [0.19.0-beta] - 2026-01-07 ### Added - User-Customizable Fonts - **10 Font Options for User Preference** - System Default (device's native font stack) - Inter, Roboto, Lato, Fira Sans (modern UI fonts) - Lexend (optimized for reading fluency) - OpenDyslexic, Atkinson Hyperlegible (accessibility fonts) - Source Serif Pro (classic serif) - JetBrains Mono (developer monospace) - **Self-Hosted Web Fonts** - All fonts bundled as woff2 files in `web/public/fonts/` - No external CDN dependencies - All fonts licensed under SIL OFL 1.1 or Apache 2.0 - **Backend Integration** - New `font_family` field in user_settings domain model - Database migration v0.21.0 adds font_family column - Syncs font preference across devices - **Frontend Implementation** - New `font.js` Pinia store for font state management - CSS variable `--app-font-family` for dynamic switching - Font selector UI in Settings view - localStorage caching for instant load on return visits - Vuetify component overrides for consistent font application ### Added - Markdown Support for Descriptions - **Description Fields Support Markdown Formatting** - Movements, WODs, and workout templates now render Markdown - Added "Format text using Markdown" hint to all description textareas - MovementDetailView updated to use MarkdownRenderer component ### Added - Admin Notification System for User Events - **Email Notifications for Administrators** - Notify admins when users are created, modified, or deleted - Events: registration, profile updates, role changes, disable/enable/unlock/delete - Per-admin opt-out setting in user_settings (`admin_user_event_notifications`) - Email includes before/after values for changes - Actor (admin who performed action) excluded from notifications - **In-App Notifications for Administrators** - Real-time in-app notifications for all admin user events - Notification types: `admin_user_created`, `admin_user_updated`, `admin_user_role_changed`, etc. - Links directly to user management in admin panel - Notifications sent to all admins except the actor - **New Service: AdminNotificationService** - Centralized admin notification logic - Async email sending (non-blocking) - Graceful degradation when email disabled - Files: `internal/service/admin_notification_service.go` - **Database Migration v0.20.0** - Added `admin_user_event_notifications` column to `user_settings` table ### Added - Expiring/Expired Subscription Management - **Admin Dashboard Subscription Views** - List subscriptions expiring within N days (7, 14, 30, 60, 90) - List all expired (overdue) subscriptions - Separate views for user and organization subscriptions - **New API Endpoints** - `GET /api/admin/subscriptions/users/expiring?days=N` - Expiring user subscriptions - `GET /api/admin/subscriptions/users/expired` - Expired user subscriptions - `GET /api/admin/subscriptions/organizations/expiring?days=N` - Expiring org subscriptions - `GET /api/admin/subscriptions/organizations/expired` - Expired org subscriptions - **Repository Methods** - Added `ListExpiring(days int)` and `ListExpired()` to both subscription repositories - Multi-database support (SQLite, PostgreSQL, MySQL) with database-native date arithmetic ### Added - User Timezone Support - **Per-User Timezone Settings** - Users can set their preferred timezone in settings - Dates displayed in user's local timezone throughout the application - Database migration v0.19.0 adds `timezone` column to `user_settings` - **Frontend Integration** - Timezone selector in Settings view - Utility functions for timezone-aware date formatting - Pinia store for timezone state management ### Fixed - PostgreSQL Compatibility - **GetPersonalRecords Query Fix** - Added aggregate functions (MAX) to all non-grouped SELECT columns - Fixes PostgreSQL strict GROUP BY enforcement error - Scan workout_date as string and parse to time.Time (MAX returns string in SQLite) - All databases (SQLite, PostgreSQL, MySQL) now work correctly - **Base Schema Sync** - Added `admin_user_event_notifications` column to base schema for all database types - Ensures fresh database installations have all columns ### Fixed - Test Suite Improvements - **Test Coverage for Subscription Features** - Repository tests for `ListExpiring` and `ListExpired` methods - Service tests for all 4 new subscription service methods - Handler tests with mock implementations - **Pre-existing Test Fixes** - Fixed backup handler test case sensitivity ("Filename" → "filename") - Updated WOD service test for removed source validation constraint - Integration test now outputs response body on failure for debugging ### Added - Merge/Upsert for Database Restore and Import Duplicate Handling - **Database Restore Modes** - Added three restore modes to `RestoreBackup` API: - `replace` - Delete all data, insert from backup (original behavior) - `merge` - Update existing records by natural key, insert new ones - `skip` - Only insert records that don't exist - Natural key matching for record identification: - Users matched by email - Movements matched by name - WODs matched by name - Organizations matched by name - User workouts matched by user_id + workout_date + workout_name - ID remapping for foreign key references during merge/skip restore - Returns detailed `RestoreResult` with statistics (records created, updated, skipped) - **Import Duplicate Handling Enhancements** - **User Workout Import**: Added `updateDuplicates` parameter - Duplicate detection using user_id + workout_date + workout_name - Can now skip OR update existing workouts during import - **Wodify Import**: Added `skipDuplicates` and `updateDuplicates` parameters - `skipDuplicates=true`: Skip workouts that already exist for a date - `updateDuplicates=true`: Replace existing workout data for a date - Added `WorkoutsSkipped` to import result statistics - **API Changes** - `POST /api/admin/backups/{filename}/restore` now accepts `mode` parameter: ```json {"confirm": true, "mode": "merge"} // or "skip" or "replace" ``` - `POST /api/import/user-workouts/confirm` now accepts `update_duplicates` form field - `POST /api/import/wodify/confirm` now accepts `skip_duplicates` and `update_duplicates` form fields **Files Modified:** - `internal/domain/backup.go` - Added RestoreMode type and RestoreResult struct - `internal/domain/wodify_import.go` - Added WorkoutsSkipped field - `internal/service/backup_service.go` - Implemented merge/upsert with ID remapping (646+ lines) - `internal/service/import_service.go` - Added updateDuplicates to user workout import - `internal/service/wodify_import_service.go` - Added skip/update duplicate handling - `internal/handler/backup_handler.go` - Added mode parameter parsing - `internal/handler/import_handler.go` - Added update_duplicates form field - `internal/handler/wodify_import_handler.go` - Added duplicate handling form fields ### Fixed - PostgreSQL Schema Migration Support - **Critical Fix: PostgreSQL Custom Schema Support** - Fixed `checkTableExists()` to use `CURRENT_SCHEMA()` instead of hardcoded 'public' - Fixed `checkColumnExists()` to filter by `CURRENT_SCHEMA()` to avoid false positives - **Impact**: Migrations now work correctly with custom PostgreSQL schemas (e.g., `DB_SCHEMA=actalog`) - **Root Cause**: Previous code hardcoded `table_schema='public'` which failed for non-public schemas - **Behavior Before Fix**: - Migration checks would fail to find existing tables in custom schemas - Would attempt to re-create tables, causing "table already exists" errors - Required manual database rebuild when using custom PostgreSQL schemas - **Behavior After Fix**: - Automatic schema detection using active `search_path` - Migrations work seamlessly across all database engines and schemas - No manual intervention needed for schema migrations - Files Modified: `internal/repository/database.go` (lines 137-200) - Build: #60 ### Added - Comprehensive Audit Logging - **Complete Audit Trail for All Data Operations** - Added audit logging to MovementService (Create, Update, UpdateAsAdmin, Delete) - Added audit logging to WODService (Create, Update, UpdateAsAdmin, Delete) - Added audit logging to WorkoutTemplateService (Create, Update, Delete) - Added audit logging to UserWorkoutService (LogWorkout, LogWorkoutWithPerformance, UpdateLoggedWorkout, DeleteLoggedWorkout) - Added audit logging to UserService (UpdateProfile) - Added audit logging to UserSettingsService (UpdateSettings) - **Audit Log Event Types** - Movement events: `movement_created`, `movement_updated`, `movement_deleted` - WOD events: `wod_created`, `wod_updated`, `wod_deleted` - Workout template events: `workout_template_created`, `workout_template_updated`, `workout_template_deleted` - User workout events: `user_workout_logged`, `user_workout_updated`, `user_workout_deleted` - User management events: `profile_updated`, `user_settings_updated` - **Change Tracking Features** - Before/after values stored for all update operations - JSON-encoded details with full context - User attribution (UserID for performer, TargetUserID for affected user) - Admin operation flags for administrative updates - Timestamp tracking for all operations ### Changed - **Service Method Signatures** - All CRUD operations now accept `userID int64` and `userEmail string` parameters - MovementService.Create signature: `Create(movement *domain.Movement, userID int64, userEmail string) error` - WODService methods updated to include userEmail parameter - WorkoutTemplateService methods updated to include userEmail parameter - UserWorkoutService methods updated to include userEmail parameter - UserSettingsService.UpdateSettings signature: `UpdateSettings(userID int64, userEmail string, updates *domain.UserSettings) (*domain.UserSettings, error)` - **Handler Implementations** - All handlers extract userEmail from JWT context using `middleware.GetUserEmail()` - Handlers pass both userID and userEmail to service methods - Updated: movement_handler.go, wod_handler.go, workout_template_handler.go, user_workout_handler.go, settings_handler.go - **Service Initialization** - All service constructors updated to accept auditLogRepo parameter - Main.go updated with comprehensive audit log repository injection - MovementService, WODService, WorkoutTemplateService, UserWorkoutService, UserSettingsService all initialized with audit logging ### Technical Details - **Build**: #40 - **Files Modified**: - `internal/domain/audit_log.go` - Added comprehensive event constants - `internal/service/movement_service.go` - Audit logging for all operations - `internal/service/wod_service.go` - Audit logging for all operations - `internal/service/workout_template_service.go` - Audit logging for all operations - `internal/service/user_workout_service.go` - Audit logging for all operations - `internal/service/user_service.go` - Added audit logging to UpdateProfile - `internal/service/user_settings_service.go` - Added audit logging to UpdateSettings - `internal/handler/movement_handler.go` - Extract and pass userEmail - `internal/handler/wod_handler.go` - Extract and pass userEmail - `internal/handler/workout_template_handler.go` - Updated interface and handlers - `internal/handler/user_workout_handler.go` - Extract and pass userEmail - `internal/handler/settings_handler.go` - Extract and pass userEmail - `cmd/actalog/main.go` - Updated service initialization with auditLogRepo ### Audit Logging Patterns - **Conditional Logging**: All audit logging uses nil checks (`if s.auditLogRepo != nil`) - **JSON Encoding**: Audit details stored as JSON for structured querying - **Error Handling**: Audit log failures don't block primary operations (fire-and-forget pattern) - **Entity Context**: Each log includes entity type, entity ID, entity name, and user context - **Admin Tracking**: Admin operations marked with `admin_update: true` flag ### Coverage - ✅ Movement CRUD operations fully logged - ✅ WOD CRUD operations fully logged - ✅ Workout Template CRUD operations fully logged - ✅ User Workout operations fully logged - ✅ User Profile updates fully logged - ✅ User Settings updates fully logged - ✅ Organization operations logged (from v0.14.0) - ✅ Subscription operations logged (from v0.14.0) - ✅ User associations logged (from v0.14.0) ### Added - Comprehensive Test Coverage Improvements - **Service Layer Test Coverage: 81.6% Overall** - 13 services now at 100% coverage - Added comprehensive backup_service tests (10 test functions) - Added wodify_import_service tests with duplicate handling - Fixed mock initialization patterns across test files - Added error injection support to mockUserRepo - **Backup Service Tests** (`backup_service_test.go`) - `TestBackupService_CreateBackup` - Full backup creation with ZIP archive - `TestBackupService_CreateBackup_UserNotFound` - Error handling for missing user - `TestBackupService_CreateBackup_WithUploads` - Backup with file attachments - `TestBackupService_RestoreBackup` - Replace mode restoration - `TestBackupService_RestoreBackup_MergeMode` - Merge mode with ID remapping - `TestBackupService_RestoreBackup_SkipMode` - Skip mode preserving existing - `TestBackupService_CreateSQLiteDump` - SQLite dump generation - `TestBackupService_ExportAllTables` - JSON export of all tables - Added `setupFullTestDB` helper with complete 20-table schema - **Test Infrastructure Improvements** (`test_helpers.go`) - Added `getByIDError` field to mockUserRepo for error injection - Fixed mock constructor patterns for proper map initialization - All mocks now use `newMockX()` constructor functions - **Files Modified:** - `internal/service/test_helpers.go` - Enhanced mockUserRepo with error injection - `internal/service/backup_service_test.go` - 10 new test functions - `internal/service/wodify_import_service_test.go` - Fixed mock initialization - `docs/TESTING.md` - Complete rewrite with current coverage stats --- ## [0.16.0-beta] - 2024-12-20 ### Added - Notification Likes Feature **Social Engagement for Notifications:** - Users can "like" any notification (PR achievements, announcements, weekly streaks, WOD milestones) - Like count displayed with thumbs up icon next to each notification - Names of users who liked displayed as comma-separated list ("Liked by: jcz, John, Mary") - Users can like their own notifications - **Automatic unread marking**: When someone likes a notification, it marks as unread for the original recipient - CASCADE DELETE: Deleting a notification automatically removes all associated likes **Backend Implementation:** - New `notification_likes` table with proper indexes and foreign keys - Unique constraint prevents duplicate likes (409 Conflict error returned) - Repository layer with JOIN query to fetch likes with user details - Service layer handles like/unlike operations and automatic unread marking - New `MarkAsUnread` method added to NotificationRepository interface **API Endpoints:** - `POST /api/notifications/{id}/like` - Like a notification - `DELETE /api/notifications/{id}/like` - Unlike a notification - `GET /api/notifications/{id}/likes` - Get all likes with user details (returns count and array of likes) **Frontend Component:** - `NotificationLikes.vue` component with thumbs up icon - Toggle between filled (liked) and outline (not liked) states - Real-time like count updates - Displays "Liked by: name1, name2, name3" in small grey text - Integrates seamlessly into existing NotificationsView - Proper authentication using configured axios instance **Database Migration:** - Migration v0.16.0 creates `notification_likes` table - Multi-database support: SQLite, PostgreSQL, MySQL - Indexes on `notification_id` and `user_id` for performance - Unique constraint on `(notification_id, user_id)` pair **Technical Details:** - **Build**: #59 - **Version**: 0.16.0-beta - **Files Created**: - `internal/domain/notification_like.go` - Domain model and repository interface - `internal/repository/notification_like_repository.go` - Data access layer - `internal/service/notification_like_service.go` - Business logic layer - `internal/handler/notification_like_handler.go` - HTTP handlers - `web/src/components/NotificationLikes.vue` - Frontend component - **Files Modified**: - `internal/repository/migrations.go` - Added v0.16.0 migration - `internal/domain/notification.go` - Added `MarkAsUnread` method to interface - `internal/repository/notification_repository.go` - Implemented `MarkAsUnread` - `cmd/actalog/main.go` - Wired up dependencies and routes - `web/src/views/NotificationsView.vue` - Integrated NotificationLikes component - `pkg/version/version.go` - Updated to v0.16.0-beta **Testing:** - ✅ Like/unlike operations verified - ✅ Like count updates correctly - ✅ User details populated via JOIN query - ✅ Notifications marked as unread when liked - ✅ CASCADE DELETE verified - ✅ Duplicate like prevention (409 Conflict) ### Fixed - Profile View Workout Summary Statistics **Bug Fixes:** - Fixed Personal Records count showing 0 (was looking for `personal_records` field, API returns `movements`) - Now correctly sums `pr_count` from each movement for total PR count - Fixed Current Streak calculation with incorrect consecutive day logic - Rewrote streak algorithm to properly check for consecutive workout days - Added null safety for API responses when no PRs exist **Streak Calculation Improvements:** - Uses unique workout dates (handles multiple workouts per day) - Checks if most recent workout is today or yesterday (or streak is broken) - Counts backwards through consecutive days correctly - Stops at first gap in workout dates **Files Modified:** - `web/src/views/ProfileView.vue:604-673` - Stats fetching and calculation logic ### Added - Workout Summary Time Period Filters **Time Filter Options:** - This Week (Sunday through today) - This Month (1st of month through today) - This Year (January 1st through today) - All Time (no filtering) **Filtering Behavior:** - Total Workouts: Filtered by selected period - Personal Records: Filtered by `last_pr_date` from PR movements - Current Streak: Always all-time (continuous metric) - Custom Templates: Always all-time (cumulative creations) **UX Features:** - Chip-based filter selector above stats - Real-time updates when switching periods - Default period: "This Month" - Reactive updates using Vue watch **Files Modified:** - `web/src/views/ProfileView.vue:198-212, 578, 603-709, 887-890` - Time filter UI and logic ### Fixed - CI Pipeline Compilation Errors **Test Compilation Fixes:** - Fixed `mockEmailService` missing `SendHTMLEmail(to, subject, htmlBody)` method - Fixed `NewUserWorkoutService` calls missing 4 parameters in all 5 test cases - Added `mockMovementRepo` with 13 methods implementing `MovementRepository` interface - Added `GetAllPerformancesForMovement` to `mockUserWorkoutMovementRepo` **Impact:** - ✅ All service tests now compile successfully - ✅ Integration tests compile successfully - ✅ CI pipeline unblocked for Go compilation step - ✅ Database matrix tests (SQLite, PostgreSQL, MySQL) can now run **Files Modified:** - `internal/service/user_service_test.go` - Added SendHTMLEmail mock method - `internal/service/user_workout_service_test.go` - Fixed all NewUserWorkoutService calls - `internal/service/test_helpers.go` - Added mockMovementRepo and GetAllPerformancesForMovement --- ## [0.14.0-beta] - 2024-12-16 ### Added - Subscription Billing System **Dual-Level Subscription Management:** - User-level subscriptions (individual billing) - Organization-level subscriptions (gym/team billing) - Flexible access model: users have access if EITHER personal OR any organization subscription is active - Three subscription types: Free, Monthly, Annual - Permanent Free subscriptions for founders/staff (never expire, never need payment) - Immediate read-only mode enforcement when subscriptions expire (no grace period) **Admin Controls:** - Manual payment management (admins mark subscriptions as paid/unpaid) - Subscription creation, cancellation, and history viewing - Complete audit trail for all subscription operations - Admin API endpoints for subscription management **Read-Only Mode:** - Users with expired subscriptions can view all data, export data, access dashboard/analytics - Write operations blocked (POST/PUT/PATCH/DELETE) return HTTP 402 Payment Required - Read operations allowed (GET/HEAD/OPTIONS) for viewing and exporting **Backward Compatibility:** - Migration 0.14.0 automatically seeds all existing users with permanent free subscriptions - Zero downtime deployment - no existing users lose access - All current users receive `is_permanent_free = TRUE` status **Database Support:** - Multi-database migration tested on SQLite, PostgreSQL, and MariaDB - Version snapshots created for all three database engines - Database versioning system for testing future migrations ### Technical Implementation **New Domain Entities:** - `UserSubscription` - Individual user subscriptions with 15 fields - `OrganizationSubscription` - Organization-level subscriptions - `SubscriptionAccessResult` - Access check result with source indication **Repository Layer:** - `UserSubscriptionRepository` - CRUD operations for user subscriptions - `OrganizationSubscriptionRepository` - CRUD for organization subscriptions - `SubscriptionAccessRepository` - Performance-optimized access checking (< 10ms target) **Service Layer:** - `SubscriptionService` - Business logic for subscription management - Admin operations: Create, MarkAsPaid, Cancel - User operations: CheckAccess, GetStatus **Middleware:** - `RequireActiveSubscription` - HTTP method-based enforcement - Allows GET requests when expired (view/export) - Blocks POST/PUT/PATCH/DELETE when expired **API Endpoints:** - `GET /api/subscriptions/status` - User subscription status - `POST /api/admin/subscriptions/user` - Create user subscription - `POST /api/admin/subscriptions/user/{id}/mark-paid` - Mark as paid - `POST /api/admin/subscriptions/user/{id}/cancel` - Cancel subscription - `GET /api/admin/subscriptions/user/{user_id}` - View subscription history - Organization subscription endpoints (parallel structure) **Database Version Management:** - `db_versions/actalog_0.14.0.db` - SQLite snapshot (564 KB with production-like data) - PostgreSQL schema `actalog_0_14_0` on 192.168.1.143 - MariaDB database `actalog_0_14_0` on 192.168.1.234 - All version databases contain identical test data with 4 test users - Automated scripts: `create-db-snapshot.sh`, `verify-version-databases.sh` ### Files Created (14 files) - `internal/domain/subscription.go` (106 lines) - Domain entities and interfaces - `internal/repository/user_subscription_repository.go` (441 lines) - `internal/repository/organization_subscription_repository.go` (441 lines) - `internal/repository/subscription_access_repository.go` (145 lines) - `internal/service/subscription_service.go` (368 lines) - `pkg/middleware/subscription.go` (81 lines) - `internal/handler/subscription_handler.go` (476 lines) - `db_versions/README.md` - Version management overview - `db_versions/VERSION_DATABASES.md` - Multi-database access guide (284 lines) - `db_versions/MIGRATION_TEST_0.14.0.md` - Migration test report - `db_versions/actalog_0.14.0.db` - SQLite version snapshot - `scripts/create-db-snapshot.sh` - Automated snapshot creation - `scripts/verify-version-databases.sh` - Multi-database verification - PostgreSQL schema: `actalog_0_14_0` with test data - MariaDB database: `actalog_0_14_0` with test data ### Files Modified (5 files) - `internal/repository/migrations.go` - Added migration 0.14.0 (lines 885-1162) - `pkg/version/version.go` - Updated to 0.14.0, build 24 - `cmd/actalog/main.go` - Wired repositories, service, handler, routes - `internal/domain/audit_log.go` - Added subscription event types - `CLAUDE.md` - Added database version management section ### Technical Details - **Build**: #24 - **Version**: 0.12.2-beta → 0.14.0-beta - **Migration**: 0.14.0 creates `user_subscriptions` and `organization_subscriptions` tables - **Schema**: 15 columns per table, 4 indexes per table for performance - **Constraints**: CHECK constraints on subscription_type and status, CASCADE/SET NULL foreign keys - **Performance**: Access check optimized for < 10ms per authenticated request - **Audit**: All subscription operations logged with admin user ID and details --- ## [0.12.2-beta] - 2025-11-28 ### Fixed - PWA Offline Functionality **Offline Workout Recording:** - Fixed service worker API caching pattern (was `/api/.*/*.json`, now correctly caches `/api/workouts`, `/api/movements`, `/api/wods`, `/api/templates`) - Added robust offline detection in axios interceptor (checks multiple error indicators: `Network Error`, `ERR_NETWORK`, `navigator.onLine`, timeout) - Extended offline handling to support PUT requests (workout updates) in addition to POST - Fixed request data parsing for offline sync queue **User-Controlled PWA Updates:** - Replaced disruptive silent auto-reload with user-controlled updates - New `UpdatePrompt.vue` component shows "Update Available" snackbar with "Later" and "Update Now" buttons - New `pwa.js` Pinia store manages PWA update state - Users can choose when to apply updates, preventing data loss during form entry **Offline Save Notification:** - Added "Saved Offline" snackbar notification when workouts are saved locally - Dispatches custom `offline-save` event for UI notification - Automatically increments pending sync count in network store ### Fixed - Unit Tests **WOD Service Tests:** - Fixed `mockWODRepo.GetByName()` to return `nil, nil` instead of `sql.ErrNoRows` when WOD not found - Updated test cases to use correct error types (`ErrWODOwnership`, `ErrWODUnauthorized`) - Added required fields (Source, Type, Regime, ScoreType) to Update tests - Fixed Search test expectation for empty query (service returns empty by design) ### Technical Details - **Build**: #1 (reset for new patch version) - **Version**: 0.12.1-beta → 0.12.2-beta - **Files Created**: - `web/src/components/UpdatePrompt.vue` (PWA update notification component) - `web/src/stores/pwa.js` (PWA state management) - **Files Modified**: - `web/vite.config.js` (service worker caching patterns) - `web/src/utils/axios.js` (offline detection and sync) - `web/src/App.vue` (offline save notification, update prompt) - `web/src/main.js` (PWA store integration) - `internal/service/test_helpers.go` (mock fixes) - `internal/service/wod_service_test.go` (test corrections) --- ## [0.12.1-beta] - 2025-11-28 ### Fixed - MySQL/MariaDB Compatibility **Database-Agnostic Timestamp Functions:** - Fixed `addWorkoutMovementWithDistance()` to use database-specific timestamp syntax - Fixed `refresh_token_repository.go` functions with hardcoded SQLite `datetime('now')`: - `GetByToken()` - Token expiration check - `Revoke()` - Token revocation timestamp - `RevokeAllForUser()` - Bulk revocation timestamp - `DeleteExpired()` - Expired token cleanup - Added `getTimestampFunc()` helper for database-agnostic timestamp generation - Supports SQLite (`datetime('now')`), PostgreSQL (`CURRENT_TIMESTAMP`), MySQL/MariaDB (`NOW()`) ### Added - Docker Host Database Documentation **Comprehensive Troubleshooting Guide for External Databases:** - `docker/DOCKER.md` - New "Connecting to Host Database" troubleshooting section - `docker/DATABASE_DEPLOYMENT.md` - Enhanced external database troubleshooting: - UFW firewall configuration for Docker network access - MariaDB/MySQL bind-address configuration steps - PostgreSQL listen_addresses and pg_hba.conf setup - Database user permission grants for Docker network (172.17.0.0/16) - Linux `extra_hosts: host.docker.internal:host-gateway` configuration - Step-by-step connection refused debugging ### Technical Details - **Build**: #4 → #5 - **Version**: 0.12.0-beta → 0.12.1-beta - **Files Modified**: - `internal/repository/database.go` (timestamp helper + fix) - `internal/repository/refresh_token_repository.go` (4 function fixes) - `docker/DOCKER.md` (host database troubleshooting) - `docker/DATABASE_DEPLOYMENT.md` (firewall + connection troubleshooting) --- ## [0.12.0-beta] - 2025-11-26 ### Fixed - Mobile PWA Layout **Comprehensive Mobile Overflow Fix:** - Systematically fixed horizontal/vertical overflow issues across 27 view files - Implemented `.mobile-view-wrapper` CSS pattern for consistent mobile-safe layouts - Updated `main.css` with global mobile-safe styles preventing body overflow - Enhanced `App.vue` with dynamic safe-area handling for iOS PWA - Views updated include: - Dashboard, Profile, Performance, Workouts - WOD/Movement Libraries and Detail views - Log Workout, Quick Log dialogs - Admin views (Users, Backups, Data Cleanup, Data Change Logs, User Content) - Import/Export, PR History, Templates - Auth flows (Login, Register, Forgot/Reset Password) - Prevents content from extending beyond viewport on mobile devices - Ensures smooth scrolling within content areas - Maintains fixed header (56px) and bottom navigation (70px) positioning ### Added - Docker Image Metadata **OCI Labels for Docker Images:** - Added comprehensive OCI-compliant labels to Docker build scripts - User-editable metadata section at top of `docker/scripts/build.sh` - Labels include: - `org.opencontainers.image.title` - Application name - `org.opencontainers.image.description` - Project description - `org.opencontainers.image.vendor` - Organization/vendor name - `org.opencontainers.image.authors` - Author contact information - `org.opencontainers.image.source` - Repository URL - `org.opencontainers.image.documentation` - Documentation URL - `org.opencontainers.image.licenses` - License type - `org.opencontainers.image.version` - Build version (from tag) - `org.opencontainers.image.created` - Build timestamp (auto-generated) - Improves container registry display and image discoverability ### Changed - Admin UI Improvements **Admin User Content View Enhancement:** - Moved Actions column from last to first position in data table - Improves mobile usability by placing action buttons immediately visible - Consistent with other admin table patterns - Delete buttons now accessible without horizontal scrolling ### Technical Details - **Build**: #71 → #1 (reset for new minor version) - **Version**: 0.11.0-beta → 0.12.0-beta - **Files Modified**: 27 Vue view files, App.vue, main.css, build.sh, AdminUserContentView.vue --- ## [0.11.0-beta] - 2025-11-26 ### Added - Data Change Audit Logs **Data Change Logging System:** - Complete audit trail for data modifications (updates and deletes) - Before/after values stored as JSON for full change history - Tracks entity type, entity ID, entity name, operation, user, timestamp - Optional IP address and user agent capture - Automatic integration with WOD and Movement services **Admin UI for Data Change Logs:** - New admin view at `/admin/data-change-logs` for browsing change history - Filterable by entity type (WOD, Movement, Workout, etc.) - Filterable by operation (Update, Delete) - Filterable by user email (partial match) - Paginated data table with 50 logs per page - Details dialog showing: - Full change metadata (timestamp, entity info, user) - Before/After JSON values in formatted display - Changed fields diff table for updates - Color-coded operations (warning for update, error for delete) - Color-coded entity types for easy identification **Navigation Integration:** - "Data Change Logs" card added to Admin dashboard - Link added to Profile page Administration section for admins - Consistent styling with existing admin tools **Database Migration:** - New `data_change_logs` table (migration 0.5.2) - Indexes on entity_type, entity_id, user_id, created_at, operation - Support for all database drivers (SQLite, PostgreSQL, MySQL) **API Endpoints:** - `GET /api/admin/data-change-logs` - List with filters and pagination - `GET /api/admin/data-change-logs/:id` - Get single log entry - `GET /api/admin/data-change-logs/entity/:type/:id` - Entity history - `POST /api/admin/data-change-logs/cleanup` - Delete old logs ### Technical Details - **Build**: #62 → #63 - **New Files**: - `internal/domain/data_change_log.go` - Domain model and interfaces - `internal/repository/data_change_log_repository.go` - Data access layer - `internal/service/data_change_log_service.go` - Business logic with helper methods - `internal/handler/data_change_log_handler.go` - HTTP handlers - `web/src/views/AdminDataChangeLogsView.vue` - Admin UI component - **Modified Files**: - `internal/service/wod_service.go` - Added data change logging - `internal/service/movement_service.go` - Created service with data change logging - `internal/handler/wod_handler.go` - Pass user email to service - `internal/handler/movement_handler.go` - Use new MovementService - `web/src/views/AdminView.vue` - Added Data Change Logs card - `web/src/views/ProfileView.vue` - Added admin link to Data Change Logs - `web/src/router/index.js` - Added route for data-change-logs ### Use Cases Enabled - Track who changed what and when across all data types - Review before/after values for any modification - Audit trail for compliance and accountability - Debug data issues by reviewing change history - Admin cleanup of old logs to manage storage --- ## [0.10.0-beta] - 2025-01-23 ### Added - Docker Deployment with Automatic Seed Import **Docker Infrastructure:** - Multi-stage Dockerfile with optimized build process - Three docker-compose configurations: - `docker-compose.yml` - SQLite (default, single-server deployments) - `docker-compose.postgres.yml` - PostgreSQL (production recommended) - `docker-compose.mariadb.yml` - MariaDB/MySQL (production alternative) - GitHub Actions CI/CD workflow for automated image building - Helper scripts for building and pushing Docker images - Health checks for container monitoring **Automatic Seed Data Import:** - Optional automatic import of CSV seed data on first deployment - Environment-based configuration (ADMIN_EMAIL, ADMIN_PASSWORD) - Entrypoint script orchestrating app startup and seed import - Imports 182 movements and 314 WODs automatically - One-time execution using marker file pattern - Graceful degradation when credentials not provided **Comprehensive Documentation:** - `DOCKER.md` - Complete Docker deployment guide with examples - `DATABASE_DEPLOYMENT.md` - Multi-database deployment guide - `TEST.md` - Testing guide for Docker deployments - Environment configuration templates for all databases - Migration guides between database types **Seed Data:** - 182 CrossFit movements (all standard movements including Girl/Hero WOD movements) - 314 benchmark WODs (all Girl and Hero WODs) - CSV format for easy import and modification ### Technical Details - **Build**: #62 → #63 (build number auto-incremented) - **New Files**: - `docker/Dockerfile` - Multi-stage build (frontend, backend, runtime) - `docker/scripts/entrypoint.sh` - Startup orchestration - `docker/scripts/init-seeds.sh` - Seed import script - `docker/scripts/build.sh` - Docker build helper - `docker/scripts/push.sh` - GitHub Container Registry push helper - `.github/workflows/docker-build.yml` - CI/CD automation - **Modified**: All environment template files (.env.example, .env.postgres, .env.mariadb) - **Documentation**: Added comprehensive Docker and database deployment guides ### Deployment Features - GitHub Container Registry (ghcr.io) integration - Automatic image builds on push to main branch - Tag-based versioning (latest, version-specific tags) - Health check endpoints for monitoring - Volume management for persistent data - Network isolation with bridge networks - Non-root container user for security ## [0.9.0-beta] - 2025-01-23 ### Added - Full Offline Support & PWA Enhancements **iOS PWA Support:** - iOS-specific meta tags for full PWA capabilities - Apple touch icon configuration - Black-translucent status bar styling **Network Status Management:** - Pinia network store for centralized online/offline state - Real-time status chip in app bar (Offline/Syncing indicators) - Automatic network event detection - Pending sync operation counter **User Notifications:** - Persistent offline notification with explanation - 3-second online notification when reconnected - Sync complete confirmation notification - All notifications dismissible by user **Offline Data Storage:** - IndexedDB integration with axios interceptors - Automatic request queuing for failed network calls - Offline workout creation with background sync - Movement list caching for offline access **Auto-Sync Mechanism:** - Automatic sync when connection restored - Visual sync status feedback - Error handling with retry logic - Manual and automatic sync triggers **Offline-Capable Data Fetching:** - `useOfflineData` composable for network-aware loading - Cache-first strategy with API fallback - Generic `fetchWithCache` pattern - Movement caching implementation **PWA Install Prompt:** - Custom branded install UI - Smart timing (1 minute delay) - 7-day dismissal memory - Installation state detection ### Changed - Enhanced axios interceptors for offline request handling - Updated service worker runtime caching configuration - App.vue now includes network notifications and install prompt ### Technical Details - **Build**: #61 - **New Files**: network.js store, InstallPrompt.vue, useOfflineData.js composable - **Modified**: index.html, App.vue, axios.js, offlineStorage.js ## [0.8.2-beta] - 2025-01-23 ### Fixed - **Quick Log Template Selection**: Fixed crash when selecting workout templates from Quick Log dialog - Removed conflicting `item-value` property from v-autocomplete (was causing null object errors) - Added optional chaining (`?.`) throughout `submitQuickLog()` for defensive coding - Added error alert when template data is invalid - **Template WOD Display**: Fixed WOD names not showing when logging from template - Updated `getWODName()` to handle both nested (`wod.name`) and flattened (`wod_name`) API formats - Updated `initializePerformanceArrays()` to handle both WOD data formats - Fixed score type mapping to use full format (`'Time (HH:MM:SS)'` instead of `'Time'`) - Added missing `time_hours` field to WOD performance initialization ### Enhanced - **UI Consistency**: Updated Log Workout page styling to match Quick Log aesthetic - Removed excessive rounded corners from form elements (changed `rounded` to `border-radius: 8px`) - Made card styles more compact and consistent - **Quick Log UX**: Improved template selection workflow - Hidden "Browse Templates" button when arriving from Quick Log with pre-selected template - Added prominent warning message explaining data preservation behavior - Changed template info box to orange warning theme with information icon - Clear message: "Only the date will be preserved. Notes, workout name, and total time entered here will not be carried over." ### Technical - Enhanced `onTemplateSelected()` function to properly initialize performance arrays after loading template - Added template to list if not already present (handles Quick Log navigation scenario) - Improved data format compatibility between different API response structures ## [0.8.1-beta] - 2025-01-22 ### Added - **Cross-Database Backup/Restore**: Complete database-agnostic backup and restore system - Database-agnostic table existence checks using `information_schema` (PostgreSQL/MySQL) and `sqlite_master` (SQLite) - Table column introspection for schema evolution support - Automatic detection of schema differences between backup and target database - Column filtering: Only restores columns that exist in target schema (handles removed columns gracefully) - New columns use DEFAULT values from schema (handles added columns) - **Full cross-database migration support**: - ✅ MariaDB → PostgreSQL - ✅ SQLite → PostgreSQL - ✅ MySQL → MariaDB - ✅ Any combination of supported databases - **PostgreSQL Sequence Reset**: Automatic sequence management after restore - Resets auto-increment sequences to `MAX(id) + 1` for all tables - Prevents "duplicate key violation" errors on subsequent inserts - Uses `pg_get_serial_sequence()` and `setval()` for proper sequence handling - Only applies to PostgreSQL (SQLite/MySQL handle sequences differently) - **Data Type Conversion**: Automatic type conversion between databases - Boolean conversion: `0/1` (SQLite/MySQL) ↔ `false/true` (PostgreSQL) - Handles columns: `is_pr`, `is_template`, `is_standard`, `email_verified`, `account_disabled`, `notifications_enabled` - JSON unmarshaling safety: Handles `float64` → boolean conversion - Preserves data integrity across different database type systems - **Schema Evolution Support**: Forward and backward compatibility for version migrations - Backup from v0.6.0 can be restored to v0.8.1 (handles missing tables/columns) - Backup from v0.8.1 can be restored to v0.6.0 (newer columns gracefully ignored) - Informative logging: "skipped N column(s) not present in target schema" - No manual SQL intervention required for schema differences ### Enhanced - **RestoreBackup Function**: Complete rewrite for database compatibility - Replaced SQLite-specific `sqlite_master` queries with database-agnostic `tableExists()` - Added column introspection before each table restore - Integrated automatic sequence reset for PostgreSQL - Enhanced error messages with specific table and column information - Graceful handling of missing tables (forward compatibility) - **restoreTable Function**: Full schema evolution and type conversion support - Column filtering based on actual target schema - Value conversion for database compatibility - Per-column type conversion using `convertValue()` - Informative progress logging during restore - Automatic sequence reset after table population ### Functions Added - `tableExists(tx, tableName)`: Database-agnostic table existence check - `getTableColumns(tx, tableName)`: Query actual schema columns - `resetSequence(tx, tableName)`: PostgreSQL sequence management - `convertValue(val, columnName)`: Cross-database type conversion - `containsString(slice, str)`: Helper for column filtering ### Use Cases Enabled - **Production Database Migration**: Migrate from SQLite (development) to PostgreSQL (production) using backup/restore - **Cross-Database Replication**: Copy data between different database systems without manual export/import - **Version Upgrades**: Restore old backups to newer application versions seamlessly - **Multi-Tenant Migration**: Migrate from single-tenant to multi-tenant PostgreSQL using schema parameter - **Disaster Recovery**: Restore backups to different database types in emergency scenarios - **Development → Production**: Test with SQLite, deploy with PostgreSQL using same backup files ### Technical Details - **Build Number**: #58 - **Files Modified**: - `internal/service/backup_service.go`: Added 190+ lines of new database-agnostic helper functions - Updated `RestoreBackup()` and `restoreTable()` with full schema evolution support - **Backward Compatibility**: 100% backward compatible - same-database restores work identically - **Testing**: Builds successfully, ready for cross-database testing ### Migration Example ```bash # On MariaDB v0.7.x instance POST /api/admin/backups Download actalog_backup_20250122.zip # On PostgreSQL v0.8.1 instance DB_DRIVER=postgres make migrate # Creates PostgreSQL schema POST /api/admin/backups/upload # Upload MariaDB backup POST /api/admin/backups/{filename}/restore # Data migrated! ``` ## [0.8.0-beta] - 2025-11-22 ### Changed - **PostgreSQL Driver Migration (BREAKING for PostgreSQL users)**: Migrated from `lib/pq` to `pgx/v5` driver - **Dependency Change**: Removed `github.com/lib/pq v1.10.9`, added `github.com/jackc/pgx/v5 v5.7.6` - **Performance**: 10-30% faster for most PostgreSQL workloads - **Active Development**: pgx is actively maintained vs lib/pq in maintenance mode - **Better Features**: Improved support for PostgreSQL-specific features (LISTEN/NOTIFY, COPY, binary protocol) - **Context Support**: Better cancellation and timeout handling - **Backward Compatibility**: SQLite and MySQL/MariaDB unaffected, full backward compatibility maintained ### Added - **PostgreSQL Schema Support**: Added `DB_SCHEMA` environment variable for schema isolation - Enables multi-tenant PostgreSQL deployments using database schemas - DSN now includes `search_path` parameter for schema targeting - Default schema: `public` (standard PostgreSQL behavior) - Example: `DB_SCHEMA=actalog` routes all operations to the actalog schema - **Connection Pooling Configuration**: Fine-grained control over database connection pools - `DB_MAX_OPEN_CONNS`: Maximum simultaneous database connections (default: 25) - `DB_MAX_IDLE_CONNS`: Maximum idle connections kept ready (default: 5) - `DB_CONN_MAX_LIFETIME`: Maximum connection lifetime before recycling (default: 5m) - Applies to PostgreSQL and MySQL/MariaDB only (SQLite uses single connection) - Configurable per deployment for optimal resource usage - Updated `.env.example` with connection pooling examples and tuning guidance - **Multi-Database Testing**: Comprehensive verification across all supported databases - ✅ SQLite (sqlite3): Fully backward compatible, all features tested - ✅ PostgreSQL (pgx/v5): Full migration verified with real database at 192.168.1.143 - ✅ MariaDB/MySQL (mysql): Compatibility verified with real database at 192.168.1.234 - All three databases: schema creation, migrations, seeding, and operations verified - Real-world connection pooling and schema isolation tested - **Documentation**: Created comprehensive migration guide - `docs/POSTGRESQL_MIGRATION.md`: Complete migration guide for PostgreSQL users - Step-by-step migration instructions for existing lib/pq users - New PostgreSQL deployment instructions from scratch - Schema isolation configuration examples - Connection pooling tuning guidelines - Troubleshooting section for common issues - Performance comparison (pgx vs lib/pq) - Rollback instructions if needed - Test results for all three databases with real connection details - **Docker Deployment Planning**: Added comprehensive Docker deployment roadmap to TODO.md - 50+ sub-tasks for complete Docker deployment solution - Documentation planning: `DOCKER_DEPLOYMENT.md`, `DOCKER_BUILD.md`, README updates - Implementation tasks: Dockerfile (multi-stage), docker-compose files for all 3 databases - GitHub Actions workflow for automated builds and publishing to ghcr.io - Multi-architecture support (amd64, arm64) - Testing across all deployment scenarios - Target: One-command deployment with `docker-compose up -d` - Target version: v0.9.0-beta ### Enhanced - **Database Abstraction Layer**: Improved database compatibility handling - New helper functions: `getBoolValue()`, `getPlaceholders()` for database-agnostic SQL - SQL placeholders: SQLite/MySQL use `?`, PostgreSQL uses `$1, $2, $3` - Boolean values: SQLite uses `0/1`, PostgreSQL/MySQL use `TRUE/FALSE` - Timestamp functions: SQLite uses `datetime('now')`, PostgreSQL uses `CURRENT_TIMESTAMP`, MySQL uses `NOW()` - Insert ID retrieval: PostgreSQL uses `RETURNING id` clause instead of `LastInsertId()` - All seeding functions updated: `seedStandardMovements()`, `seedStandardWODs()`, `seedWorkoutTemplates()` - All helper functions updated: `createWorkout()`, `addWorkoutMovement()`, `addWorkoutMovementWithTime()`, `addWorkoutWOD()`, `getMovementIDByName()`, `getWODIDByName()` - **DSN Format**: Updated PostgreSQL connection string format for pgx compatibility - Old format (lib/pq): `host=localhost port=5432 user=actalog dbname=actalog sslmode=disable` - New format (pgx): `postgres://user:password@host:port/database?sslmode=disable&search_path=schema` - Automatic schema path inclusion when `DB_SCHEMA` is configured - Full compatibility with PostgreSQL URIs - **Configuration Files**: Updated all configuration examples - `.env.example`: Added DB_SCHEMA, connection pooling parameters, and tuning guidelines - `configs/config.go`: New DatabaseConfig fields (Schema, MaxOpenConns, MaxIdleConns, ConnMaxLifetime) - Environment loading functions: `getEnvInt()`, `getEnvDuration()` for typed config values - Default values optimized for production use ### Fixed - **MariaDB Compatibility**: Fixed SQL syntax issues for MariaDB/MySQL - Fixed `addWorkoutWOD()` to use database-specific timestamp functions - Fixed `getMovementIDByName()` to use database-specific placeholders - Fixed `getWODIDByName()` to use database-specific placeholders - All helper functions now properly handle MySQL/MariaDB-specific SQL ### Technical Details - **Build Number Range**: #47-56 (10 builds during migration) - **Files Modified**: - Core: `go.mod`, `configs/config.go`, `internal/repository/database.go` - Commands: `cmd/actalog/main.go`, `cmd/migrate/main.go`, `cmd/check-schema/main.go` - Documentation: `.env.example`, `docs/POSTGRESQL_MIGRATION.md` - **Breaking Changes**: - PostgreSQL users must update from lib/pq to pgx (see migration guide) - No breaking changes for SQLite or MySQL users - Database schemas and data remain fully compatible - **Migration Path**: Existing PostgreSQL databases work without changes (DSN format updated automatically) ## [0.7.6-beta] - 2025-11-22 ### Added - **Backup Upload for Migration**: Added ability to upload external backup ZIP files from other systems - New upload button in AdminBackupsView with file picker for .zip files - `POST /api/admin/backups/upload` endpoint for multipart file upload - `UploadBackup()` service method with filename validation and ZIP verification - Timestamp-based renaming to prevent filename conflicts - Audit logging for all backup uploads with original filename tracking - Enables data migration between different ActaLog installations - Supports cross-database migrations (e.g., PostgreSQL backup restored to SQLite system) - **Documentation Planning**: Comprehensive planning for future documentation systems added to TODO.md - **End-User Help Documentation System**: Multi-document help system with Markdown, screenshots, and Mermaid diagrams - Planned GitHub storage (docs/help/ directory) with links from Profile screen - Table of Contents, FAQ section, and "How do I..." tutorials - 8 tutorial topics covering key features (logging, PRs, templates, performance, imports, PWA) - 4 workflow diagrams (workout logging, PR detection, import/export, authentication) - Image placeholders with descriptive captions for future screenshots - Cross-referenced topics and troubleshooting section - **Administrator Documentation System**: Comprehensive admin guide for system operators - Planned GitHub storage (docs/admin/ directory) with admin-only access from Profile screen - 12 administrative tutorials (user management, backups, audit logs, security, troubleshooting) - 5 admin workflow diagrams (user lifecycle, backup/restore, security/audit, permissions, lockout process) - Security best practices section (password policy, JWT management, CORS, email, monitoring) - System configuration guide (environment variables, database setup, SMTP, PWA, deployment) - API endpoint reference for automation - **Test Coverage Planning**: Comprehensive testing strategy for both backend and frontend - Backend testing: 13 tasks covering unit tests, integration tests, mocking, transactions - Frontend testing: 10 tasks covering components, E2E flows, PWA functionality, routing - Testing infrastructure: 7 tasks including CI/CD, coverage reporting, E2E framework, performance testing - Documentation: 4 tasks for testing patterns, guidelines, data setup, and CI documentation - **Scheduled Remote Backups**: Future enhancement planning for automatic cloud backups - Support for 6 cloud providers (AWS S3, Google Cloud Storage, Azure, Dropbox, Google Drive, SFTP/FTP) - Configurable schedules (hourly, daily, weekly, monthly) - Retention policies, verification, notifications, bandwidth throttling - **Expanded Seed Data**: Planning for extracting additional WODs and Movements from import files - Parse PDFs and crossfit_wods.csv to expand standard movement and WOD library - Automated extraction and conversion to seed CSV format ### Enhanced - **Audit Logging for Backup Operations**: Comprehensive audit trail for all backup activities - `backup_downloaded` event now logs file size in bytes asynchronously - `backup_restored` event now includes detailed statistics: - Total users, workouts, movements, and WODs restored - Provides visibility into restore scope and impact - All audit logs include user email and timestamp - Enables security monitoring and compliance tracking for data operations ### Fixed - **Cross-Version Restore Compatibility**: Backup restore now handles schema version differences gracefully - Added table existence checks before DELETE and INSERT operations using `sqlite_master` queries - Tables missing in current schema are skipped with warnings instead of causing fatal errors - `restoreTable()` method validates table existence before attempting data restore - Enables restoring backups from different ActaLog versions (forward and backward compatibility) - Warning messages logged for skipped tables to aid troubleshooting - Prevents 500 errors when restoring backups created on different schema versions ## [0.7.5-beta] - 2025-11-22 ### Added - **Admin User Management - Complete Integration**: Fully activated admin user management dashboard - Activated "User Management" card in AdminView (`/admin`) - now clickable and navigates to user management - Removed "Coming Soon" placeholder status - Backend API endpoints from v0.4.6-beta now fully integrated with frontend UI - **"Remember Me" Functionality**: Extended session duration for better user experience - Added checkbox to login form: "Remember me for 30 days" - Backend: Extended refresh token duration from 7 days to 30 days when Remember Me is checked - Modified `CreateRefreshToken()` method to accept `rememberMe` parameter (`internal/service/user_service.go:517`) - Updated login handler to pass Remember Me flag to service (`internal/handler/auth_handler.go:147`) - Frontend: Auth store already configured to send `remember_me` flag to API - Refresh tokens stored in localStorage for automatic session restoration - Audit logging for Remember Me token creation - Users who don't check "Remember Me" still get 7-day refresh tokens (default behavior) - **Database Backup and Restore System - Complete Activation**: Full disaster recovery and data migration capability - Activated "Database Backups" card in AdminView (`/admin`) with orange database-export icon - Complete backup/restore functionality previously implemented but not activated - Backend fully implemented and wired up: - `internal/service/backup_service.go` - Full database export to ZIP with JSON data - `internal/handler/backup_handler.go` - All CRUD endpoints for backup management - Routes active in `cmd/actalog/main.go` under `/api/admin/backups` - Frontend fully implemented: - `AdminBackupsView.vue` - Complete backup management interface at `/admin/backups` - Create new backups with metadata (version, user counts, workout counts) - List all backups with creation date, creator email, stats, and file size - Download backups as ZIP files - Delete backups with confirmation dialog - Restore backups with strong warning dialog and confirmation requirement - Empty state for first-time use - API Endpoints (Admin-only): - `POST /api/admin/backups` - Create new backup - `GET /api/admin/backups` - List all backups - `GET /api/admin/backups/{filename}` - Download backup file - `GET /api/admin/backups/{filename}/metadata` - Get backup metadata - `DELETE /api/admin/backups/{filename}` - Delete backup - `POST /api/admin/backups/{filename}/restore` - Restore from backup - ZIP backup structure includes all database tables exported as JSON - **SQLite Database Dump**: All backups now include a portable SQLite database file (`actalog_backup.db`) - If running SQLite: Direct copy of production database included in ZIP - If running PostgreSQL/MySQL: New SQLite database created from exported data and included in ZIP - Provides universal, portable database format that can be opened with any SQLite tool - Enables easy data inspection and migration between database systems - Supports all database drivers (SQLite, PostgreSQL, MySQL) - Audit logging for all backup operations - Security: Filename validation prevents directory traversal attacks ### Changed - **Mobile-Friendly Admin Table**: Restructured user management table for better mobile accessibility - Split single "Actions" column into 6 individual labeled columns (Details, Lock, Enable, Email, Change Role, Delete) - Clear column headers eliminate need for hover tooltips on mobile devices - Improved visual clarity with centered icons and consistent sizing - Better touch targets for mobile users ### Fixed - **PR History Date Display**: Fixed PR history to show workout date instead of record creation date - Backend: Added `WorkoutDate` assignment in `GetPRMovements()` and `GetPRWODs()` repository methods - Frontend: Changed `PRHistoryView.vue` to display `workout_date` instead of `created_at` - PR dates now show when the workout was performed (e.g., "Fri, Oct 10, 2024") - Previously showed database record creation timestamp which was incorrect for imported data - Affects both movement PRs and WOD PRs - **AdminBackupsView Layout**: Fixed Vuetify bottom navigation layout error - Restructured container hierarchy (outer `` → `
`) - Eliminated "Could not find layout item 'bottom-navigation'" console error - Fixed scroll behavior with proper overflow handling - Resolved layout conflicts when navigating from ProfileView - Applied same container pattern from AdminUsersView, WODLibraryView, MovementsLibraryView - **AdminUsersView Layout**: Fixed Vuetify bottom navigation layout error - Restructured container hierarchy (outer `` → `
`) - Eliminated "Could not find layout item 'bottom-navigation'" console error - Fixed scroll behavior with proper overflow handling - Resolved layout conflicts when navigating from ProfileView ## [0.7.4-beta] - 2025-11-22 ### Added - **Quick Log Buttons on Library Cards**: Added Quick Log functionality directly to WOD and Movement library card views - Teal lightning bolt icon buttons on each WOD card in WOD Library view - Teal lightning bolt icon buttons on each Movement card in Movements Library view - Quick Log dialog opens directly from cards without navigating to detail pages - Pre-populated forms with selected WOD or Movement data - Streamlined workout logging workflow from library browsing - **Quick Log Buttons on Detail Pages**: Enhanced WOD and Movement detail screens - Added prominent Quick Log buttons to WODDetailView and MovementDetailView - Pre-populated Quick Log dialogs with current item being viewed - Consistent user experience across all viewing contexts - **Admin User Management Dashboard**: Complete administrative control system for user accounts - Activated Admin User Management card in AdminView (`/admin`) - Full-featured user management UI at `/admin/users` route - User list table with pagination (50 users per page) and real-time search - Mobile-optimized table with individual labeled columns (no hover tooltips required): - **Details**: View comprehensive user information dialog - **Lock**: Unlock temporarily locked accounts from failed login attempts - **Enable**: Enable/disable user accounts with optional reason tracking - **Email**: Toggle email verification status manually - **Change Role**: Switch between "user" and "admin" roles - **Delete**: Permanently delete users with confirmation dialog - User details dialog showing all account information: - Email verification status with visual badges - Account status (Active/Disabled) with color coding - Role display with chips - Timestamps: created_at, last_login_at, email_verified_at, disabled_at - Disable reason display when applicable - Color-coded status indicators throughout (green/success, red/error, purple/admin, blue/user) - Confirmation dialogs for destructive actions (disable, delete) - Success/error messaging for all operations - Backend API endpoints from v0.4.6-beta now fully integrated with frontend ### Changed - **Icon Consistency**: Unified Quick Log iconography across the entire application - All Quick Log buttons now use `mdi-lightning-bolt` icon (teal color) - Replaced `mdi-play-circle` icons in WorkoutsView template cards with lightning bolt - Consistent visual language for Quick Log feature throughout the app - Tooltips added to all Quick Log buttons for clarity - **User Management Table Structure**: Improved accessibility and mobile usability - Restructured "Actions" column into 6 individual labeled columns - Clear column headers eliminate need for hover tooltips on mobile devices - Centered icon buttons with consistent sizing and colors - Enhanced visual feedback for current state (locked/unlocked, enabled/disabled, verified/unverified) ### Fixed - **Vuetify Layout Issues**: Fixed bottom navigation layout conflicts - Restructured WODLibraryView, MovementsLibraryView, and AdminUsersView container hierarchies - Changed outer containers from `` to `
` to prevent layout system conflicts - Moved bottom navigation outside scrollable content containers - Eliminated "Could not find layout item 'bottom-navigation'" console errors - Fixed scroll behavior with proper `overflow-y: auto` and `max-height` constraints - **Template Deletion Bug**: Fixed custom template deletion endpoint error - Corrected API endpoint from `DELETE /api/workouts/{id}` to `DELETE /api/templates/{id}` - Resolved 500 Internal Server Error and "unauthorized workout access" issue - Custom workout templates now delete successfully ## [0.7.3-beta] - 2025-01-22 ### Added - **Quick Log on Performance Screen**: Complete Quick Log dialog integration on Performance view - Quick Log button now opens dialog directly on Performance screen (no navigation to Dashboard) - Pre-populates with the movement or WOD currently being viewed - User can change selection within dialog if needed - Automatically refreshes performance data after successful submission - Maintains user context and viewing state ### Fixed - **Performance Chart Sorting**: Fixed chronological ordering for workouts on the same date - Implemented two-level sorting: primary by `workout_date`, secondary by `created_at` timestamp or `id` - Ensures newest entries appear on the right side of charts (chronological order) - Prevents multiple same-day workouts from appearing in database order - Applied to both movement and WOD performance charts ## [0.7.2-beta] - 2025-01-22 ### Added - **1RM (One-Rep Max) Calculation and Display**: Complete system for tracking estimated strength maximums - **Backend**: Enhanced `/api/performance/movements/{id}` endpoint to calculate and return 1RM data - Added `MovementPerformanceWithRM` response type with `calculated_1rm` and `formula` fields - Returns `best_1rm` and `best_formula` for overall best performance - Uses hybrid formula approach from `pkg/prmath/one_rm.go`: - 1 rep = Actual weight - 2-10 reps = Epley formula: `1RM = weight × (1 + reps/30)` - 11+ reps = Wathan formula: `1RM = (100 × weight) / (48.8 + 53.8 × e^(-0.075 × reps))` - **Frontend - Best 1RM Card**: New stat card displaying estimated 1RM - Prominent gold-colored display (#ffc107) with arm-flex icon - Shows rounded 1RM value with "lbs (estimated)" label - Displays formula chip indicating calculation method - Only appears when weight/reps data is available - **Frontend - Performance History**: Enhanced history entries with 1RM estimates - Shows "Est. 1RM: XXX lbs" in gold text for each performance record - Appears alongside date and notes in subtitle line - **Frontend - Chart Enhancements**: Dual-line performance chart - Added dashed gold line showing estimated 1RM trend - Original solid dark line shows actual weight lifted - Legend automatically displays when 1RM data exists - Enhanced tooltips showing both actual weight and estimated 1RM with formula - Null value filtering prevents gaps in chart display - **Y-Axis Labels**: Added clear axis labels to all performance charts - Movement charts: "Weight (lbs)" - WOD charts: Dynamic labels based on score type (Time/Rounds/Weight) ### Fixed - **WOD Chart Rendering Issue**: Fixed canvas element not rendering on initial load - Moved `loadingPerformance = false` before chart rendering to ensure DOM updates - Added proper `await nextTick()` sequencing for canvas availability - Resolved null reference errors in WOD performance charts ### Changed - **Code Cleanup**: Removed debug console.log statements from PerformanceView - Removed WOD debug logging throughout fetchPerformanceData and renderWODChart - Cleaner console output in production ## [0.7.1-beta] - 2025-01-22 ### Fixed - **Wodify Import Date Issue**: Fixed performance charts showing all imported workouts as "today" instead of actual workout dates - Backend: Added `WorkoutDate` field to `UserWorkoutMovement` and `UserWorkoutWOD` domain models - Backend: Updated repositories to populate `workout_date` from `user_workouts.workout_date` join - Frontend: Changed PerformanceView to use `workout_date` instead of `created_at` for all date displays - Charts now correctly show historical dates (e.g., Jul 30, 2018) from Wodify CSV imports - History grouping and sorting now use actual workout dates ### Changed - **Performance Chart Date Display**: Charts now display full dates with year - X-axis labels show year: "Jul 30, 2018" instead of "Jul 30" - Hover tooltips display full date with year in title - Applied to both Movement and WOD performance charts - **Rep Scheme Filter Enhancement**: Improved dropdown filter in Performance view - Changed "All Reps" to simplified "All" option - "All" displays all weighted records regardless of rep scheme, sets, or other factors - Cleaner, more intuitive filtering experience ## [0.7.0-beta] - 2025-11-21 ### Added - **Wodify Performance Import System** - **Backend Components** - **Domain Models** (`internal/domain/wodify_import.go`) - `WodifyPerformanceRow` - Represents CSV row from Wodify export (19 columns) - `WodifyImportPreview` - Preview statistics and validation results - `WodifyImportResult` - Import completion statistics - `ParsedPerformanceResult` - Structured performance data after parsing - **Result Parser** (`internal/service/wodify_parser.go` - 273 lines) - 9 regex-based parsers for different result types: - `Weight` - Parses "3 x 10 @ 85 lbs" → sets, reps, weight - `Time` - Parses "5:30" (MM:SS) or "1:05:30" (HH:MM:SS) → seconds - `AMRAP - Rounds and Reps` - Parses "7 + 3" → rounds, reps - `AMRAP - Reps` - Parses "50 Reps" - `AMRAP - Rounds` - Parses "5 Rounds" - `Max reps` - Parses "3 x 8" (sets x reps) - `Calories` - Parses "133 Calories" - `Distance` - Parses "500 m" - `Each Round` - Parses "175 Total Reps" - `ParseDate()` - Handles MM/DD/YYYY and MM/DD/YY formats - `DetermineMovementType()` - Maps component type to movement type - `DetermineWODScoreType()` - Maps result type to WOD score type - **Import Service** (`internal/service/wodify_import_service.go` - 582 lines) - `PreviewImport()` - Analyzes CSV and returns preview without database changes - `ConfirmImport()` - Executes import with entity auto-creation - `parseCSV()` - Handles 19-column CSV with multi-line field support - `groupByDate()` - Groups performances by workout date - `getOrCreateMovement()` - Auto-creates missing movements - `getOrCreateWOD()` - Auto-creates missing WODs - `importWorkout()` - Creates UserWorkout with linked performances - PR preservation from Wodify export - **HTTP Handler** (`internal/handler/wodify_import_handler.go` - 107 lines) - `POST /api/import/wodify/preview` - Preview Wodify CSV import - `POST /api/import/wodify/confirm` - Execute Wodify CSV import - File size limit: 10MB - Multipart form-data with "file" field - **Frontend Integration** (`web/src/views/ImportView.vue`) - Added "Wodify Performance" import type with file-chart icon - **Wodify-Specific Preview UI:** - Summary stats: total rows, valid rows, workout dates, entities to create - New Entities card with chips showing movements and WODs to auto-create - Workout Summary table: date, movement count, WOD count, component types, PR flags - Gold trophy icons for workouts containing PRs - **Success Message:** - Displays: workouts created, performances, movements/WODs auto-created, PRs flagged - Format: "Workouts Created: 189 | Performances: 293 | Movements Created: 37 | WODs Created: 28 | PRs Flagged: 62" - **Documentation** - Updated `CLAUDE.md` with comprehensive Wodify import documentation - Real-world test results with 6+ years of data - Code examples for API usage - Domain model definitions ### Technical - Clean Architecture maintained: domain → service → handler pattern - CSV parsing with LazyQuotes and TrimLeadingSpace for robust handling - Regex-based result string parsing for data extraction - Date grouping logic to create cohesive UserWorkout entries - Auto-entity creation reduces manual data entry - PR flag preservation from source data - Build number incremented: 27 → 28 ### Testing - ✅ Preview import: Analyzed 293 performance entries, 189 unique dates - ✅ Confirm import: Successfully imported 6+ years of workout history (2018-2025) - 189 user workouts created (grouped by date) - 37 new movements auto-created - 28 new WODs auto-created - 293 performance entries - 62 PRs automatically flagged - ✅ Data persistence verified in database - ✅ Data appears correctly in GET /api/workouts - ✅ Round-trip import → export verified working - ✅ Graceful handling of invalid rows (1 row with missing component type/name) ### Bug Fixes - ✅ Investigated and resolved reported User Workouts Import bug - Testing confirmed feature working correctly - Data persists to database, appears in API, exports correctly - Bug report was false or already fixed in previous session --- ## [0.6.0-beta] - 2025-11-21 ### Added - **Database Backup/Restore System** - **Backend Service** (`internal/service/backup_service.go`) - `CreateBackup()` - Exports all tables to JSON + uploaded files to ZIP - `ListBackups()` - Returns metadata for all available backups - `GetBackupMetadata()` - Reads metadata from backup file - `DeleteBackup()` - Removes backup file with audit logging - `RestoreBackup()` - Full database restore from backup - Automatic table detection (skips tables that don't exist) - Multi-database support (SQLite, PostgreSQL, MySQL) - **API Endpoints** (`internal/handler/backup_handler.go`) - `POST /api/admin/backups` - Create new backup - `GET /api/admin/backups` - List all backups - `GET /api/admin/backups/{filename}` - Download backup file - `GET /api/admin/backups/{filename}/metadata` - Get backup metadata - `DELETE /api/admin/backups/{filename}` - Delete backup - `POST /api/admin/backups/{filename}/restore` - Restore from backup - All endpoints admin-only with authorization checks - Filename validation to prevent directory traversal attacks - **Frontend View** (`web/src/views/AdminBackupsView.vue`) - Backup list table with metadata (users, workouts, movements, WODs) - Create backup button with progress indicator - Download/delete/restore actions for each backup - Strong confirmation dialog for restore (warns about data loss) - Empty state for no backups - File size formatting and date/time display - **Backup Structure** - ZIP file containing `backup_data.json` with all table data - Includes uploaded files (profile pictures, etc.) in `uploads/` folder - Metadata: version, database driver, user counts, file size, created by - Stored in `/backups/` directory with .gitignore - **Documentation** - Updated ProfileView with "Database Backups" admin navigation link - Added `/admin/backups` route to router - Created `backups/.gitignore` to prevent backup files from being committed ### Technical - Clean Architecture maintained: domain → service → handler pattern - Audit logging for backup creation, deletion, and restore operations - Transaction-based restore to ensure data consistency - Automatic cleanup of existing data before restore - Security: Admin-only access, filename validation, token-based auth - Build number incremented: 24 → 25 ### Testing - ✅ Create backup: Successfully generates 1.7MB ZIP file - ✅ List backups: Returns metadata with correct statistics - ✅ Download backup: Serves ZIP file for download - ✅ Delete backup: Removes file and logs action - ⚠️ Restore backup: Tested manually (destructive operation) --- ## [0.5.1-beta] - 2025-11-21 ### Added - **Import/Export System (Phase 1 & 2 - COMPLETE)** - **WOD Export** (`GET /api/export/wods`) - CSV format with all WOD fields - Query parameters for filtering: `include_standard`, `include_custom` - Successfully tested with all standard WODs - **Movement Export** (`GET /api/export/movements`) - CSV format with all movement fields - Query parameters for filtering: `include_standard`, `include_custom` - Successfully tested with all standard movements - **User Workouts Export** (`GET /api/export/user-workouts`) - JSON format with full nested data structure - Optional date range filtering: `start_date`, `end_date` - Includes metadata: user_email, export_date, version, total_count - Nested workout data: movements, WODs, performance metrics - **WOD Import** (`POST /api/import/wods/preview`, `POST /api/import/wods/confirm`) - Preview endpoint with validation before committing - CSV validation: source, type, regime, score_type enums - Duplicate detection and handling - Options: skip_duplicates, update_duplicates - Successfully tested: created custom WOD - **Movement Import** (`POST /api/import/movements/preview`, `POST /api/import/movements/confirm`) - Preview endpoint with validation - CSV validation: type enum (weightlifting, cardio, gymnastics, bodyweight) - Duplicate detection - Successfully tested: created 2 custom movements - **User Workouts Import** (`POST /api/import/user-workouts/preview`, `POST /api/import/user-workouts/confirm`) - Preview endpoint working correctly ✅ - Confirm endpoint working correctly ✅ - JSON parsing and validation - Nested data handling (movements, WODs) - Auto-creation of missing movements and WODs - Default workout_name generation for ad-hoc workouts - **Frontend Views** - `ExportView.vue` at `/settings/export` - Data type selector (WODs, Movements, User Workouts) - Format handling (CSV for WODs/Movements, JSON for User Workouts) - Options: Include standard items, include custom items - Date range picker for User Workouts - Export button triggers file download - `ImportView.vue` at `/settings/import` - File upload with drag-and-drop support - Supported formats info (CSV, JSON) - Preview table showing parsed data with validation status - Validation errors display (red highlights for invalid rows) - Import statistics (total, valid, invalid, duplicates) - Import options: Skip duplicates, Update duplicates - Confirm and Cancel buttons - Fixed axios import to use authenticated instance (was causing 401 errors) - **Backend Services (1,691 lines total)** - `internal/service/export_service.go` (385 lines) - `internal/service/import_service.go` (829 lines) - `internal/handler/export_handler.go` (178 lines) - `internal/handler/import_handler.go` (299 lines) - All routes wired up in `cmd/actalog/main.go` - **Documentation** - Created `docs/ROADMAP.md` with detailed development plan - Updated `docs/TODO.md` with completion status - Testing results: 6/6 features working (100%) ### Fixed - **User Workouts Import Persistence Bug** (CRITICAL - Build 22) - **Location:** `internal/service/import_service.go:760-776` - **Issue:** Import reported success but workouts didn't appear in API responses - **Root Cause 1:** Missing `WorkoutType` field when creating UserWorkout struct - Field was present in JSON import data but not being set on the domain object - Caused workout_type column to be NULL in database - **Root Cause 2:** Missing `workout_name` default value for ad-hoc workouts - Ad-hoc workouts (without workout_id) require workout_name to be queryable - `GetByIDWithDetails()` throws error when both workout_id and workout_name are NULL - This caused API to return empty array even though workouts existed in database - **Fix Applied:** - Added `WorkoutType: workoutData.WorkoutType` to UserWorkout struct creation - Added default workout_name generation: `fmt.Sprintf("Workout %s", workoutDate.Format("2006-01-02"))` - Ensures all ad-hoc workouts have a valid workout_name for retrieval - **Testing Results:** - Before: Database had workouts but API returned 0 ❌ - After: Database has workouts AND API returns all workouts ✅ - Verified via database query and `/api/workouts` endpoint ### Changed - Version remains 0.5.0-beta (will bump to 0.5.1-beta on release) - Build number incremented: 20 → 22 - Import/Export system is now 100% functional (6/6 features working) ### Testing - ✅ WOD export/import round-trip tested successfully - ✅ Movement export/import round-trip tested successfully - ✅ User Workouts export tested successfully - ✅ User Workouts import preview tested successfully - ✅ User Workouts import confirm tested successfully (bug fixed) ### Technical - Clean Architecture maintained throughout implementation - Multi-database support (SQLite, PostgreSQL, MySQL) - CSV parsing with validation - JSON nested data handling - Duplicate detection algorithms - Authorization checks (users can only import/export their own data) - Rate limiting on import endpoints - File size limits (max 10MB) --- ## [0.4.6-beta] - 2025-11-15 ### Added - **Admin User Management Enhancements** - Delete user functionality with confirmation dialog (`DELETE /api/admin/users/{id}`) - Prevents admin from deleting their own account - Displays what will be deleted: profile, workouts, PRs, performance history - Audit logging for all user deletion operations - Service layer validation with authorization checks - **Session Management System** - List active sessions endpoint (`GET /api/sessions`) - Revoke specific session endpoint (`DELETE /api/sessions/{id}`) - Revoke all sessions endpoint (`POST /api/sessions/revoke-all`) - Session ownership validation (users can only manage their own sessions) - Audit logging for session revocation events - Service layer: `GetActiveSessions()`, `RevokeSession()`, `RevokeAllSessions()` - Handler layer: `SessionHandler` with list, revoke, and revoke-all operations - All endpoints require authentication - **User Repository Enhancements** - Fixed `List()` method to include all admin-relevant fields - Now properly selects: email_verified, account_disabled, locked_at, locked_until, disable_reason - Proper NULL handling for all nullable timestamp and string fields ### Fixed - **Admin Users View** - Icons now correctly display current user state (verified, locked, enabled, role) - Dynamic icon shapes and colors based on state - Enhanced tooltips showing current state explicitly - All toggles (verify email, lock, enable, role, delete) now work correctly ### Changed - Version bumped to 0.4.6-beta - Build number reset to 1 for new minor version - Admin panel now has full CRUD capabilities for user management ### Technical - Clean Architecture maintained: service → repository pattern - Audit trail for all administrative actions - Service layer performs authorization checks before operations - CASCADE delete configured for related user data - Security: token ownership validation prevents unauthorized access ## [0.4.5-beta] - 2025-11-14 ### Added - **Admin Data Cleanup: Edit WOD Records** - New API endpoint: `PUT /api/admin/data-cleanup/wod-record/{id}` for updating individual WOD records - Backend validation ensures updates match WOD score_type requirements - Clickable mismatch cards in admin cleanup view open edit dialog - Edit dialog with score_type-specific form fields (only shows relevant fields) - Hours, Minutes, Seconds input for Time-based WODs - Rounds and Reps input for Rounds+Reps WODs - Weight input for Max Weight WODs ### Fixed - **Quick Log Form (Dashboard)** - Fixed Quick Log to respect WOD score_type constraints - Score type now auto-populates from selected WOD (read-only) - Only shows fields relevant to the WOD's score_type - Time-based WODs now support HH:MM:SS format (was only showing seconds) - Added reactive watchers to auto-calculate total seconds from HH:MM:SS inputs - **Log Workout Form** - Fixed score_type check from `'Time'` to `'Time (HH:MM:SS)'` - Added hours field to time inputs (now fully supports HH:MM:SS) - Updated time calculation logic to include hours in total seconds and score_value formatting - **Admin Cleanup View** - Removed duplicate bottom navigation bar from admin cleanup view ### Changed - All workout entry and edit forms now enforce WOD score_type constraints - Time-based WODs consistently use HH:MM:SS format across all forms - Version bumped to 0.4.5-beta build 1 ### Technical - Frontend conditional rendering prevents invalid field combinations based on score_type - Backend validation in `UpdateWODRecord` ensures data integrity - Multi-layer constraint enforcement: frontend UX + backend validation - Clean Architecture maintained: handler → service → repository layers ## [0.4.4-beta] - 2025-11-14 ### Added - **Retroactive PR Detection System** - Service method `RetroactivelyFlagPRs()` to analyze all historical workouts chronologically - Automatically flags PRs based on historical max values for movements and WODs - Processes workouts in chronological order, tracking max weights, best times, and best rounds+reps - Repository methods: `UpdatePRFlag()` for both movements and WODs - API endpoint: `POST /api/workouts/retroactive-flag-prs` (authenticated) - Command-line script `scripts/retroactive_prs.go` for direct database PR flagging - Returns count of movement PRs and WOD PRs flagged ### Fixed - PR detection now works for historical workouts logged before PR system was implemented - Personal Records view now displays PRs from all workouts, not just newly logged ones - Resolved issue where existing workouts had `is_pr = 0` even when they contained record performances ### Technical - Chronological processing ensures PRs are correctly identified based on order of performance - In-memory tracking of max values during processing to avoid multiple database queries - Multi-database support (SQLite, PostgreSQL, MySQL) for PR flag updates - Clean Architecture maintained: domain interfaces → repository implementation → service logic → handler/script ### Changed - Version bumped to 0.4.4-beta across all version files (pkg/version/version.go, web/package.json) --- ## [0.4.3-beta] - 2025-01-14 ### Changed - **UI Spacing Improvements**: Reduced whitespace and padding throughout the application - Reduced top margin from 36px to 5px on all main views (Dashboard, Profile, Performance, Workouts) - Reduced card padding: `pa-4` → `pa-2`, `pa-3` → `pa-2`, `pa-2` → `pa-1` - Reduced section margins: `mb-3` → `mb-2`, `mb-2` → `mb-1` - Reduced form field spacing from `mb-2` to `mb-1` - Removed top padding from main containers (`pt-0`) - Changed border radius from `rounded="lg"` to `rounded` for tighter appearance - Applied changes across Dashboard, Profile, Performance, and Workouts views - Result: More compact, efficient use of screen space on mobile devices ## [0.4.2-beta] - 2025-01-14 ### Added - **Version and Build Display**: Added version and build number display in Profile screen - Created new version display card at top of Profile screen - Shows full version (e.g., "0.4.2-beta+build.1") and build number - Backend exposes `/api/version` endpoint (public, no auth required) - Returns `version`, `build`, `fullVersion`, and `app` fields - Frontend fetches version info on Profile page load - **Automatic Build Number Increment System** - Created `scripts/increment-build.sh` for automatic build number management - Updated `Makefile` to auto-increment build on every `make build` - Build number stored in `pkg/version/version.go` as `Build` constant - Added `FullVersion()`, `BuildNumber()`, and `FullString()` functions - Format: `Major.Minor.Patch-PreRelease+build.N` (e.g., "0.4.2-beta+build.1") ### Changed - Version endpoint moved from `/version` to `/api/version` for Vite proxy compatibility - Updated `CLAUDE.md` with comprehensive Build Number Auto-Increment documentation ## [0.4.1-beta] - 2025-01-14 ### Fixed - **Quick Log movement search**: Fixed autocomplete not displaying movements in Quick Log dialog - Added loading states for movements and WODs - Added auto-select-first for better search UX - Added search icon to match design patterns - Added console logging for debugging data loading - **Localhost hardcoded URLs**: Fixed profile pictures and assets not working outside of localhost - Created `web/src/utils/url.js` with dynamic URL resolution utilities - `getApiBaseUrl()` - Environment-aware API base URL - `getAssetUrl()` - Converts relative paths to absolute URLs - `getProfileImageUrl()` - Specifically handles profile image URLs - Updated `web/src/stores/auth.js` to use new URL utilities - Updated `web/src/views/ProfileView.vue` to use new URL utilities - Fixed `web/src/views/VerifyEmailView.vue` to use relative URLs - Added `/uploads` proxy to Vite dev server configuration - **Axios configuration**: Changed baseURL to use relative URLs to leverage Vite proxy in development ### Added - Created `web/.env.example` documenting `VITE_API_BASE_URL` environment variable - Added comprehensive URL utility functions for production deployments ### Changed - Quick Log dialog now opens immediately and fetches data in background for better UX - Updated Vite proxy configuration to handle both `/api` and `/uploads` routes ## [0.4.0-beta] - 2025-01-13 ### Added - Multi-Database Support - **Multi-database support**: SQLite, PostgreSQL, and MySQL/MariaDB - **Database migration system** with version tracking and rollback support - Database-agnostic DSN builder - Driver-specific schema generation (SQLite, PostgreSQL, MySQL) - Comprehensive DATABASE_SUPPORT.md documentation - Support for database-agnostic migrations with driver parameter ### Added - Workout Logging (Backend Complete) - **Workout logging functionality** with complete CRUD operations - **Movement database** with 82 standard CrossFit movements (auto-seeded) - **Progress tracking** by movement for PR analysis - API endpoints for workout management: - POST /api/workouts - Create workout with movements - GET /api/workouts - List workouts with pagination and date filtering - GET /api/workouts/{id} - Get workout details - PUT /api/workouts/{id} - Update workout - DELETE /api/workouts/{id} - Delete workout (cascade deletes movements) - GET /api/progress/movements/{movement_id} - Track performance history - Movement management API endpoints: - GET /api/movements - List standard movements - GET /api/movements/search - Search movements by name - GET /api/movements/{id} - Get movement details - POST /api/movements - Create custom movement ### Added - Design Refinements (Planned for v0.3.0) **Refined design decisions documented** through user consultation (not yet implemented): **Email Verification System:** - Optional email verification with feature unlock approach - Users can immediately use core features without verification - Email verification unlocks leaderboard participation and data export - Verification email sent on registration with resend capability - Added `email_verified` and `email_verified_at` fields to users table **Personal Records (PR) Tracking:** - Auto-detection system for PRs: - Highest weight for strength movements (per user, per movement) - Fastest time for time-based WODs (per user, per WOD) - Most rounds+reps for AMRAP WODs (per user, per WOD) - Manual PR flag/unflag capability for user corrections - PR badges displayed on workout cards in dashboard and history - PR indicators (⭐) shown in movement history lists - Added `is_pr` field to `workout_wods` and `workout_strength` tables **Leaderboard System with Scaled Divisions:** - Three-division leaderboard system: - **Rx (As Prescribed)**: Workout performed exactly as specified - **Scaled**: Modified workout (lighter weight, fewer reps, substitute movements) - **Beginner**: Simplified version for newer athletes - Users self-select division when logging WOD scores - Separate leaderboards for each division to ensure fair comparisons - Global leaderboards for standard benchmark WODs - Email verification required for leaderboard participation - Added `division` field to `workout_wods` table **Hybrid Workout Template System:** - Users can use pre-defined WODs and admin-created templates - Users can create and save their own custom workout templates - "Save as Template" option when logging workouts - Template management UI for create, edit, delete operations - Both standard and custom content searchable and filterable **Hybrid Movement/WOD Libraries:** - Pre-defined library of standard CrossFit movements and WODs - Users can add custom movements and WODs - `is_standard` flag distinguishes pre-defined vs. user-created content - Standard content cannot be edited by regular users - Added `is_standard` field to `wods` and `strength_movements` tables **Workout Scheduling:** - Users can schedule workouts for future dates - Calendar view distinguishes scheduled vs. completed workouts - "Complete Scheduled Workout" flow for pre-planned training - No push notifications initially (infrastructure ready for future) **Performance Analytics:** - Weight progression charts for strength movements - Workout frequency heatmap showing consistency and streaks - WOD leaderboards with division filters - Focus on three primary visualizations **Import/Export Enhancements:** - Support for three formats: CSV, JSON, and Markdown - CSV for spreadsheet compatibility and data analysis - JSON for complete structured backup/restore - Markdown for formatted workout reports - Date range selection for partial exports - Data type selection (Workouts, WODs, Movements, Profile) **Data Sync Strategy:** - "Last write wins" conflict resolution for offline sync - Most recent timestamp takes precedence - Suitable for single-user workout logging scenarios - Sync status indicator for pending operations **User Roles:** - Simple two-tier system: regular users and admins - First user becomes admin automatically - No coach or gym owner roles in initial version ### Added - Database Schema Design (Planned for v0.3.0) - **Major schema redesign** based on logical data model requirements (documented but not yet implemented) - New `wods` table for predefined CrossFit workouts with comprehensive attributes: - Source (CrossFit, Other Coach, Self-recorded) - Type (Benchmark, Hero, Girl, Notables, Games, Endurance, Self-created) - Regime (EMOM, AMRAP, Fastest Time, etc.) - Score Type (Time, Rounds+Reps, Max Weight) - Description, URL, and notes fields - New `user_workouts` junction table linking users to workout instances on specific dates - New `workout_wods` junction table linking workouts to WODs with scoring - New `user_settings` table for user preferences (theme, notifications, export format) - New `audit_logs` table for audit trail and accountability - Added `updated_by` tracking to all entities for audit purposes ### Changed - Database Schema Design (Planned for v0.3.0) - **Workouts** are now reusable templates (not user-specific instances) - Renamed `movements` table to `strength_movements` - Added `movement_type` to strength_movements (weightlifting, cardio, gymnastics) - Renamed `workout_movements` to `workout_strength` - Removed user-specific fields from workouts table (user_id, workout_date, workout_type) - Updated ERD to reflect many-to-many relationships properly ### Changed - Multi-Database Support - Updated migration system to accept driver parameter for database-agnostic migrations - Improved table existence checking across all database types - Enhanced schema creation with database-specific SQL dialects ### Migration Required (Future Work) - Database migration from v0.1.0 to v0.3.0 will be needed when implementing v0.3.0 - See DATABASE_SCHEMA.md for planned migration steps - Backend domain models will need updates - API endpoints will need refactoring for new structure ### UI Updates - Dashboard Redesign - New Dashboard UI matching design specifications - Calendar component showing monthly workout activity - Recent workouts cards with grouped display - Top app bar with ActaLog logo and current date - Unified bottom navigation across all authenticated views - Avatar support for user profile icon - Workout badge for Personal Records (PRs) - Complete Dashboard redesign with calendar view - Moved header and bottom navigation to App.vue for consistency - Updated color scheme to match brand guidelines - Improved mobile-first responsive design - Enhanced bottom navigation with better iconography ### Documentation - **Reorganized app navigation structure** - Settings Menu as central hub - Added comprehensive "Screens & Navigation Flow" section to REQUIREMENTS.md - **33 core screens** defined with routes, purposes, and components - Settings Menu flyout accessed from user avatar - Management screens for WODs, Strength Movements, and Workout Templates with full CRUD operations - Import/Export data screens - App Preferences screen - Navigation flow diagrams - Screen interaction patterns - PWA-specific screens (install prompt, offline indicator) - Added `birthday` field to User profile ### Planned - Implement database migration scripts for v0.3.0 schema - Update backend domain models for new schema - Seed data for standard WODs and movements - Connect frontend to workout logging APIs - Workout templates and named WOD database - Charts and graphs for progress visualization - Push notifications for workout reminders - Web Share API integration - Implement all 33 screens defined in screen inventory: - Management screens for WODs (List, Create, Edit with CRUD operations) - Management screens for Strength Movements (List, Create, Edit with CRUD operations) - Management screens for Workout Templates (List, Create, Edit with CRUD operations) - Import/Export data screens - Settings Menu flyout implementation - First-user-as-admin logic - Configurable registration control (ALLOW_REGISTRATION) - SQLite database with auto-initialization - PostgreSQL and MariaDB support - Database schema with users, workouts, movements, and workout_movements tables - Bcrypt password hashing (cost factor 12) - CORS middleware with configurable origins - Request logging middleware - Health check endpoint (`/health`) - Version endpoint (`/version`) - Docker and docker-compose configuration - Makefile for development workflow - Windows batch script (`build.bat`) for Windows users - Comprehensive documentation: - README.md with quick start guide - ARCHITECTURE.md with Clean Architecture patterns - DATABASE_SCHEMA.md with ERD diagrams - SETUP.md for local and Docker development - REQUIREMENTS.md with user stories - AI_INSTRUCTIONS.md for development guidelines - Frontend views: - Login and registration pages - Dashboard with bottom navigation - Workout logging form (matching design) - Workouts history view - Performance tracking view - Profile and settings views - 404 error page - Vue Router with authentication guards - Pinia state management for auth - Axios HTTP client with interceptors - Custom ActaLog theme with design colors - Mobile-first responsive design - ESLint 9 with flat config format - Prettier code formatting - golangci-lint configuration - Version management system (v0.1.0-alpha) ### Fixed - Windows build permission issues (uses project-local cache) - SQLite driver name corrected from 'sqlite' to 'sqlite3' - npm dependency deprecation warnings - esbuild security vulnerability - ESLint 8 to ESLint 9 migration - CORS configuration for development ### Security - JWT token generation and validation - Password hashing with bcrypt - SQL injection prevention via parameterized queries - CORS origin whitelisting - Secure defaults in configuration - No sensitive data in error responses ### Changed - Updated all npm dependencies to latest versions - Migrated from ESLint 8 to ESLint 9 - Updated Vite to version 6 - Updated Vue.js to version 3.5 - Updated Vuetify to version 3.7 ### Developer Experience - Hot reload support for frontend (Vite) - Clean build artifacts with `make clean` - Formatted code with `make fmt` - Linting with `make lint` - Testing support with `make test` - Docker support for easy deployment - Cross-platform build scripts (Makefile + build.bat) ## [0.3.1-beta] - 2025-11-10 ### Added - **Email Verification System (Complete)** - Database migration v0.3.1 adding `email_verified` and `email_verified_at` columns to users table - Backend API endpoints: `GET /api/auth/verify-email`, `POST /api/auth/resend-verification` - Email service with SMTP integration for sending verification emails - Styled HTML email templates with verification links - 24-hour token expiration with secure token generation (crypto/rand) - Single-use verification tokens (marked as used after verification) - Repository layer: `CreateVerificationToken()`, `GetVerificationToken()`, `MarkTokenAsUsed()` - Service layer: `SendVerificationEmail()`, `VerifyEmailWithToken()`, `ResendVerificationEmail()` - Handler layer: `VerifyEmail()`, `ResendVerification()` with proper error handling - **Email Verification Frontend** - VerifyEmailView component at `/verify-email?token=...` route - Automatic email verification on page load - Loading, success, and error states with appropriate messaging - Handles expired, invalid, and already-used tokens - Updates auth store user object on successful verification - ResendVerificationView component at `/resend-verification` route - Email input form to request new verification email - Success confirmation displaying the email address - Comprehensive error handling (404, 400, network errors) - Updated RegisterView to show verification success message - No longer auto-redirects to dashboard after registration - Displays sent email address and 24-hour expiration notice - Link to resend verification if email not received - Dashboard verification status banner - Warning alert for users with unverified emails - Prominent "Resend Email" button - Closable alert for better UX ### Changed - User registration flow now includes email verification step - Users receive verification email immediately after registration - Dashboard shows verification reminder until email is verified - Router updated with `/verify-email` and `/resend-verification` routes - Navigation guards allow verify-email access for both authenticated and unauthenticated users - Version bumped to 0.3.1-beta across all version files ### Technical - Email verification tokens stored in `email_verification_tokens` table - Tokens generated using crypto/rand (32 bytes hex-encoded) for security - SMTP configuration via environment variables (EMAIL_FROM, SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS) - HTML email template with inline styles for cross-client compatibility - Authorization checks ensure users can only resend verification for their own email - Frontend build: 618 modules, 47 PWA cache entries - Multi-database support (SQLite, PostgreSQL, MySQL) for email_verified field ## [0.3.0-beta] - 2025-11-10 ### Added - **Personal Records (PR) Tracking System** - Automatic PR detection when logging workouts (weight-based comparison) - Manual PR flag toggle via API endpoint - Database migration v0.3.0 adding `is_pr` column to workout_movements - Multi-database support (SQLite, PostgreSQL, MySQL) for PR field - New domain models: `PersonalRecord` struct and `IsPR` field in `WorkoutMovement` - Repository methods: `GetPersonalRecords()`, `GetMaxWeightForMovement()`, `GetPRMovements()` - Service layer methods: `DetectAndFlagPRs()`, `GetPersonalRecords()`, `TogglePRFlag()` - API endpoints: `GET /api/workouts/prs`, `GET /api/workouts/pr-movements`, `POST /api/workouts/movements/:id/toggle-pr` - Gold trophy badges (mdi-trophy) on workout cards containing PRs - Individual PR indicators next to movements in workout lists - Dedicated PR History page at `/prs` route showing recent PRs and all-time records - Visual distinction with gold/amber color scheme (#ffc107) for PR indicators - **Password Reset Frontend (Part 3/3)** - Forgot Password view with email submission form - Reset Password view with token validation and new password form - Router configuration for `/forgot-password` and `/reset-password/:token` routes - "Forgot password?" link added to Login view - Integration with backend password reset API endpoints - Success/error messaging for user feedback ### Changed - Integrated PR detection into workout creation workflow - Updated RecentWorkoutsCards component to display PR badges - Updated WorkoutsView to show PR indicators on individual movements - Enhanced router with authentication guards for password reset routes - Version bumped to 0.3.0-beta across all version files ### Technical - PR auto-detection algorithm: compares current weight against previous max for each movement - Authorization checks on PR flag toggle to ensure workout ownership - Backward-compatible database migration with DEFAULT values - Clean Architecture maintained: domain → repository → service → handler layers - All PR queries include proper user scoping for security ## [0.2.0-beta] - 2025-11-06 ### Added - Complete workout CRUD functionality with RESTful API endpoints - Workout repository layer for database operations - Movement repository with 31 seeded standard CrossFit movements - Workout movement repository for linking movements to workouts - Workout service layer with business logic and authorization - JWT authentication middleware for protected routes - Dashboard with real-time workout statistics (total workouts, monthly count) - Recent workouts display on dashboard (last 5 workouts) - Workout saving functionality from Log Workout screen - Workouts list view with movement details - Autocomplete/search functionality for movement selection - Custom movement item templates showing type and icons - Modern UI design with cyan accent color (#00bcd4) - Dark navy header (#2c3e50) across all views - Responsive scrolling with fixed header and footer navigation ### Changed - Updated LogWorkoutView with functional save button and API integration - Updated WorkoutsView to fetch and display real workout data - Updated DashboardView to show live statistics from API - Updated PerformanceView with searchable movement dropdown - Improved font readability with darker colors (#1a1a1a) - Reduced vertical spacing for better mobile fit - Changed v-select components to v-autocomplete for better UX - Enhanced workout responses to include full movement details ### Fixed - Cache directory creation issue in Makefile (mkdir -p added to run/dev targets) - SQLite driver name changed from "sqlite" to "sqlite3" in config - Workout save button now properly calls API endpoint - Vertical scrolling enabled on all views - Content no longer runs off bottom of screen - Movement names now display correctly in workout lists ### Technical - Implemented Clean Architecture pattern (domain → repository → service → handler) - Added dependency injection for repositories and services - Integrated JWT token validation in middleware - Database seeding for standard movements on first run - Proper error handling and validation in API endpoints - User authorization checks in workout service layer ## [0.1.0-alpha] - 2025-11-05 ### Added - Initial project setup with Go backend and Vue.js frontend - User authentication with JWT tokens - Basic user registration and login endpoints - Database schema for users, workouts, movements, and workout_movements - SQLite and PostgreSQL database support - Vue.js frontend with Vuetify 3 UI framework - Vue Router setup with authentication guards - Pinia store for state management - Basic view scaffolding (Dashboard, Performance, Workouts, Profile, Login, Register) - Bottom navigation with mobile-first design - Clean Architecture folder structure - Configuration management with environment variables - Makefile for common development tasks - Documentation (README.md, ARCHITECTURE.md, AI_INSTRUCTIONS.md, DATABASE_SCHEMA.md) ### Technical - Go 1.24+ with Chi router - Vue 3 with Composition API - Vuetify 3 for UI components - Axios for HTTP requests - bcrypt for password hashing - JWT for authentication - SQLite3 driver integration --- ## Version History Format ### [Version] - YYYY-MM-DD #### Added New features that have been added to the project. #### Changed Changes in existing functionality. #### Deprecated Soon-to-be removed features. #### Removed Features that have been removed. #### Fixed Bug fixes. #### Security Security-related changes or fixes. --- **Current Version:** 1.2.1 **Schema Version:** v0.32.0 (Coach Role & Role Rename) **Last Updated:** 2026-04-01