Files
Termix/readme/DATABASE-LAYER-GRAY-ROLLOUT.md
T
ZacharyZcR 1e7c9ea53c 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>
2026-07-15 23:28:10 -05:00

448 lines
34 KiB
Markdown

# Database Layer Gray Rollout Guide
Status: Draft branch gray-rollout guide
Branch: `feature/database-layer-refactor`
Scope: repository-boundary migration for current SQLite snapshot runtime
This branch is not the full multi-database refactor. Gray rollout is only for
the already-migrated repository boundary paths while the production runtime still
uses the existing encrypted SQLite snapshot model.
## 1. Gray Scope
Allowed in gray rollout:
- Existing encrypted SQLite snapshot runtime.
- Existing database file format.
- Existing schema and migration flow.
- Settings, user, host, API key, session, trusted device, audit log, user
preference, open tab, dismissed alert, homepage layout/item, and network
topology, dashboard service link, session recording, command history, recent
activity, transfer recent, and file-manager bookmark current repository
plus C2S tunnel preset, tmux session tag, OPKSSH token, Vault token/profile,
SSH credential usage, role, SSO provider, host folder, alert, host health,
host metrics preference/history, credential, host resolution, snippet,
RBAC access, shared credential, Termix ID identity/CA, and user data export
current repository factories share `current-repository-runtime` for SQLite
context and write-save hooks.
- Settings reads and writes migrated behind `SettingsRepository`.
- Database import/export settings reads and admin upserts migrated behind
`SettingsRepository`.
- Session create/read/update/revoke/list paths migrated behind
`SessionRepository`.
- User create/read/update/delete/auth paths migrated behind `UserRepository`.
- User setup/count/db-health, password-login TOTP guard, and last-admin delete
guard reads migrated behind `UserRepository`.
- Database import/export user unlock/admin checks migrated behind
`UserRepository`.
- LDAP first-user provisioning and admin-group user creation migrated behind
`UserRepository`.
- API key create/list/delete and authentication last-used updates migrated behind
`ApiKeyRepository`.
- Trusted device check/add/remove and TOTP trusted-device cleanup migrated
behind `TrustedDeviceRepository`.
- Credential list, folder list, detail reads, update lookup/readback, host route
credential resolution reads, folder rename writes, apply usage writes, shared
credential source row reads, credential delete lookup/delete, and
credential-host list reads migrated behind `CredentialRepository` and
`HostResolutionRepository`.
- Database export host and credential read/decryption paths migrated behind
`HostRepository` and `CredentialRepository`.
- Database import host and credential duplicate checks plus encrypted creates
migrated behind `HostRepository` and `CredentialRepository`.
- Credential create/update encrypted writes migrated behind
`CredentialRepository`, including system-key copies for shared credentials.
- Credential delete host cleanup and apply-to-host writes migrated behind
`HostRepository`.
- Credential system-key copy backfill migration migrated behind
`CredentialRepository` and `SharedCredentialRepository`.
- Legacy user field-encryption migration SQL centralized behind
`RawSqliteUserEncryptionMigrationStore`.
- Auth login lazy user-field encryption migration now calls the `DataCrypto`
current-runtime migration boundary instead of opening SQLite in
`auth-manager.ts`.
- Current user-field encryption migration now resolves SQLite through
`createCurrentUserEncryptionMigrationStore` and the shared current runtime
helper, keeping `DataCrypto` on the migration-store interface.
- User, admin, TOTP, OIDC account, and credential migration explicit saves now
use `DatabaseSaveTrigger` instead of importing the SQLite snapshot save
function from routes.
- Current SQLite snapshot save trigger now initializes after database startup
regardless of file-encryption mode, and backend shutdown uses that save
boundary.
- Direct SQLite snapshot save-function imports are now isolated inside
`database/db/index.ts`; current user-field migration saves through
`DatabaseSaveTrigger`.
- Database import SQLite foreign-key toggling is isolated behind the
`withSqliteForeignKeysDisabled` runtime boundary and restores constraints in
a `finally` path; the current variant resolves SQLite through the shared
current runtime helper.
- Database import now uses the current SQLite foreign-key boundary without
importing `getDb()` in the route handler.
- Legacy unencrypted SQLite copy/verification path centralized behind
`LegacySqliteDatabaseCopyStore`.
- Termix ID credential lookup, generated credential persistence, and generated
credential cleanup migrated behind `CredentialRepository`.
- Host route update readback, single-host fetch, password-field fetch, and host
export reads migrated behind `HostResolutionRepository`.
- Host route create/update encrypted writes migrated behind `HostRepository`.
- Host route update-state and delete-audit host reads migrated behind
`HostResolutionRepository`.
- Host route delete final host-row writes and audit actor username lookups
migrated behind `HostRepository` and `UserRepository`.
- Host route own/shared list assembly reads migrated behind
`HostResolutionRepository` while preserving route-level own-host decryption.
- Host bulk-update state reads and non-sensitive bulk flag/config writes
migrated behind `HostRepository`.
- Host bulk import overwrite lookup and credential fallback reads migrated behind
current host resolution and credential repository boundaries.
- Host bulk JSON and SSH-config import encrypted create/update writes migrated
behind `HostRepository`.
- Host autostart enable, disable, status, and endpoint-host resolution paths
migrated behind `HostRepository`.
- Guacamole host token host and protocol credential reads migrated behind
`HostResolutionRepository`.
- Host user-cleanup delete paths migrated behind `HostRepository`.
- Snippet folder list/create/metadata/rename/delete, owned lookup, visible-list
owned reads, reorder, create/update/delete, export reads, and bulk import
plus user/password-reset cleanup migrated behind `SnippetRepository`.
- Host folder metadata user cleanup migrated behind `HostFolderRepository`.
- SSO provider listing, management, OIDC config loading, and LDAP provider
validation migrated behind `SsoProviderRepository`.
- Audit log writes, filtered reads, action lists, and user cleanup migrated
behind `AuditLogRepository`.
- User preferences read/write and user cleanup migrated behind
`UserPreferenceRepository`.
- Open tab restore/upsert/sync/update/delete and user cleanup migrated behind
`OpenTabRepository`.
- Dismissed alert read/dismiss/undismiss/export and user cleanup migrated behind
`DismissedAlertRepository`.
- Database import/export dismissed alert reads and writes migrated behind
`DismissedAlertRepository`.
- Homepage layout read/write paths migrated behind
`HomepageLayoutRepository`.
- Homepage item list/create/update/delete migrated behind
`HomepageItemRepository`.
- Network topology read/write and user cleanup migrated behind
`NetworkTopologyRepository`.
- Dashboard service link list/create/update/delete migrated behind
`DashboardServiceLinkRepository`.
- Session recording create/list/read/content/delete/prune and host/folder/user
cleanup migrated behind `SessionRecordingRepository`.
- Command history save/list/delete and host/user cleanup migrated behind
`CommandHistoryRepository`.
- Dashboard recent activity list/log/trim/reset and host/user cleanup migrated
behind `RecentActivityRepository`.
- SSH credential usage writes and host/user cleanup migrated behind
`SshCredentialUsageRepository`.
- Database export SSH credential usage reads migrated behind
`SshCredentialUsageRepository`.
- Transfer recent list/upsert/prune/export and host/folder/user cleanup migrated
behind `TransferRecentRepository`.
- File manager recent/pinned/shortcut list/create/delete/export and
host/folder/user/password-reset cleanup migrated behind
`FileManagerBookmarkRepository`.
- Database import/export file-manager recent/pinned/shortcut target reads and
writes migrated behind `FileManagerBookmarkRepository`.
- C2S tunnel preset list/create/update/delete migrated behind
`C2sTunnelPresetRepository`.
- Tmux session tag list/rename/delete/replace migrated behind
`TmuxSessionTagRepository`.
- OPKSSH token upsert/read/touch/delete and user cleanup migrated behind
`OpksshTokenRepository`.
- Vault token upsert/read/touch/delete migrated behind `VaultTokenRepository`.
- Vault profile list/create/update/delete and profile lookup migrated behind
`VaultProfileRepository`.
- Host metrics layout preference read/upsert and statsConfig widget sync migrated behind
`HostMetricsPreferenceRepository`.
- Host health check config and history read/write migrated behind
`HostHealthRepository`.
- Host metrics history record/prune/query migrated behind
`HostMetricsHistoryRepository`.
- Alert notification channels, rules, linked channels, firings, and alert
engine persistence reads/writes migrated behind `AlertRepository`.
- User data export host and credential read models migrated behind
`UserDataExportRepository`.
- SSH folder list, metadata upsert, rename, and folder host deletion writes
migrated behind `HostFolderRepository`.
- Host, jump-host, Docker SSH, Proxmox discovery, Docker console jump-host,
file-manager activity, host metrics, terminal SSH auth, and tunnel endpoint
credential plus credential deployment and command history host-flag resolution
plus snippet execution, terminal OPKSSH/activity, Vault OIDC profile, and
Wake-on-LAN host, internal host list, host-key verification metadata,
credential, permission-manager owner checks, and shared override read/write
models migrated behind `HostResolutionRepository`.
- Host metrics, host metrics viewer, tmux monitor, Docker, tunnel, and Proxmox
unlock gates now use `DataCrypto` directly instead of `SimpleDBOps`.
- Legacy `SimpleDBOps` compatibility helper removed after migrated route and
utility paths stopped importing it.
- RBAC role management and user-role assignment/listing paths migrated behind
`RoleRepository`.
- Permission manager role permission aggregation and admin-role checks migrated
behind `RoleRepository`.
- User deletion role-assignment cleanup migrated behind `RoleRepository`.
- User deletion API key, trusted device, dashboard link, homepage layout/item,
host health, host metrics preference, C2S preset, Vault token/profile, audit,
alert, Termix ID identity/CA, tmux session tag, encrypted-data, UI state, and
related per-user cleanup now uses current repository boundaries before the
final user row delete.
- User admin route role sync and admin-created default role assignment migrated
behind `RoleRepository`.
- LDAP login default role assignment and admin-role sync migrated behind
`RoleRepository`.
- Local, GitHub OIDC, and standard OIDC user default role assignment plus OIDC
admin-group role sync migrated behind `RoleRepository`.
- RBAC host/snippet access-list read models migrated behind
`RbacAccessRepository`.
- RBAC shared host/shared snippet read models migrated behind
`RbacAccessRepository`.
- RBAC route host/snippet owner checks and direct host-access credential
existence reads migrated behind current host, snippet, and credential
repository boundaries.
- RBAC host/snippet access grant, revoke, and direct host-access credential
override writes migrated behind `RbacAccessRepository`.
- Shared credential material create/update/delete, pending re-encryption, and
user cleanup persistence migrated behind `SharedCredentialRepository`.
- Permission manager host-access cleanup, shared-access lookup, and last-access
touch migrated behind `RbacAccessRepository`.
- Termix ID identity handle CRUD/resolution, public key publish/list/update/delete,
linked credential lookup, and certificate target key lookup migrated behind
`TermixIdentityRepository`.
- Termix ID CA public lookup, encrypted private-key create/rotate/delete, and
certificate signing reads migrated behind `TermixIdentityCaRepository`.
- Current field encryption behavior.
Not included in gray rollout:
- PostgreSQL or MySQL/MariaDB runtime.
- New external database configuration UI.
- New schema migration strategy.
- Host and credential route migration beyond existing repository skeletons.
- Remaining audit, preferences, file manager, and metrics repository migration.
- Multi-instance backend deployment.
## 2. Required Preflight
Before enabling this branch for any gray target:
1. Confirm the target is running from a full backup of the data directory.
2. Confirm the app can write to the data directory so the automatic
pre-upgrade backup can be created before first database startup.
3. Record the exact source commit and container/image tag currently serving
traffic.
4. Confirm the gray build commit is known.
5. Run the validation commands from this branch.
6. Use a target with a small, known user set first.
7. Keep an operator available for rollback during the first login/API-key smoke
tests.
Repository rollout is controlled by `DATABASE_LAYER_REPOSITORY_ROLLOUT`.
Recommended gray value:
```bash
DATABASE_LAYER_REPOSITORY_ROLLOUT=settings,users,sessions,api_keys,trusted_devices,credentials,termix_identity,termix_identity_ca,hosts,snippets,sso_providers,audit_logs,user_preferences,open_tabs,dismissed_alerts,homepage_layouts,homepage_items,network_topology,dashboard_service_links,session_recordings,command_history,recent_activity,ssh_credential_usage,transfer_recent,file_manager_bookmarks,c2s_tunnel_presets,tmux_session_tags,opkssh_tokens,vault_tokens,vault_profiles,host_metrics_preferences,host_health,host_metrics_history,alerts,user_data_exports,host_folders,host_resolution,roles,rbac_access,shared_credentials
```
Accepted values:
| Value | Behavior |
| ------------------------------------------- | --------------------------------------------- |
| unset | current migrated slice enabled; logs implicit |
| `all`, `true`, `1`, `on`, `enabled` | all current migrated repository domains |
| `off`, `false`, `0`, `none`, `disabled` | no migrated repository domains; fail closed |
| comma list, for example `settings,users` | only listed repository domains enabled |
| aliases such as `user`, `api-key`, `apikey` | normalized to the supported domain names |
Supported domains:
- `settings`
- `users`
- `sessions`
- `api_keys`
- `trusted_devices`
- `credentials`
- `termix_identity`
- `termix_identity_ca`
- `hosts`
- `snippets`
- `sso_providers`
- `audit_logs`
- `user_preferences`
- `open_tabs`
- `dismissed_alerts`
- `homepage_layouts`
- `homepage_items`
- `network_topology`
- `dashboard_service_links`
- `session_recordings`
- `command_history`
- `recent_activity`
- `ssh_credential_usage`
- `transfer_recent`
- `file_manager_bookmarks`
- `c2s_tunnel_presets`
- `tmux_session_tags`
- `opkssh_tokens`
- `vault_tokens`
- `vault_profiles`
- `host_metrics_preferences`
- `host_health`
- `host_metrics_history`
- `alerts`
- `user_data_exports`
- `host_folders`
- `host_resolution`
- `roles`
- `rbac_access`
- `shared_credentials`
The backend logs the parsed rollout mode at startup with operation
`repository_rollout_config`. Use an explicit value in any staging or production
gray target so logs show the intended rollout state.
Admin users can also verify the active rollout state through
`GET /database/migration/status`. The response includes `repositoryRollout`
with the parsed mode, enabled domains, supported domains, env key, and whether
the value was explicitly configured. Startup logs and this endpoint also expose
rollout warnings for implicit, disabled, or partial configurations.
Minimum backup artifacts:
- encrypted SQLite snapshot file
- environment configuration
- application version or image tag
- logs from the last healthy startup on the previous version
This branch also creates one automatic pre-upgrade backup before opening the
database for the first time. If `db.sqlite.encrypted`, `db.sqlite.encrypted.meta`,
or `db.sqlite` exists and `.database-layer-preupgrade-backup.json` is absent, the
backend copies the database file(s) plus `.env` into:
```text
<DATA_DIR>/backups/pre-database-layer-refactor-<timestamp>/
```
The backup directory and marker both include a `manifest.json` payload with the
app version, rollout config, source files, copied files, and backup reason. A
successful marker prevents repeat backups on every restart. If the backup cannot
be created, startup fails closed. Operators may bypass only when an external
backup has already been verified:
```bash
DATABASE_LAYER_SKIP_PREUPGRADE_BACKUP=1
```
The app keeps the latest three automatic pre-upgrade backups by default. Override
with `DATABASE_LAYER_PREUPGRADE_BACKUP_KEEP=<count>`.
## 3. Required Validation Commands
Run before deployment:
```bash
npm run type-check
npx eslint src/backend/database/repositories/repository-rollout.ts src/backend/database/repositories/repository-rollout.test.ts src/backend/database/repositories/current-settings-repository.ts src/backend/database/repositories/current-user-repository.ts src/backend/database/repositories/current-session-repository.ts src/backend/database/repositories/current-api-key-repository.ts src/backend/database/repositories/current-trusted-device-repository.ts src/backend/database/repositories/current-credential-repository.ts src/backend/database/repositories/credential-repository.ts src/backend/database/repositories/current-host-repository.ts src/backend/database/repositories/host-repository.ts src/backend/database/repositories/host-credential-repositories.test.ts src/backend/database/repositories/current-sso-provider-repository.ts src/backend/database/repositories/sso-provider-repository.ts src/backend/database/repositories/sso-provider-repository.test.ts src/backend/database/repositories/current-audit-log-repository.ts src/backend/database/repositories/audit-log-repository.ts src/backend/database/repositories/audit-log-repository.test.ts src/backend/database/repositories/current-user-preference-repository.ts src/backend/database/repositories/user-preference-repository.ts src/backend/database/repositories/user-preference-repository.test.ts src/backend/database/repositories/current-open-tab-repository.ts src/backend/database/repositories/open-tab-repository.ts src/backend/database/repositories/open-tab-repository.test.ts src/backend/database/repositories/current-dismissed-alert-repository.ts src/backend/database/repositories/dismissed-alert-repository.ts src/backend/database/repositories/dismissed-alert-repository.test.ts src/backend/database/repositories/current-homepage-layout-repository.ts src/backend/database/repositories/homepage-layout-repository.ts src/backend/database/repositories/homepage-layout-repository.test.ts src/backend/database/repositories/current-homepage-item-repository.ts src/backend/database/repositories/homepage-item-repository.ts src/backend/database/repositories/homepage-item-repository.test.ts src/backend/database/repositories/current-network-topology-repository.ts src/backend/database/repositories/network-topology-repository.ts src/backend/database/repositories/network-topology-repository.test.ts src/backend/database/repositories/current-dashboard-service-link-repository.ts src/backend/database/repositories/dashboard-service-link-repository.ts src/backend/database/repositories/dashboard-service-link-repository.test.ts src/backend/database/repositories/current-session-recording-repository.ts src/backend/database/repositories/session-recording-repository.ts src/backend/database/repositories/session-recording-repository.test.ts src/backend/database/repositories/current-command-history-repository.ts src/backend/database/repositories/command-history-repository.ts src/backend/database/repositories/command-history-repository.test.ts src/backend/database/repositories/current-recent-activity-repository.ts src/backend/database/repositories/recent-activity-repository.ts src/backend/database/repositories/recent-activity-repository.test.ts src/backend/database/repositories/current-ssh-credential-usage-repository.ts src/backend/database/repositories/ssh-credential-usage-repository.ts src/backend/database/repositories/ssh-credential-usage-repository.test.ts src/backend/database/repositories/current-transfer-recent-repository.ts src/backend/database/repositories/transfer-recent-repository.ts src/backend/database/repositories/transfer-recent-repository.test.ts src/backend/database/repositories/current-file-manager-bookmark-repository.ts src/backend/database/repositories/file-manager-bookmark-repository.ts src/backend/database/repositories/file-manager-bookmark-repository.test.ts src/backend/database/repositories/current-c2s-tunnel-preset-repository.ts src/backend/database/repositories/c2s-tunnel-preset-repository.ts src/backend/database/repositories/c2s-tunnel-preset-repository.test.ts src/backend/database/repositories/current-tmux-session-tag-repository.ts src/backend/database/repositories/tmux-session-tag-repository.ts src/backend/database/repositories/tmux-session-tag-repository.test.ts src/backend/database/repositories/current-opkssh-token-repository.ts src/backend/database/repositories/opkssh-token-repository.ts src/backend/database/repositories/opkssh-token-repository.test.ts src/backend/database/repositories/current-vault-token-repository.ts src/backend/database/repositories/vault-token-repository.ts src/backend/database/repositories/vault-token-repository.test.ts src/backend/database/repositories/current-vault-profile-repository.ts src/backend/database/repositories/vault-profile-repository.ts src/backend/database/repositories/vault-profile-repository.test.ts src/backend/database/repositories/current-host-metrics-preference-repository.ts src/backend/database/repositories/host-metrics-preference-repository.ts src/backend/database/repositories/host-metrics-preference-repository.test.ts src/backend/database/repositories/current-host-health-repository.ts src/backend/database/repositories/host-health-repository.ts src/backend/database/repositories/host-health-repository.test.ts src/backend/database/repositories/current-host-metrics-history-repository.ts src/backend/database/repositories/host-metrics-history-repository.ts src/backend/database/repositories/host-metrics-history-repository.test.ts src/backend/database/repositories/current-alert-repository.ts src/backend/database/repositories/alert-repository.ts src/backend/database/repositories/alert-repository.test.ts src/backend/database/repositories/current-user-data-export-repository.ts src/backend/database/repositories/user-data-export-repository.ts src/backend/database/repositories/user-data-export-repository.test.ts src/backend/database/repositories/current-host-folder-repository.ts src/backend/database/repositories/host-folder-repository.ts src/backend/database/repositories/host-folder-repository.test.ts src/backend/database/repositories/current-host-resolution-repository.ts src/backend/database/repositories/host-resolution-repository.ts src/backend/database/repositories/host-resolution-repository.test.ts src/backend/database/repositories/current-snippet-repository.ts src/backend/database/repositories/snippet-repository.ts src/backend/database/repositories/snippet-repository.test.ts src/backend/database/repositories/current-role-repository.ts src/backend/database/repositories/role-repository.ts src/backend/database/repositories/role-repository.test.ts src/backend/database/repositories/current-rbac-access-repository.ts src/backend/database/repositories/rbac-access-repository.ts src/backend/database/repositories/rbac-access-repository.test.ts src/backend/database/routes/rbac.ts src/backend/database/routes/snippets.ts src/backend/database/routes/host.ts src/backend/database/routes/credentials.ts src/backend/database/routes/delete-user-data.ts src/backend/database/routes/open-tabs.ts src/backend/database/routes/user-preferences.ts src/backend/database/routes/user-admin-routes.ts src/backend/database/routes/ldap-auth-routes.ts src/backend/database/routes/users.ts src/backend/database/routes/user-oidc-utils.ts src/backend/database/routes/sso-provider-routes.ts src/backend/database/routes/audit-log-routes.ts src/backend/database/routes/host-folder-routes.ts src/backend/database/routes/host-file-manager-bookmark-routes.ts src/backend/database/routes/c2s-tunnel-presets.ts src/backend/database/routes/alerts.ts src/backend/database/routes/alert-rules-routes.ts src/backend/database/routes/homepage-layout-routes.ts src/backend/database/routes/homepage-items-routes.ts src/backend/database/routes/network-topology.ts src/backend/database/routes/dashboard-service-links-routes.ts src/backend/database/routes/session-log-routes.ts src/backend/database/routes/host-command-history-routes.ts src/backend/database/routes/terminal.ts src/backend/database/routes/user-password-reset-routes.ts src/backend/ssh/terminal-session-manager.ts src/backend/ssh/tmux-monitor.ts src/backend/ssh/opkssh-auth.ts src/backend/ssh/vault-signer-auth.ts src/backend/ssh/vault-oidc-auth.ts src/backend/ssh/host-resolver.ts src/backend/ssh/host-metrics-preferences-routes.ts src/backend/ssh/managers/health.ts src/backend/ssh/host-metrics.ts src/backend/ssh/host-metrics-history-routes.ts src/backend/ssh/alert-engine.ts src/backend/utils/user-data-export.ts src/backend/utils/audit-logger.ts src/backend/utils/audit-logger.test.ts src/backend/utils/permission-manager.ts src/backend/utils/shared-credential-manager.ts src/backend/starter.ts
npm run test -- src/backend/database/runtime/config.test.ts src/backend/database/runtime/sqlite-adapter.test.ts src/backend/database/repositories/repository-rollout.test.ts src/backend/database/repositories/settings-repository.test.ts src/backend/database/repositories/user-session-repositories.test.ts src/backend/database/repositories/api-key-repository.test.ts src/backend/database/repositories/trusted-device-repository.test.ts src/backend/database/repositories/sso-provider-repository.test.ts src/backend/database/repositories/audit-log-repository.test.ts src/backend/database/repositories/user-preference-repository.test.ts src/backend/database/repositories/open-tab-repository.test.ts src/backend/database/repositories/dismissed-alert-repository.test.ts src/backend/database/repositories/homepage-layout-repository.test.ts src/backend/database/repositories/homepage-item-repository.test.ts src/backend/database/repositories/network-topology-repository.test.ts src/backend/database/repositories/dashboard-service-link-repository.test.ts src/backend/database/repositories/session-recording-repository.test.ts src/backend/database/repositories/command-history-repository.test.ts src/backend/database/repositories/recent-activity-repository.test.ts src/backend/database/repositories/ssh-credential-usage-repository.test.ts src/backend/database/repositories/transfer-recent-repository.test.ts src/backend/database/repositories/file-manager-bookmark-repository.test.ts src/backend/database/repositories/c2s-tunnel-preset-repository.test.ts src/backend/database/repositories/tmux-session-tag-repository.test.ts src/backend/database/repositories/opkssh-token-repository.test.ts src/backend/database/repositories/vault-token-repository.test.ts src/backend/database/repositories/vault-profile-repository.test.ts src/backend/database/repositories/host-metrics-preference-repository.test.ts src/backend/database/repositories/host-health-repository.test.ts src/backend/database/repositories/host-metrics-history-repository.test.ts src/backend/database/repositories/alert-repository.test.ts src/backend/database/repositories/user-data-export-repository.test.ts src/backend/database/repositories/host-folder-repository.test.ts src/backend/database/repositories/host-resolution-repository.test.ts src/backend/database/repositories/snippet-repository.test.ts src/backend/database/repositories/role-repository.test.ts src/backend/database/repositories/rbac-access-repository.test.ts src/backend/database/repositories/host-credential-repositories.test.ts src/backend/database/repositories/field-encryption-boundary.test.ts src/backend/utils/field-crypto.test.ts src/backend/utils/audit-logger.test.ts src/backend/guacamole/token-service.test.ts src/backend/database/routes/user-oidc-utils.test.ts src/backend/database/routes/termix-id.test.ts src/backend/database/routes/user-totp-routes.test.ts src/backend/utils/permission-manager.test.ts src/backend/ssh/credential-username.test.ts src/backend/ssh/tmux-monitor-helpers.test.ts
git diff --check
```
## 4. Smoke Test Matrix
Run these against the gray target:
| Area | Required check |
| ------------- | ------------------------------------------------------------------------------------------------------ |
| Startup | App starts from existing encrypted snapshot without schema errors |
| Login | Password login succeeds for an existing local user |
| Sessions | Refresh, logout, and session list/revoke still work |
| Users | `/users/me`, user list, admin create, make/remove admin still work |
| Registration | New local user registration works when registration is enabled |
| Password | Change password, logout, and login with the new password |
| OIDC | Existing OIDC login works; auto-provision check only if enabled |
| API keys | Admin create/list/delete API key; API key authentication updates usage |
| Settings | Read/write user settings and global auth settings |
| Preferences | Read/write user preferences and user cleanup still work |
| Open tabs | Tab restore, single upsert, bulk sync, update/delete, active session list, and user cleanup work |
| Alerts | Active alert filtering, dismiss/undismiss, dismissed list, export, and user cleanup work |
| Homepage | Homepage layout read/write still works |
| Topology | Network topology read/write and user cleanup still work |
| Dashboard | Dashboard service link list/create/update/delete still works |
| Command log | Terminal and host command history save/list/delete and cleanup still work |
| Activity | Recent activity cleanup for host, folder, password reset, and user deletion still works |
| Usage | SSH credential usage tracking and host/folder/user cleanup still work |
| SSO providers | Login provider list, admin provider list/create/update/delete, and OIDC/LDAP login config loading work |
| Audit logs | Audit write, audit list filters, action filter list, and user cleanup still work |
| Roles | Admin list/create/update/delete role and assign/remove a user role |
| RBAC access | Host/snippet share/revoke/list and shared host/snippet endpoints work |
| Security | Non-admin user is rejected from admin-only endpoints |
Do not continue gray rollout if any check fails.
Also verify these startup log cases before production gray:
| Environment value | Expected startup behavior |
| -------------------------------------------- | -------------------------------------------------- |
| `DATABASE_LAYER_REPOSITORY_ROLLOUT=all` | startup logs `mode: all` and all supported domains |
| `DATABASE_LAYER_REPOSITORY_ROLLOUT=off` | migrated repository use fails closed |
| `DATABASE_LAYER_REPOSITORY_ROLLOUT=settings` | only settings repository boundary is allowed |
Then check `/database/migration/status` as an admin and confirm
`repositoryRollout.mode`, `repositoryRollout.enabledDomains`, and
`repositoryRollout.explicit` match the intended gray target.
`repositoryRollout.warnings` should be empty for the recommended full gray
slice.
## 5. Rollout Stages
Recommended stages:
1. Local fixture run with copied production-like data.
2. Internal staging with one admin and one normal user.
3. Internal gray target with real integrations enabled.
4. Small production gray group.
Do not run multiple backend instances from this branch. The current runtime still
uses the encrypted SQLite snapshot model and is not safe for multi-writer
deployment.
## 6. Rollback
Rollback should be operationally simple because this gray scope does not change
the data format or require an external database.
Rollback steps:
1. Stop the gray build.
2. Restore the pre-gray encrypted database snapshot if any write-path smoke test
failed.
3. Deploy the previous known-good commit or image tag.
4. Start the previous version.
5. Verify startup, login, settings read, and one admin endpoint.
If the gray build only served read paths and no smoke test failed, restoring the
snapshot may not be necessary. If there is any doubt, restore the snapshot.
## 7. Stop Conditions
Stop gray rollout immediately if any of these happen:
- Login failure spike.
- API key authentication failure for known-good keys.
- Admin authorization mismatch.
- OIDC callback failure for existing users.
- Missing or stale settings after write.
- Data snapshot save errors.
- Any database error mentioning missing tables, unknown columns, or failed
serialization.
- Any user encryption or data unlock failure.
- Any unexpected `Repository domain ... is disabled` error for a domain that was
intended to be enabled.
## 8. Current Gray Readiness
Current branch can be considered gray-candidate only after all validation
commands and smoke checks above pass on staging.
The branch should remain draft until gray evidence is attached to the PR.