Files
kandev/docs/specs/system-page/system-design/system-data-storage-pages.md
T

185 lines
11 KiB
Markdown

---
status: current
system: system-page
requirements:
- REQ-SYSTEM-PAGE-DATA-STORAGE-PAGES-001
- REQ-SYSTEM-PAGE-DATA-STORAGE-PAGES-002
- REQ-SYSTEM-PAGE-DATA-STORAGE-PAGES-003
- REQ-SYSTEM-PAGE-DATA-STORAGE-PAGES-004
---
# System Data and Storage Pages System Design
## Purpose and boundaries
System-page owns the composition and maintenance presentation of these two routes.
This revision describes the implemented [settings storage tabs package](../../../plans/settings-storage-tabs/plan.md).
The existing two-page split and the new tab allocation are current.
The [UI header-tab design](../../ui/system-design/settings-header-tabs.md) owns the reusable interaction.
Office owns retention policy, deletion eligibility, preview markers, and count semantics.
Those backend contracts remain unchanged.
## Requirement mapping
| Requirement | Design section |
| --- | --- |
| REQ-SYSTEM-PAGE-DATA-STORAGE-PAGES-001 | Route composition and compatibility |
| REQ-SYSTEM-PAGE-DATA-STORAGE-PAGES-002 | Route composition and compatibility; State and permissions |
| REQ-SYSTEM-PAGE-DATA-STORAGE-PAGES-003 | Retention controls; Temporary files and compaction |
| REQ-SYSTEM-PAGE-DATA-STORAGE-PAGES-004 | Retention status |
## Route composition and compatibility
`src/settings-routes.tsx` retains both canonical paths.
`SystemRouteShell` and `SystemPageShell` pass an optional tabs slot to the existing `SettingsPageHeader`.
Each page owns one shared Tabs root around its header and content.
Use dedicated route compositions when the shared root must contain the shell itself.
Do not put a second page heading or tab strip inside the content.
| Path | Query | Content order |
| --- | --- | --- |
| `/settings/system/data-storage` | `tab=database` (default) | DatabaseStatsCard, ToolPayloadRetentionCard, BackupsTable |
| `/settings/system/data-storage` | `tab=logs` | LogViewer |
| `/settings/system/storage` | `tab=host` (default) | StorageMaintenanceSettings |
| `/settings/system/storage` | `tab=office-retention` | Retention status, retention policy |
`DataLogsSettings` is the Data & Logs tab composition.
`StorageSettings` wraps existing host maintenance and Office retention.
Settings menu labels and breadcrumb paths remain unchanged.
Storage description includes host cleanup and Office history retention.
In `lib/settings-discovery/catalog/system.ts`, move the retention entry to the Storage discovery parent.
Keep stable target IDs and add tab queries to all affected entries.
Backups and compaction resolve to Database, log results to Logs, and all existing host targets to Host.
A recognized target fragment selects its owning tab before focus/highlight.
A manually selected tab removes the old target fragment so it cannot override later navigation.
Legacy routes resolve as follows:
- `/settings/system/database` -> Data & Logs, Database.
- `/settings/system/backups` -> Data & Logs, Database, existing backups target.
- `/settings/system/logs` -> Data & Logs, Logs.
- Old Data & Logs retention fragments -> Storage, Office retention, same retention target.
Unrelated query parameters survive redirects. Legacy redirects use replacement navigation.
An unqualified Data & Logs link still opens Database because it cannot identify a historical retention intent.
Update `internal/office/retention/health.go` `fixURL` to
`/settings/system/storage?tab=office-retention` and update its focused tests.
Other backend behavior and health issue identities remain unchanged.
## State and permissions
The existing `SettingsSaveProvider` is keyed by pathname, not query.
Use the UI design's same-path tab replacement and retained stateful panels.
Keep contributors `system:storage-policy`, `system:retention`, and `system:tool-payload-retention` in their owning page.
Do not duplicate them or reset their dirty baselines on tab activation.
Visit panels lazily, then retain forms until route exit. The Logs panel mounts
`LogViewer` on first activation and keeps it mounted while hidden so an in-progress
diagnostic bundle can finish and download.
Existing ongoing maintenance/preparation jobs keep their current lifecycle when a form is hidden.
The floating Save changes control saves all dirty contributors on the page, including inactive panels.
Discard restores their authoritative baselines. Failed saves keep drafts and expose the existing error feedback.
Return to the affected panel without losing state. Cross-page changes retain the existing navigation guard.
Retain existing API role gates and read-only member surfaces.
Office retention remains admin-scoped even beside member-readable host information.
A failed Office request must not hide the Host tab or its permitted content.
## Retention controls
Refactor `retention-settings-card.tsx` into focused policy, status, and help components under the same system directory.
Keep `useRetentionSettings`, the settings wire types, and the save contributor contract.
Use stable technical IDs for test selectors and wire mapping, independently of translated display labels.
| Existing identity | Display label | Explanation |
| --- | --- | --- |
| `office_routine_runs` | Routine history | Routine activity, including skipped and coalesced executions |
| `runs` | Agent run history | Office agent runs |
| `run_events` | Run events | Timeline entries belonging to a run |
| `office_run_route_attempts` | Provider attempts | Provider/model routing attempts for a run |
| `office_run_skills` | Run skill records | Skill references associated with a run |
Use Minimum per routine for `routine_runs.floor_per_owner`.
Use Minimum per agent profile for `runs.floor_per_owner`.
Keep the enable switch, retention days, and minimums visible.
Place interval, batch limit, and all three warning thresholds in Advanced settings, initially collapsed.
Keep advanced fields in the draft while collapsed. Show validation errors outside the collapse and reveal the affected field.
The run-events threshold counts events only. Dependent records have no independent retention window or floor.
Remove the explicit `settingsControlClassName("h-11")` override from `NumberField`.
Use the shared sizing helper without a desktop height override.
Each numeric label has a focusable information button. Help covers meaning, limits, and zero-value behavior where supported.
Reuse the `SleepInhibitionInfoTooltip` interaction in `sleep-inhibition-settings.tsx`: Tooltip on fine pointers, Drawer via `useTouchDrawer` on touch.
The drawer has a label, close action, safe-area clearance, and focus return to its opener.
Keep a short visible statement: cleanup removes old finished history and related run details, while active work remains protected.
Helper icons contain secondary explanations; field labels and deletion consequences remain understandable without opening help.
## Retention status
Extract a pure status view-model helper and test it with the existing `RetentionStatus` shape.
The summary uses saved `status.settings`, never the unsaved draft.
The enabled badge means automatic deletion is configured; it does not imply a healthy last cleanup.
Do not show an invented next-run time or a persisted history. Last sweep data resets after server restart.
Render these sections in order:
1. Automatic cleanup enabled/disabled and the last recorded cleanup result/time.
2. Three stored-count summaries with translated labels, counts, and threshold states.
3. Expandable Cleanup details with per-category deletion/preview counts, provider attempts, run skill records, skips, and attribution.
Derive outcome from all reported table errors and both swept-table preview/backlog flags.
Any error produces a visible error outcome, while retaining committed counts from successful categories.
A preview in one category must not mask deletion in another. Show a mixed outcome when both occur.
Show backlog separately from errors and preview. Preview counts never count as deleted records.
A deletion total sums the five reported committed deletion counts and uses the unit records, never runs.
Preserve `not_computed`, fresh, and stale states independently per count.
A missing count shows unavailable, not zero. A stale count retains its last value and timestamp with a visible stale label.
Compare counts against saved thresholds using the backend's strict greater-than rule. Zero disables that threshold.
Stale values can say the last count exceeded a threshold but cannot claim current health.
Use one Updated timestamp only when all displayed measured counts have the same timestamp; otherwise keep per-count timestamps.
State that stored records include protected work and are not a deletion estimate.
Warnings, unknown-status notices, backlog, and errors remain visible when details collapse.
Details preserve unknown status values/counts, top routine ID/share, skip count/time, and per-category errors.
Raw diagnostic values can remain in details; normal titles and labels use product language.
No added network call, count scan, health metric, or history table is required.
## Temporary files and compaction
Rename the temporary-artifacts section to Temporary Kandev files through locale keys.
In `storage-policy-card.tsx`, explain registered diagnostic bundles and utility working folders.
Remove the repeated age sentence. Keep a concise visible stale-age/quarantine consequence next to the cleanup action.
Help explains that shared temporary folders and unrelated package caches are excluded from this provider.
Preserve the scheduled opt-in switch, manual action, disabled reasons, confirmations, and quarantine behavior.
Remove `max-w-3xl` from `ToolPayloadRetentionCard` and retain `min-w-0`.
The card fills the Database content row, while controls keep compact widths and wrap on phones.
Keep existing analysis, backup preparation, automatic compaction, manual compaction, and space-reuse explanations.
## Mobile design contract
The Settings index and full-height Settings surface remain the entry point and page scroll owner.
Header tabs move below the description. They remain inline because they choose the primary page content.
Phone retention status becomes a single-column list. Policy fields stack with labels, units, and 44px touch targets.
The primary settings action remains the existing floating Save changes control with safe-area clearance.
Help uses the shipped sleep-inhibition Drawer pattern; desktop uses hover/focus Tooltip.
No second mobile state model, hidden duplicate form, nested vertical scroll area, or new sidebar is introduced.
## Localization and documentation
All changed labels use `t()` or `Trans` with complete English, Portuguese, and Chinese catalogs.
Use `pnpm run i18n:zh-hant` for Traditional Chinese and verify the pseudo-locale.
Use locale-aware number/date formatting. Preserve internal IDs and wire keys.
Update `docs/public/operations.md` and applicable authentication navigation references when implementation ships.
Public docs remain current during this design-only change.
## Related decisions and contracts
- [Header tabs](../../../decisions/2026-09-15-settings-header-tabs.md)
- [Separate data/storage pages](../../../decisions/2026-09-03-separate-system-data-storage-pages.md)
- [Owned temporary files](../../../decisions/2026-08-08-owned-temp-artifact-cleanup.md)
- [Office retention operations](../../office/system-design/run-history-retention-operations.md)
- [Tool payload retention](tool-payload-retention.md)