4.7 KiB
created, status, requirements, system_design, legacy_specs
| created | status | requirements | system_design | legacy_specs | ||
|---|---|---|---|---|---|---|
| 2026-08-27 | done |
|
|
Implementation Plan: Backup Location and Action Guidance
Overview
First, expose the absolute, resolved SQLite backup directory through database statistics. Then show that directory and add guidance to each backup row action.
The order establishes one server-owned path before the frontend renders it.
Scope
In scope
- Add the resolved SQLite backup directory to database statistics.
- Show the directory in the Backups section description.
- Add hover and focus tooltips to Download, Restore, and Delete.
- Keep action targets usable on coarse pointers.
- Prove desktop and mobile behavior with focused Playwright tests.
Out of scope
- Change backup storage, retention, or operation behavior.
- Add per-snapshot absolute paths to the backup list.
- Change backup permissions.
- Add PostgreSQL snapshot support.
- Change backup placeholders in other dialogs.
- Change public documentation that already describes the sibling directory.
Technical approach
Resolved directory
Add BackupDirectory to database.Stats in apps/backend/internal/system/database/stats.go.
Return the absolute backups sibling path for SQLite, resolving the derived
path with filepath.Abs, and an empty value for PostgreSQL.
Add backup_directory to DatabaseStats in apps/web/lib/types/system.ts.
Use the shared database state in data-logs-settings.tsx for the Backups description.
Remove the static BACKUP_DIR value from system-route-shell.tsx.
Keep BACKUP_SQL_COMMAND as a stable interpolated command value.
Action tooltips
Wrap each control in BackupRowActions with the shared Tooltip primitives.
Use localized operation-only labels as tooltip content. Keep each
snapshot-specific aria-label on the interactive control.
Add pointer-specific 44-pixel minimum dimensions to the three controls. Keep the current compact dimensions for fine-pointer desktop use.
Tests
apps/backend/internal/system/database/stats_test.gocovers default, custom, and non-SQLite directory values.apps/web/components/settings/system/system-route-copy.test.tscovers the exact dynamic English description.apps/web/components/settings/system/system-invisible-copy.test.tsxkeeps the resolved path literal in the pseudo-locale.apps/web/components/settings/system/backups-table.test.tsxcovers tooltip labels, accessible names, and touch-target classes.
E2E tests
apps/web/e2e/tests/system/backups-page.spec.tscovers the resolved path and all three hover tooltips forAC-SYSTEM-PAGE-BACKUP-GUIDANCE-001.1through.3.apps/web/e2e/tests/auth/mobile-system-data-storage-member-gating.spec.tscovers action size and horizontal containment for.4and.5.
Work orders
Verification results
Passed.
go test ./internal/system/database -run 'TestStats|TestHandleStats' -count=1passed (6 tests, including the relative-path absolute-directory regression).pnpm --filter @kandev/web exec vitest run components/settings/system/system-route-copy.test.ts components/settings/system/system-invisible-copy.test.tsx lib/api/domains/system-api.test.tspassed (52 tests, including the empty backup-directory regression).pnpm --filter @kandev/web exec vitest run components/settings/system/backups-table.test.tsxpassed (4 tests).pnpm --filter @kandev/web e2e:run tests/system/backups-page.spec.tspassed (3 Chromium tests).pnpm --filter @kandev/web e2e:run --project mobile-chrome tests/auth/mobile-system-data-storage-member-gating.spec.tspassed (2 mobile Chromium tests).pnpm --filter @kandev/web run typecheckpassed.pnpm --filter @kandev/web run i18n:checkpassed with the repository's existing advisory orphan-catalog warnings.python3 scripts/lint-spec-files.py --allpassed.git diff --checkpassed.- Review remediation passed: the backend resolves the derived directory with
filepath.Absand returns an error if resolution fails; the desktop E2E test independently asserts that the API value is absolute and matches the database-path sibling.
Risks
- A frontend path reconstruction can break Windows separators. The backend must own the derived value.
- A second database hook can send duplicate requests. The section must use the existing shared state.
- A tooltip wrapper can change link composition. The download anchor must remain the interactive element.
- Long filenames can widen a tooltip or the table. Both surfaces need wrapping and containment checks.