mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-16 05:13:36 +00:00
draft: database layer refactor (#1054)
* feat(sshid) - sshid.io equivalent for termix (#919) * feat(ssh-id): database schema, migrations and field encryption Adds ssh_identities, ssh_identity_keys and ssh_identity_ca tables (public keys stored plaintext for the unauthenticated resolver; CA private key registered for per-user field encryption), with UNIQUE(user_id), an index on ssh_identity_keys(identity_id), and idempotent CREATE TABLE migrations. * feat(ssh-id): backend API — resolver, key management, CA and certificates Mounts /sshid (nginx route added). Public text/plain authorized_keys resolver (+ exact /:algo filter, HTML viewer) and CA public-key endpoint; no-store + noindex headers on every resolver response including early 404s. Authenticated management: claim/rename/delete handle, add/import/generate/enable/delete keys, and a per-user CA (create/rotate/delete) with pure-Node OpenSSH certificate issuance. Audit logging on all mutations; UNIQUE races map to a precise 409. Unit tests for key parsing and certificate signing (ssh-keygen-validated). * feat(ssh-id): frontend panel, API client and i18n SSH ID panel wired into the app rail and AppShell: claim handle, resolver URL + curl one-liner, key list, generate, paste/import, CA enable/rotate/remove with server trust command, and per-key certificate issuance. API client re-exported through main-axios.ts; all strings i18n'd. * style(ssh-id): align panel and resolver page with Termix theme - Rebuild the SSH ID sidebar panel with the theme's square components (SectionCard / SettingRow / FakeSwitch) instead of rounded ad-hoc cards; use accent-brand and destructive tokens rather than raw red/green. - Fix panel scrolling: move overflow to a block scroll container so the cards keep their natural height instead of being clipped. - Restyle the public resolver HTML page (/sshid/u/:handle) to the Termix dark theme: square corners, #18181b/#303032 palette, #f59145 accent, uppercase section labels. - Tidy copy: 'Save To Credentials' label, drop the redundant generate intro, and correct the generate tooltip (the key is stored when saving to vault). * feat: rename to Termix ID, improve UI, backend inconsistencies, and general bug fixes --------- Co-authored-by: LukeGus <bugattiguy527@gmail.com> * ci(deps): bump actions/checkout from 6 to 7 in the github-actions group (#922) Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 6 to 7 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump the dev-patch-updates group with 11 updates (#923) Bumps the dev-patch-updates group with 11 updates: | Package | From | To | | --- | --- | --- | | [@codemirror/search](https://github.com/codemirror/search) | `6.7.0` | `6.7.1` | | [@codemirror/view](https://github.com/codemirror/view) | `6.43.0` | `6.43.1` | | [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.3.0` | `4.3.1` | | [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.1.8` | `4.1.9` | | [@vitest/ui](https://github.com/vitest-dev/vitest/tree/HEAD/packages/ui) | `4.1.8` | `4.1.9` | | [eslint-plugin-react-refresh](https://github.com/ArnaudBarre/eslint-plugin-react-refresh) | `0.5.2` | `0.5.3` | | [lint-staged](https://github.com/lint-staged/lint-staged) | `17.0.7` | `17.0.8` | | [prettier](https://github.com/prettier/prettier) | `3.8.3` | `3.8.4` | | [sharp](https://github.com/lovell/sharp) | `0.35.1` | `0.35.2` | | [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.0` | `4.3.1` | | [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.8` | `4.1.9` | Updates `@codemirror/search` from 6.7.0 to 6.7.1 - [Changelog](https://github.com/codemirror/search/blob/main/CHANGELOG.md) - [Commits](https://github.com/codemirror/search/commits) Updates `@codemirror/view` from 6.43.0 to 6.43.1 - [Changelog](https://github.com/codemirror/view/blob/main/CHANGELOG.md) - [Commits](https://github.com/codemirror/view/commits) Updates `@tailwindcss/vite` from 4.3.0 to 4.3.1 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/@tailwindcss-vite) Updates `@vitest/coverage-v8` from 4.1.8 to 4.1.9 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.9/packages/coverage-v8) Updates `@vitest/ui` from 4.1.8 to 4.1.9 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.9/packages/ui) Updates `eslint-plugin-react-refresh` from 0.5.2 to 0.5.3 - [Release notes](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/releases) - [Changelog](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/blob/main/CHANGELOG.md) - [Commits](https://github.com/ArnaudBarre/eslint-plugin-react-refresh/compare/v0.5.2...v0.5.3) Updates `lint-staged` from 17.0.7 to 17.0.8 - [Release notes](https://github.com/lint-staged/lint-staged/releases) - [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md) - [Commits](https://github.com/lint-staged/lint-staged/compare/v17.0.7...v17.0.8) Updates `prettier` from 3.8.3 to 3.8.4 - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.8.3...3.8.4) Updates `sharp` from 0.35.1 to 0.35.2 - [Release notes](https://github.com/lovell/sharp/releases) - [Commits](https://github.com/lovell/sharp/compare/v0.35.1...v0.35.2) Updates `tailwindcss` from 4.3.0 to 4.3.1 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/tailwindcss) Updates `vitest` from 4.1.8 to 4.1.9 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.9/packages/vitest) --- updated-dependencies: - dependency-name: "@codemirror/search" dependency-version: 6.7.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: "@codemirror/view" dependency-version: 6.43.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: "@tailwindcss/vite" dependency-version: 4.3.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: "@vitest/coverage-v8" dependency-version: 4.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: "@vitest/ui" dependency-version: 4.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: eslint-plugin-react-refresh dependency-version: 0.5.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: lint-staged dependency-version: 17.0.8 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: prettier dependency-version: 3.8.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: sharp dependency-version: 0.35.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: tailwindcss dependency-version: 4.3.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates - dependency-name: vitest dependency-version: 4.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-patch-updates ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump nanoid in the prod-patch-updates group (#925) Bumps the prod-patch-updates group with 1 update: [nanoid](https://github.com/ai/nanoid). Updates `nanoid` from 5.1.11 to 5.1.15 - [Release notes](https://github.com/ai/nanoid/releases) - [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md) - [Commits](https://github.com/ai/nanoid/compare/5.1.11...5.1.15) --- updated-dependencies: - dependency-name: nanoid dependency-version: 5.1.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-patch-updates ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump the major-updates group with 5 updates (#926) Bumps the major-updates group with 5 updates: | Package | From | To | | --- | --- | --- | | [js-yaml](https://github.com/nodeca/js-yaml) | `4.2.0` | `5.0.0` | | [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) | `9.39.4` | `10.0.1` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.9.2` | `26.0.0` | | [concurrently](https://github.com/open-cli-tools/concurrently) | `9.2.1` | `10.0.3` | | [eslint](https://github.com/eslint/eslint) | `9.39.4` | `10.5.0` | Updates `js-yaml` from 4.2.0 to 5.0.0 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/4.2.0...5.0.0) Updates `@eslint/js` from 9.39.4 to 10.0.1 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/commits/v10.0.1/packages/js) Updates `@types/node` from 25.9.2 to 26.0.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `concurrently` from 9.2.1 to 10.0.3 - [Release notes](https://github.com/open-cli-tools/concurrently/releases) - [Commits](https://github.com/open-cli-tools/concurrently/compare/v9.2.1...v10.0.3) Updates `eslint` from 9.39.4 to 10.5.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v9.39.4...v10.5.0) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: major-updates - dependency-name: "@eslint/js" dependency-version: 10.0.1 dependency-type: direct:development update-type: version-update:semver-major dependency-group: major-updates - dependency-name: "@types/node" dependency-version: 26.0.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: major-updates - dependency-name: concurrently dependency-version: 10.0.3 dependency-type: direct:development update-type: version-update:semver-major dependency-group: major-updates - dependency-name: eslint dependency-version: 10.5.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: major-updates ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(ssh): add HashiCorp Vault SSH signer authentication * fix: small fixes to vault feature to align with Termix codebase * chore: add view docs links for vault/termix id * fix: file upload fails with 400 and missing schema migrations on upgrade (#929) Two bugs introduced in v2.4.1: 1. uploadFileStream uses fileManagerApi.post() which triggers axios's transformRequest to JSON-serialize the FormData because the instance default Content-Type is application/json. Change to postForm() which sets Content-Type: multipart/form-data so the browser XHR sends the correct multipart body with boundary. 2. Two schema items added to schema.ts were not included in migrateSchema() in db/index.ts, causing 500 errors on existing installations upgrading from v2.4.0: - user_preferences.status_color_scheme (no such column) - dashboard_service_links table (no such table) Fixes #928 Co-authored-by: sash <sash@fominykh.io> * fix: support PuTTY PPK ssh keys (#930) * fix: chunk large file manager uploads (#932) * fix: route dashboard hosts by protocol (#934) * fix: resolve tunnel endpoints reliably (#935) * Fix Electron OIDC browser auth failures (#936) * Allow RDP connections without stored credentials (#937) * Sync role credential shares for OIDC users (#938) * Fix terminal link dialog layering (#940) * Confirm large files before opening editor (#942) * Confirm closing active host connections (#943) * Preserve file path case in file manager UI (#941) * fix: preserve unicode guacamole tokens (#933) * Persist VNC authentication settings (#944) * Fix Guacamole websocket base path (#946) * Promote file manager terminals to tabs (#939) * Guard Guacamole disconnect during startup (#945) * chore: increment ver * feat: bitwarden ssh agent integration * feat: serial connections support * fix: various small bug fixes * feat: open all sessions in a folder and terminal custom theme color support * feat: cross host file manager clipboard and several small bug fixes * feat: tailscale/wireguard support and added a new status state for when backend is checking status * feat: grafana like server stats history, new alert system, ntfy/webhook support * feat: new grid and widget based homepage function * feat: new donate button in dashboard * fix: alert ui incorrectly using termix css and fixed issue with alert system not loading * chore: start database layer refactor * docs: plan database layer refactor * docs: audit database layer refactor phase zero * chore: add database runtime adapter skeleton * chore: add settings repository skeleton * chore: add user session repository skeleton * chore: add host credential repository skeleton * chore: add field encryption boundary * chore: migrate settings route slice * chore: migrate user settings routes * chore: migrate host metrics settings routes * chore: migrate acme settings route * chore: migrate terminal settings route * chore: migrate tailscale settings read * chore: migrate guacamole settings reads * chore: migrate session timeout settings reads * chore: migrate auth route settings reads * chore: migrate host metrics settings reads * chore: migrate startup settings reads * chore: migrate user settings cleanup * chore: migrate password reset settings * chore: migrate oidc legacy settings read * chore: migrate user route settings slice * chore: migrate oidc state settings * chore: migrate user login settings reads * chore: migrate user crypto settings * chore: consolidate startup settings defaults * chore: consolidate database settings import export * chore: migrate core session auth paths * chore: migrate remaining session auth paths * chore: migrate admin user routes * chore: migrate user route admin checks * chore: migrate user lifecycle routes * chore: migrate auth user lookups * chore: migrate oidc user routes * chore: migrate api key repository paths * docs: add database gray rollout guide * chore: migrate trusted device paths * chore: migrate user session route user lookups * chore: add database repository rollout guard * chore: expose repository rollout status * chore: warn on repository rollout misconfiguration * chore: migrate remaining user lookup helpers * chore: migrate ssh user lookups * chore: migrate user settings admin lookups * chore: migrate acme ssl user lookups * chore: migrate audit log admin checks * chore: migrate oidc account user updates * chore: migrate password reset user updates * chore: migrate user deletion core records * chore: migrate snippet audit user lookups * chore: migrate ldap user sync paths * chore: migrate totp user updates * chore: migrate rbac user checks * chore: migrate rbac role paths * chore: migrate permission role lookups * chore: migrate rbac access list reads * chore: migrate shared rbac reads * chore: migrate rbac access writes * chore: migrate permission host access * chore: migrate role host access lookup * chore: migrate snippet access lookup * chore: migrate shared credential access lookups * chore: migrate host access cleanup writes * chore: migrate host list access checks * chore: migrate host access cleanup routes * chore: migrate shared credential role lookups * chore: migrate user role cleanup * chore: migrate admin role sync * chore: migrate ldap role sync * chore: migrate user role assignment * chore: migrate sso provider access * chore: migrate audit log access * chore: migrate user preference access * chore: migrate open tab access * chore: migrate dismissed alert access * chore: migrate homepage layout access * chore: migrate network topology access * chore: migrate dashboard service link access * chore: migrate command history access * chore: migrate recent activity cleanup * chore: migrate ssh credential usage access * chore: migrate transfer recent access * chore: migrate file manager bookmark access * chore: migrate c2s tunnel preset access * chore: migrate homepage item access * chore: migrate session recording access * chore: migrate tmux session tag access * chore: migrate opkssh token access * chore: migrate vault token access * chore: migrate vault profile access * chore: migrate host metrics preference access * chore: migrate host health access * chore: migrate host metrics history access * chore: migrate alert persistence access * chore: route alert host lookup through repository * chore: migrate user data export reads * chore: route host metrics stats sync through repository * chore: migrate host folder persistence * chore: migrate host resolution reads * chore: route jump host resolution reads * chore: route docker console jump host reads * chore: route docker ssh resolution reads * chore: route proxmox discovery resolution reads * chore: route file manager activity host reads * chore: route host metrics resolution reads * chore: route ssh auth credential reads * chore: route tunnel endpoint credential reads * chore: route credential deployment resolution reads * chore: route command history host flag reads * chore: route snippet execution resolution reads * chore: route terminal host resolution reads * chore: route vault oidc host resolution reads * chore: route wake on lan host reads * chore: route internal host list reads * chore: route host key verification persistence * chore: route credential read paths * chore: route credential host usage reads * chore: route credential folder rename * chore: route host owner access checks * chore: route shared credential source reads * chore: route user host credential cleanup * chore: route credential delete reads * chore: route credential update reads * chore: route host credential reads * chore: route host read paths * chore: route host projection reads * chore: route host list reads * chore: route snippet read paths * chore: route snippet folder writes * chore: route snippet crud paths * chore: route snippet bulk import * chore: route rbac ownership reads * chore: route user count reads * chore: route cleanup snippets folders * chore: route shared credential persistence * chore: route dashboard activity * chore: route guacamole host reads * chore: route host bulk lookups * chore: remove unlock-only simple db ops * chore: route host autostart persistence * chore: route ldap provisioning through users * chore: route credential encrypted writes * chore: route host encrypted writes * chore: route bulk host encrypted writes * chore: route termix id credentials * chore: route termix id ca persistence * chore: route termix identity persistence * chore: route credential system migration * chore: isolate user encryption migration storage * chore: remove legacy simple db ops * chore: isolate legacy sqlite migration copy * chore: route database settings import export * chore: route database host credential export * chore: route database host credential import * chore: route database file-manager import export * chore: route database alert usage import export * chore: route database user checks * chore: isolate auth lazy migration storage * chore: route explicit database saves * chore: initialize database save boundary * chore: route migration snapshot saves * chore: isolate sqlite import constraints * chore: route import sqlite boundary * chore: route user encryption migration store * chore: centralize current repository runtime * chore: route more current repositories * chore: route activity repository runtimes * chore: route token repository runtimes * chore: route health repository runtimes * chore: route identity repository runtimes * chore: route rbac repository runtime * chore: centralize current sqlite runtime access * chore: route user deletion key cleanup * chore: route user deletion vault cleanup * chore: route user deletion homepage cleanup * chore: route user deletion health cleanup * chore: route user deletion alert cleanup * chore: route user deletion identity cleanup * chore: add database layer preupgrade backup * Fix database repository type errors * fix: complete post-merge compile fixes for database refactor Restore missing DatabaseSaveTrigger/getDb imports, session log format fallback, OIDC provider resolution, guacamole recording insert, and passwordFallbackOnly typing after merging current dev. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: DivByZero <mr.oplus@yahoo.fr> Co-authored-by: LukeGus <bugattiguy527@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: devdanetra <46488477+devdanetra@users.noreply.github.com> Co-authored-by: Aleksandr Fominykh <neoformalex@users.noreply.github.com> Co-authored-by: sash <sash@fominykh.io>
This commit is contained in:
@@ -0,0 +1,548 @@
|
||||
# Database Layer Refactor Phase 0 Audit
|
||||
|
||||
Status: Draft
|
||||
Branch: `feature/database-layer-refactor`
|
||||
Purpose: Establish the current database access inventory, domain map, sensitive field map, and first implementation boundaries before changing runtime persistence.
|
||||
|
||||
## 1. Scope
|
||||
|
||||
Phase 0 does not change runtime behavior.
|
||||
|
||||
It produces the evidence needed for the next implementation phases:
|
||||
|
||||
- where database access currently happens
|
||||
- which modules write directly to the database
|
||||
- which tables belong to which product domains
|
||||
- which fields are sensitive
|
||||
- which direct writes are risky under the current in-memory snapshot model
|
||||
- which domains should move first into repositories
|
||||
|
||||
## 2. Current Evidence
|
||||
|
||||
Commands used for the initial audit:
|
||||
|
||||
```bash
|
||||
rg -n "getDb\\(|getSqlite\\(|DatabaseSaveTrigger|SimpleDBOps|db\\.\\$client|\\.prepare\\(" src/backend
|
||||
rg -n "getDb\\(\\)\\.(insert|update|delete)|await db\\.(insert|update|delete)|db\\.(insert|update|delete)|\\.\\$client\\.prepare\\(\\\"(INSERT|UPDATE|DELETE)|\\.prepare\\(\\\"(INSERT|UPDATE|DELETE)|DatabaseSaveTrigger\\.triggerSave|DatabaseSaveTrigger\\.forceSave" src/backend
|
||||
rg -n "export const .* = sqliteTable\\(" src/backend/database/db/schema.ts
|
||||
```
|
||||
|
||||
High-level findings:
|
||||
|
||||
- Database infrastructure is concentrated in `src/backend/database/db/index.ts`.
|
||||
- Business database access is spread across route modules, SSH modules, utilities, and auth helpers.
|
||||
- `SimpleDBOps` is not the only write path.
|
||||
- There are many direct Drizzle writes and raw SQLite writes.
|
||||
- Some direct writes manually trigger `DatabaseSaveTrigger`; many write paths do not.
|
||||
- Schema is SQLite-specific through `sqliteTable` and manual `CREATE TABLE IF NOT EXISTS` / `addColumnIfNotExists`.
|
||||
|
||||
## 3. Database Access Hotspots
|
||||
|
||||
The most database-heavy files by audit hits:
|
||||
|
||||
| File | Approx. hits | Notes |
|
||||
| ----------------------------------------------------- | -----------: | --------------------------------------------------------------- |
|
||||
| `src/backend/database/db/index.ts` | 75 | database init, schema creation, ad-hoc migration, snapshot save |
|
||||
| `src/backend/database/routes/alert-rules-routes.ts` | 64 | alert rules, channels, firings, raw SQL deletes |
|
||||
| `src/backend/database/routes/users.ts` | 54 | users, settings, OIDC/GitHub settings, admin flows |
|
||||
| `src/backend/database/database.ts` | 27 | import/export, legacy SQLite handling |
|
||||
| `src/backend/ssh/host-metrics.ts` | 26 | metrics connection and settings reads |
|
||||
| `src/backend/database/routes/user-settings-routes.ts` | 16 | user settings |
|
||||
| `src/backend/dashboard.ts` | 15 | dashboard aggregation reads |
|
||||
| `src/backend/ssh/docker.ts` | 14 | host/credential reads for Docker SSH |
|
||||
| `src/backend/ssh/managers/health.ts` | 13 | host health checks |
|
||||
| `src/backend/ssh/alert-engine.ts` | 13 | alert evaluation and firing state |
|
||||
| `src/backend/utils/user-crypto.ts` | 12 | settings writes for crypto metadata |
|
||||
| `src/backend/ssh/host-metrics-settings-routes.ts` | 12 | metrics settings |
|
||||
| `src/backend/ssh/tmux-monitor.ts` | 11 | tmux session tags |
|
||||
| `src/backend/guacamole/routes.ts` | 11 | Guacamole config/routes |
|
||||
| `src/backend/database/routes/host.ts` | 10 | host operations and related rows |
|
||||
|
||||
This confirms the refactor must be domain-by-domain. A mechanical replacement of `getDb()` would be noisy and unsafe.
|
||||
|
||||
## 4. Direct Write Risk Inventory
|
||||
|
||||
Under the current architecture, a direct write is risky when it bypasses `SimpleDBOps` and does not trigger `DatabaseSaveTrigger`.
|
||||
|
||||
### 4.1 Direct Writes That Need Repository Ownership
|
||||
|
||||
These areas perform direct writes and should move behind repositories/services:
|
||||
|
||||
| Area | Representative files | Examples |
|
||||
| --------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------- |
|
||||
| users/settings/auth | `routes/users.ts`, `utils/auth-manager.ts`, `utils/user-crypto.ts` | sessions, trusted devices, OIDC settings, registration settings |
|
||||
| RBAC/sharing | `routes/rbac.ts`, `utils/shared-credential-manager.ts` | roles, host access, snippet access, shared credentials |
|
||||
| hosts/credentials | `routes/host.ts`, `routes/credentials.ts`, `host-resolver.ts` | host access cleanup, credential usage |
|
||||
| file manager metadata | `host-file-manager-bookmark-routes.ts` | recent, pinned, shortcuts |
|
||||
| alerts | `alert-rules-routes.ts`, `ssh/alert-engine.ts` | channels, rules, firings |
|
||||
| metrics | `host-metrics-preferences-routes.ts`, `managers/health.ts` | preferences, health checks, history |
|
||||
| terminal logs | `terminal-session-manager.ts` | session recording metadata |
|
||||
| tmux | `tmux-monitor.ts` | tmux session tags |
|
||||
| import/export | `database/database.ts` | SQLite import and forced save |
|
||||
| open tabs | `routes/open-tabs.ts` | tab persistence and cleanup |
|
||||
| API keys | `user-api-key-routes.ts`, `utils/auth-manager.ts` | API key create/delete/last-used |
|
||||
| SSO and identity | `sso-provider-routes.ts`, `termix-id.ts` | providers, identity keys/CA |
|
||||
|
||||
### 4.2 Immediate Compatibility Rule
|
||||
|
||||
Until a domain is migrated to repositories:
|
||||
|
||||
- Every direct write must either be moved into a repository or explicitly trigger persistence in the old runtime.
|
||||
- New code should not add direct `getDb()` writes outside infrastructure or repositories.
|
||||
- The draft branch should add an enforcement check before Phase 8, not immediately, because the current codebase still violates the target rule widely.
|
||||
|
||||
## 5. Table Domain Map
|
||||
|
||||
### 5.1 Identity and Authentication
|
||||
|
||||
| Tables | Notes |
|
||||
| ---------------------- | -------------------------------------------- |
|
||||
| `users` | local/OIDC users, TOTP fields, password hash |
|
||||
| `sessions` | JWT sessions |
|
||||
| `trusted_devices` | remembered devices |
|
||||
| `api_keys` | API token hashes/prefixes |
|
||||
| `sso_providers` | configured SSO providers |
|
||||
| `termix_identities` | Termix identity records |
|
||||
| `termix_identity_keys` | public/private identity key metadata |
|
||||
| `termix_identity_ca` | CA material, private key is sensitive |
|
||||
|
||||
Suggested repository:
|
||||
|
||||
- `userRepository`
|
||||
- `sessionRepository`
|
||||
- `trustedDeviceRepository`
|
||||
- `apiKeyRepository`
|
||||
- `ssoProviderRepository`
|
||||
- `termixIdentityRepository`
|
||||
|
||||
### 5.2 Hosts and Credentials
|
||||
|
||||
| Tables | Notes |
|
||||
| ---------------------- | ------------------------------------------------ |
|
||||
| `ssh_data` | primary host table, many config JSON/text fields |
|
||||
| `ssh_credentials` | reusable credentials |
|
||||
| `ssh_credential_usage` | usage history |
|
||||
| `ssh_folders` | folder metadata |
|
||||
| `host_access` | sharing/RBAC access rows |
|
||||
| `shared_credentials` | encrypted shared credential material |
|
||||
| `network_topology` | topology graph/config |
|
||||
|
||||
Suggested repository:
|
||||
|
||||
- `hostRepository`
|
||||
- `credentialRepository`
|
||||
- `credentialUsageRepository`
|
||||
- `hostAccessRepository`
|
||||
- `sharedCredentialRepository`
|
||||
- `hostFolderRepository`
|
||||
- `networkTopologyRepository`
|
||||
|
||||
### 5.3 RBAC
|
||||
|
||||
| Tables | Notes |
|
||||
| ---------------- | ------------------------ |
|
||||
| `roles` | role definitions |
|
||||
| `user_roles` | user to role assignments |
|
||||
| `host_access` | host-level grants |
|
||||
| `snippet_access` | snippet-level grants |
|
||||
|
||||
Suggested repository:
|
||||
|
||||
- `roleRepository`
|
||||
- `accessRepository`
|
||||
|
||||
### 5.4 File Manager
|
||||
|
||||
| Tables | Notes |
|
||||
| ------------------------ | ---------------------------------- |
|
||||
| `file_manager_recent` | recently opened paths |
|
||||
| `file_manager_pinned` | pinned paths |
|
||||
| `file_manager_shortcuts` | saved shortcuts |
|
||||
| `transfer_recent` | host-to-host transfer destinations |
|
||||
|
||||
Suggested repository:
|
||||
|
||||
- `fileManagerRepository`
|
||||
- `transferRecentRepository`
|
||||
|
||||
### 5.5 Snippets
|
||||
|
||||
| Tables | Notes |
|
||||
| ----------------- | ----------------------- |
|
||||
| `snippets` | command snippets |
|
||||
| `snippet_folders` | snippet folder metadata |
|
||||
| `snippet_access` | snippet sharing |
|
||||
|
||||
Suggested repository:
|
||||
|
||||
- `snippetRepository`
|
||||
|
||||
### 5.6 Runtime Metadata and Audit
|
||||
|
||||
| Tables | Notes |
|
||||
| -------------------- | ------------------------------------------------------ |
|
||||
| `audit_logs` | append-only audit trail |
|
||||
| `session_recordings` | terminal recording metadata, log content is file-based |
|
||||
| `recent_activity` | host activity feed |
|
||||
| `command_history` | terminal command history |
|
||||
| `user_open_tabs` | UI restore state; currently cleared on startup |
|
||||
| `user_preferences` | per-user UI/preferences |
|
||||
| `settings` | global settings |
|
||||
|
||||
Suggested repository:
|
||||
|
||||
- `auditRepository`
|
||||
- `sessionRecordingRepository`
|
||||
- `activityRepository`
|
||||
- `commandHistoryRepository`
|
||||
- `openTabsRepository`
|
||||
- `userPreferencesRepository`
|
||||
- `settingsRepository`
|
||||
|
||||
### 5.7 Metrics and Alerts
|
||||
|
||||
| Tables | Notes |
|
||||
| -------------------------- | -------------------------- |
|
||||
| `host_metrics_preferences` | metrics layout/preferences |
|
||||
| `host_health_checks` | health check definitions |
|
||||
| `host_health_history` | health check results |
|
||||
| `host_metrics_history` | metrics history |
|
||||
| `alert_rules` | alert definitions |
|
||||
| `notification_channels` | webhook/ntfy/etc config |
|
||||
| `alert_rule_channels` | rule/channel joins |
|
||||
| `alert_firings` | firing/ack state |
|
||||
| `dismissed_alerts` | dismissed system alerts |
|
||||
|
||||
Suggested repository:
|
||||
|
||||
- `metricsRepository`
|
||||
- `healthCheckRepository`
|
||||
- `alertRepository`
|
||||
- `notificationRepository`
|
||||
|
||||
### 5.8 Integrations and Feature Config
|
||||
|
||||
| Tables | Notes |
|
||||
| ------------------------- | --------------------------------------- |
|
||||
| `c2s_tunnel_presets` | tunnel preset config |
|
||||
| `opkssh_tokens` | OPKSSH cert/private key cache |
|
||||
| `vault_profiles` | Vault profile config, mostly non-secret |
|
||||
| `vault_tokens` | Vault cert/private key cache |
|
||||
| `dashboard_service_links` | dashboard links |
|
||||
| `homepage_items` | homepage widgets/items |
|
||||
| `homepage_layouts` | homepage layouts |
|
||||
| `tmux_session_tags` | tmux tag metadata |
|
||||
|
||||
Suggested repository:
|
||||
|
||||
- `tunnelPresetRepository`
|
||||
- `opksshTokenRepository`
|
||||
- `vaultRepository`
|
||||
- `dashboardRepository`
|
||||
- `homepageRepository`
|
||||
- `tmuxRepository`
|
||||
|
||||
## 6. Sensitive Field Map
|
||||
|
||||
The current explicit `FieldCrypto` map encrypts:
|
||||
|
||||
| Table | Fields |
|
||||
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `users` | `passwordHash`, `clientSecret`, `totpSecret`, `totpBackupCodes`, `oidcIdentifier` |
|
||||
| `ssh_data` | `password`, `key`, `keyPassword`, `sudoPassword`, `autostartPassword`, `autostartKey`, `autostartKeyPassword`, `socks5Password`, `rdpPassword`, `vncPassword`, `telnetPassword` |
|
||||
| `ssh_credentials` | `password`, `privateKey`, `keyPassword`, `key`, `publicKey` |
|
||||
| `opkssh_tokens` | `sshCert`, `privateKey` |
|
||||
| `termix_identity_ca` | `privateKey` |
|
||||
| `vault_tokens` | `sshCert`, `privateKey` |
|
||||
|
||||
Additional sensitive fields by table semantics:
|
||||
|
||||
| Table | Fields / reason |
|
||||
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `ssh_credentials` | `systemPassword`, `systemKey`, `systemKeyPassword` are system-key encrypted credential copies |
|
||||
| `shared_credentials` | `encryptedUsername`, `encryptedAuthType`, `encryptedPassword`, `encryptedKey`, `encryptedKeyPassword`, `encryptedKeyType` are already encrypted payload fields |
|
||||
| `api_keys` | `tokenHash` is not plaintext but is authentication material; `tokenPrefix` may remain plaintext for display |
|
||||
| `settings` | some keys may hold provider secrets or reset codes; repository must classify by key |
|
||||
| `notification_channels` | config may include webhook URLs/tokens; treat config as sensitive unless split |
|
||||
| `alert_rules` | rule definitions are usually not secret but can include host/resource metadata |
|
||||
| `homepage_items` | widget config can include URLs/API config; classify per widget type |
|
||||
| `c2s_tunnel_presets` | config can include connection details; review before plaintext external DB storage |
|
||||
| `termix_identity_keys` | inspect key material fields before migration; public keys are not secret but private material must never be plaintext |
|
||||
| `vault_profiles` | current comments say profile fields are non-secret; keep that invariant explicit |
|
||||
|
||||
Open privacy decision:
|
||||
|
||||
- `ssh_data.ip`, domain fields, usernames, folders, and tags are queryable today.
|
||||
- Encrypting them improves confidentiality but breaks search/filter/sort unless blind indexes are added.
|
||||
- Recommended initial migration: keep them plaintext and document privacy implications; add optional privacy mode later.
|
||||
|
||||
## 7. Repository Migration Order
|
||||
|
||||
Use a vertical slice instead of broad replacement.
|
||||
|
||||
### 7.1 First Slice
|
||||
|
||||
1. `settingsRepository`
|
||||
2. `userRepository`
|
||||
3. `sessionRepository`
|
||||
4. `hostRepository`
|
||||
5. `credentialRepository`
|
||||
|
||||
Reasons:
|
||||
|
||||
- Covers the app's boot/login/core host management path.
|
||||
- Exercises field encryption.
|
||||
- Exercises per-user data unlock requirements.
|
||||
- Exercises transaction and migration behavior.
|
||||
- Builds reusable patterns for the rest of the backend.
|
||||
|
||||
### 7.2 Second Slice
|
||||
|
||||
1. `hostAccessRepository`
|
||||
2. `roleRepository`
|
||||
3. `sharedCredentialRepository`
|
||||
4. `auditRepository`
|
||||
5. `userPreferencesRepository`
|
||||
|
||||
Reasons:
|
||||
|
||||
- Completes permission and sharing boundaries.
|
||||
- Removes high-risk direct writes in admin/RBAC flows.
|
||||
- Moves audit to an append-only repository.
|
||||
|
||||
### 7.3 Third Slice
|
||||
|
||||
1. `snippetRepository`
|
||||
2. `fileManagerRepository`
|
||||
3. `metricsRepository`
|
||||
4. `alertRepository`
|
||||
5. `homepageRepository`
|
||||
|
||||
Reasons:
|
||||
|
||||
- These are broad feature domains with many routes.
|
||||
- They should reuse patterns from the core slices.
|
||||
|
||||
### 7.4 Fourth Slice
|
||||
|
||||
1. `vaultRepository`
|
||||
2. `opksshTokenRepository`
|
||||
3. `termixIdentityRepository`
|
||||
4. `tunnelPresetRepository`
|
||||
5. `tmuxRepository`
|
||||
|
||||
Reasons:
|
||||
|
||||
- Sensitive token/key cache domains need careful encryption tests.
|
||||
- Some data is transient and should have retention cleanup.
|
||||
|
||||
## 8. Adapter Design Notes
|
||||
|
||||
The adapter boundary should expose:
|
||||
|
||||
```ts
|
||||
interface DatabaseAdapter {
|
||||
dialect: "sqlite" | "postgres" | "mysql";
|
||||
connect(): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
migrate(): Promise<void>;
|
||||
transaction<T>(fn: (tx: DatabaseTransaction) => Promise<T>): Promise<T>;
|
||||
}
|
||||
```
|
||||
|
||||
The repository layer should not depend on `better-sqlite3`.
|
||||
|
||||
For Drizzle, likely options:
|
||||
|
||||
- keep dialect-specific Drizzle clients internally
|
||||
- expose repositories instead of exposing the raw Drizzle client
|
||||
- keep schema definitions close to migrations, not route handlers
|
||||
|
||||
Important: do not make route modules import dialect-specific schema objects after migration.
|
||||
|
||||
## 9. Compatibility Shims
|
||||
|
||||
During the migration, avoid a flag day.
|
||||
|
||||
Add a compatibility database module that lets old code continue to run while new repositories are introduced:
|
||||
|
||||
```text
|
||||
legacy getDb() path
|
||||
new adapter/repository path
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- New modules use repositories only.
|
||||
- Migrated modules must not fall back to `getDb()`.
|
||||
- Legacy path is removed only after all domains move.
|
||||
|
||||
## 10. Phase 1 Entry Criteria
|
||||
|
||||
Before implementing the adapter skeleton:
|
||||
|
||||
- This audit document exists.
|
||||
- The sensitive field map is reviewed.
|
||||
- The first vertical slice is accepted.
|
||||
- The draft PR remains draft.
|
||||
- No runtime behavior has changed.
|
||||
|
||||
## 11. Phase 1 Deliverables
|
||||
|
||||
Recommended first implementation PR on this branch:
|
||||
|
||||
- `src/backend/database/runtime/config.ts`
|
||||
- `src/backend/database/runtime/adapter.ts`
|
||||
- `src/backend/database/runtime/sqlite-adapter.ts`
|
||||
- `src/backend/database/repositories/settings-repository.ts`
|
||||
- `src/backend/database/repositories/user-repository.ts`
|
||||
- `src/backend/database/repositories/session-repository.ts`
|
||||
- `src/backend/database/repositories/host-repository.ts`
|
||||
- `src/backend/database/repositories/credential-repository.ts`
|
||||
- `src/backend/database/repositories/field-encryption-boundary.ts`
|
||||
- `src/backend/database/repositories/current-settings-repository.ts`
|
||||
- tests for config parsing and SQLite adapter boot
|
||||
|
||||
Started:
|
||||
|
||||
- runtime config parser
|
||||
- SQLite adapter skeleton
|
||||
- migration metadata table bootstrap
|
||||
- `SettingsRepository` skeleton and tests
|
||||
- `UserRepository` and `SessionRepository` skeletons and tests
|
||||
- `HostRepository` and `CredentialRepository` skeletons and tests
|
||||
- `FieldEncryptionBoundary` skeleton and tests
|
||||
- first settings route slice wired through `SettingsRepository`
|
||||
- user settings route direct `settings` table access moved behind
|
||||
`SettingsRepository`
|
||||
- host metrics settings route direct `settings` table access moved behind
|
||||
`SettingsRepository`
|
||||
- ACME SSL settings route direct `settings` table access moved behind
|
||||
`SettingsRepository`
|
||||
- terminal route direct `settings` table access moved behind
|
||||
`SettingsRepository`
|
||||
- tailscale route direct `settings` table access moved behind
|
||||
`SettingsRepository`
|
||||
- Guacamole route and WebSocket server direct `settings` table access moved
|
||||
behind the current settings repository boundary
|
||||
- auth token expiry and terminal session timeout settings reads moved behind the
|
||||
current settings repository boundary
|
||||
- open tabs, TOTP, and LDAP auth route settings reads moved behind the current
|
||||
settings repository boundary
|
||||
- host metrics polling settings reads moved behind the current settings
|
||||
repository boundary
|
||||
- backend startup settings reads moved behind the current settings repository
|
||||
boundary
|
||||
- user deletion cleanup now removes per-user settings through
|
||||
`SettingsRepository.deleteLike`
|
||||
- password reset route reset code and temporary token settings access moved
|
||||
behind `SettingsRepository`
|
||||
- OIDC utility legacy config fallback reads `oidc_config` through
|
||||
`SettingsRepository`
|
||||
- user route registration/password flags and OIDC config administration moved
|
||||
behind the current settings repository boundary
|
||||
- OIDC authorize/callback temporary state and auto-provision reads moved behind
|
||||
the current settings repository boundary
|
||||
- user login settings reads moved behind the current settings repository
|
||||
boundary, completing direct `settings` access cleanup in `routes/users.ts`
|
||||
- user encryption metadata in `utils/user-crypto.ts` moved behind the current
|
||||
settings repository boundary
|
||||
- database startup and schema migration defaults in `database/db/index.ts`
|
||||
moved to local raw settings helpers
|
||||
- database import/export settings handling in `database/database.ts` moved to
|
||||
local helper boundaries
|
||||
- core `auth-manager.ts` session create/read/update/revoke/list paths started
|
||||
using the current session repository boundary
|
||||
- remaining `auth-manager.ts` session cleanup/middleware/logout paths and
|
||||
`user-session-routes.ts` single-session lookup moved behind the current
|
||||
session repository boundary
|
||||
- current user repository factory/write-save hook added, and
|
||||
`user-admin-routes.ts` list/admin promotion/admin removal/admin-create user
|
||||
paths moved behind the current user repository boundary
|
||||
- low-risk `routes/users.ts` current-user lookup and admin gate checks moved
|
||||
behind the current user repository boundary
|
||||
- user registration, self-delete, password change hash updates, and admin
|
||||
delete-user lookup paths in `routes/users.ts` moved behind the current user
|
||||
repository boundary, with first-user admin creation kept transactional inside
|
||||
`UserRepository`
|
||||
- traditional login username lookup and `auth-manager.ts` admin user checks
|
||||
moved behind the current user repository boundary
|
||||
- GitHub and standard OIDC callback user lookup/create/rollback/profile/admin
|
||||
sync writes moved behind the current user repository boundary, removing direct
|
||||
Drizzle `users` table access from `routes/users.ts`, `user-admin-routes.ts`,
|
||||
and `auth-manager.ts`
|
||||
- API key create/list/delete and API key authentication last-used updates moved
|
||||
behind the current API key repository boundary
|
||||
- trusted device check/add/remove and TOTP trusted-device cleanup moved behind
|
||||
the current trusted device repository boundary
|
||||
- user session routes moved user/admin lookups and admin session username
|
||||
enrichment behind the current user repository boundary
|
||||
- vault admin checks, Termix ID audit username lookup, permission manager admin
|
||||
checks, and user data export user lookup moved behind the current user
|
||||
repository boundary
|
||||
- SSH credential OIDC username expansion and tmux monitor audit actor username
|
||||
lookup moved behind the current user repository boundary
|
||||
- user settings route admin checks and audit actor username lookups moved behind
|
||||
the current user repository boundary
|
||||
- ACME SSL route admin checks and audit actor username lookups moved behind the
|
||||
current user repository boundary
|
||||
- audit log route admin checks moved behind the current user repository boundary
|
||||
- OIDC account link/unlink route user lookups and OIDC field updates moved
|
||||
behind the current user repository boundary
|
||||
- password reset route user lookups, password hash updates, and TOTP reset
|
||||
fields moved behind the current user repository boundary
|
||||
- user deletion helper now removes sessions through the current session
|
||||
repository and the final user record through the current user repository
|
||||
- snippet create/update/delete audit actor username lookups moved behind the
|
||||
current user repository boundary
|
||||
- LDAP login existing-user lookup, encryption rollback delete, admin sync, and
|
||||
display-name sync moved behind the current user repository boundary
|
||||
- TOTP setup/enable/disable/backup-code/login verification user updates and
|
||||
session revocation moved behind the current user/session repository
|
||||
boundaries
|
||||
- RBAC host sharing, role assignment, and snippet sharing target-user existence
|
||||
checks moved behind the current user repository boundary, with existing
|
||||
RBAC/snippet owner username joins retained
|
||||
- RBAC role list/create/update/delete, user-role assignment/removal/listing,
|
||||
and shared host/snippet role-id lookups moved behind the current role
|
||||
repository boundary, with existing RBAC/share credential joins retained
|
||||
- permission manager role permission aggregation, role-id lookups for shared
|
||||
host access, and admin role checks moved behind the current role repository
|
||||
boundary
|
||||
- RBAC host/snippet access-list read models moved behind the current RBAC access
|
||||
repository boundary, and snippet route shared-access role-id lookups moved
|
||||
behind the current role repository boundary
|
||||
- RBAC shared host/shared snippet read models and the main snippet
|
||||
shared-snippet read model moved behind the current RBAC access repository
|
||||
boundary
|
||||
- RBAC host/snippet access grant, revoke, and direct host-access credential
|
||||
override writes moved behind the current RBAC access repository boundary,
|
||||
with shared credential material creation retained in the existing manager
|
||||
- permission manager host-access expiration cleanup, shared host-access lookup,
|
||||
and last-access timestamp updates moved behind the current RBAC access
|
||||
repository boundary
|
||||
- repository rollout guard added through `DATABASE_LAYER_REPOSITORY_ROLLOUT`
|
||||
for the migrated settings/users/sessions/API-key/trusted-device/role/RBAC-access
|
||||
slice
|
||||
|
||||
Keep it small. Do not wire host or credential routes into the new repositories in
|
||||
the same first implementation commit.
|
||||
|
||||
## 12. Current Unknowns
|
||||
|
||||
- Exact Drizzle multi-dialect strategy needs a spike.
|
||||
- The project may need a migration generator or a custom migration runner.
|
||||
- Some raw SQL in `routes/users.ts`, `alert-rules-routes.ts`, and `db/index.ts` must be rewritten or isolated.
|
||||
- `settings` contains mixed public and sensitive values; key-level classification is required.
|
||||
- `homepage_items.config`, `notification_channels.config`, and tunnel configs may contain embedded secrets.
|
||||
- Legacy encrypted snapshot fixtures need to be created before migration implementation.
|
||||
|
||||
## 13. Decision Log
|
||||
|
||||
- Default upgrade target should be persistent SQLite, not PostgreSQL/MySQL.
|
||||
- PostgreSQL/MySQL migration should be explicit and initially manual/experimental.
|
||||
- Runtime SSH/WebSocket/tunnel state remains memory-only.
|
||||
- Field-level encryption is mandatory for every database backend.
|
||||
- Field-level encryption must use a stable record id; temporary encryption
|
||||
contexts are forbidden for newly written repository data.
|
||||
- Repository migration should start with settings/users/sessions/hosts/credentials.
|
||||
Reference in New Issue
Block a user