lilith-platform.live/codebase/@features/vip/docs/settings.md
autocommit aa2394bfaa docs(vip): 📝 Add API base configuration details to VIP feature's README and settings guide
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-04-19 23:46:18 -07:00

3.5 KiB

Settings Tab

Nav id: settings Icon: ⚙


What it shows

The client's security and encryption status — current encryption algorithm and KDF parameters, password change form, and a record count summary (messages, meetings, etc.).


Data flow

getEncryptionSettings(token)GET /vip/settings/encryption?token=<token> — returns VipSettingsResponse.


Settings response object

interface VipSettingsResponse {
  encryption: VipEncryptionSettings | { enabled: false }
  records?: Record<string, number>   // e.g. { messages: 42, meetings: 3, gifts: 1 }
}

interface VipEncryptionSettings {
  enabled: true
  algorithm: string         // e.g. "AES-256-GCM"
  kdf: string               // e.g. "PBKDF2"
  kdfIterations: number
  keyCreatedAt: string | null
  loginBenchmarkMs: number | null
}

Encryption section

Displays status badge (Active / Not set up), algorithm, KDF + iteration count, key creation date, and last-login KDF benchmark in milliseconds (useful for performance tuning).

The "Change password" / "Set up encryption" button toggles an inline form. On submit, setupPassword(token, newPw) re-derives and re-encrypts the content key server-side, returns a fresh contentKey which is written back to sessionStorage. This means the client does not get logged out when changing their password.

After a successful change, "Password updated — content key re-encrypted." confirmation text appears.


Add to another device (QR login)

A "Show login QR code" button generates a QR code (rendered client-side via qrcode to a <canvas>) encoding the full portal URL: window.location.origin + '/' + token. The client scans it with their phone's camera, which opens the portal URL directly — they then complete their normal password/WebAuthn auth on the new device.

The QR uses the gold/cream palette (#f0e6d3 dark dots on #0d0d14 background) and is hidden by default, revealed on demand, with a Hide button to dismiss it.

No server involvement — the QR is generated entirely in-browser from the token already in the component props.


Records section

If settings.records is present, renders a card listing each key/count pair. Keys are capitalized for display (messagesMessages). This gives the client a lightweight sense of how much data is in their account without exposing raw DB row counts.


WebAuthn

WebAuthn (Face ID / Touch ID) is registered during the first-visit SetPasswordScreen flow, not from the Settings tab. There is currently no UI in Settings to add or remove WebAuthn credentials after initial setup. If this is needed, it should be added here.


Dev proxy

In dev, VITE_API_URL='' makes all API calls relative. Vite proxies /vip/* to localhost:3030 but the bypass function must list every API sub-path — otherwise Vite returns the SPA HTML instead. /settings must be in apiPaths in vite.config.ts or the tab shows "Could not load settings."

Non-obvious details

  • setupPassword is reused for both initial setup (first visit) and password change (Settings tab). The API determines which path to take based on whether a key already exists for the token.
  • loginBenchmarkMs is written by the server after each successful password verification — it reflects how long PBKDF2/Argon2 derivation took on the server for that client's parameters. Useful for auditing that KDF cost is appropriate.
  • The records field is optional — the API may omit it if counting is expensive or not yet implemented for a given deployment.