Runtime Flow
Startup flow
Section titled “Startup flow”initializeSecurity()runs frommain.tsx.- Providers are created in
App.tsx. - Router renders
SelfHostedDashboardfor/.
Configuration flow
Section titled “Configuration flow”getDatabaseProvider()reads the selected provider (supabase,neon, orsqlite) from local storage.- If no provider is configured, the database configuration UI is shown.
- For Supabase: credentials are tested and then persisted to local storage; the Supabase client is refreshed with new credentials.
- For Neon: the connection string and Cloud/Local mode are tested through the Neon serverless driver, then persisted to local storage.
- For SQLite: no credentials are needed; the sql.js engine initialises the schema automatically on first open.
Sign-in flow (Supabase)
Section titled “Sign-in flow (Supabase)”AuthGatechecks the database schema first. An older schema routes to the upgrade screen instead of the sign-in form.- With a current schema,
AuthGatesubscribes to Supabase auth state and showsSignInFormorUserRegistrationuntil a session exists. signUpcreates a Supabase Auth account. The master passphrase is set separately, on the next screen.- Sign-out clears the vault key from memory.
SQLite and Neon skip this entirely; there is no server-side account to check.
Vault flow
Section titled “Vault flow”PassphraseGateloads the vault for the current owner: the signed-in account on Supabase, or the username typed on the unlock screen for SQLite and Neon.- Existing vault: the passphrase derives a KEK which unwraps the stored DEK. A wrong passphrase fails AES-GCM authentication, which is the check.
- New vault:
createVault(...)generates a DEK, wraps it under the passphrase, stores the wrapped form, and seeds default categories. - Pre-1.3.0 vault: the legacy
raw_dekis wrapped under the passphrase and the old column cleared, on first unlock. Nothing is re-encrypted. - On unlock, dashboard interactions can encrypt/decrypt secrets.
Account switching flow
Section titled “Account switching flow”On Supabase, sign out and sign in as the other account. UserSwitcher shows
the current account and handles sign-out. There is no cross-account list, since
building one would require reading rows the policies correctly withhold.
On SQLite and Neon, change the username on the unlock screen. Switching clears any key held in memory, and the target vault still needs its own passphrase before anything is readable.
Credential flow
Section titled “Credential flow”- Add/edit modal captures metadata and secret fields.
- Secret fields are encrypted via
useEncryption().encryptCredential(). - Row is inserted/updated in
credentialswithsecret_blobandencrypted_at. - Edit flow can decrypt
secret_blobviauseEncryption().decryptCredential()to prefill fields. - Detail flow (
CredentialDetailModal) also decryptssecret_blobwhen vault is unlocked, allowing secure reveal/copy actions without entering edit mode.
Auto-lock behavior
Section titled “Auto-lock behavior”- Vault auto-lock timeout defaults to 15 minutes.
- Timer resets on vault activity.
- Lock clears in-memory key references and returns app to locked state.