ESLint
- Pinned eslint@^8 + eslint-config-next@^14 to match Next 14's `next lint`.
ESLint 9's flat-config breaks `next lint` for legacy projects.
- .eslintrc.json extends next/core-web-vitals; ignores tests/, scripts/,
prisma/data/, .next/, node_modules.
- 7 pre-existing warnings surfaced (exhaustive-deps + alt-text + img tag
in user-written components). Left as warnings — pre-existing, not
breaking. CI runs lint; warnings don't fail the job.
Server action tests (tests/actions-admin.test.ts, tests/actions-auth.test.ts)
- Vitest setup file (tests/helpers/setup-actions.ts) sets DATABASE_URL
to a per-process temp SQLite DB and runs `prisma db push` BEFORE
lib/prisma instantiates its global PrismaClient. Tests then call the
real server actions against an isolated DB.
- vi.mock + vi.hoisted to mock @/lib/auth.getCurrentUser, next/headers
cookies+headers, next/navigation redirect, next/cache revalidatePath.
- Coverage:
- admin: setUserAdmin (Forbidden, promote, last-admin demote refused,
demote-with-other-admin allowed), deleteUser (last-admin guard,
self-delete refused, cascading delete to exercises + workouts),
adminResetPassword (hash-and-revoke, short-password rejected).
- auth flows: signupAction (closed by default, opens-and-creates,
mismatched confirm rejected, short pwd rejected, malformed email
rejected, no email-enumeration leak), changePasswordAction
(rotate-and-revoke-others, wrong current pwd rejected, no-op pwd
rejected), deleteMyAccountAction (phrase required, password required,
last-admin refused, success cascades + clears cookie + redirects).
- Total suite: 34 tests, ~2s.
Export my data (/api/me/export + Settings -> Export my data)
- Downloads a JSON dump of every workout/set/exercise/program tied to
the user. Excludes password hash and sessions. Filename includes
email + date. content-disposition: attachment, no-store cache.
- Exported shape matches the underlying tables 1:1 so a future "import
my data" flow can round-trip without ambiguity.
Enriched /api/health
- Now reports: database.connected, database.journalMode (and walEnabled
shortcut), users count, instanceSettings.signupsOpen, library.available
+ sizeBytes. Surfaces a `warnings` array if journal_mode != 'wal' but
doesn't fail the check (app still works without WAL — just unsafe for
online backups). Returns 503 only on hard DB failure.
CHANGELOG.md
- Single Unreleased section documenting everything that will ship as
v1.0.0:1 once the maintainer drops a fresh /data snapshot. Added /
Changed / Removed / Compat-notes sections.