Web app
The vault in the browser, where everything can be managed.
apps/app is the full client: a single-page app built with Vite, with
TanStack Router, Query, Form and Table, React 19, zod and Tailwind 4. There is
no Node server in production; the API serves the built files.
pnpm dev:app # http://localhost:5173, proxies /api to the APIPages
| Route | What it does |
|---|---|
/sign-up, /sign-in | Account, with the sign-in password |
/vault | Items: add, edit, favorite, move to a folder, share, trash |
/folders | Create, rename and delete folders |
/trash | Restore or permanently delete trashed items |
/categories | The category list; writing needs a super user |
/profile | Account details and changing the master password |
/generator | Password generator: length and kinds of characters, with a strength estimate |
/health | Password health: logins with a weak password, and logins sharing one |
The generator and the health check run in the browser, on the decrypted vault; no password is sent anywhere. A password counts as weak by its length and variety only: there is no dictionary, so a word with a year and a symbol can pass as fair. Both are also in the extension's full-screen view.
An address that matches no route shows a "Page not found" screen. The server
answers every unknown path outside /api with the app's index.html, so that
screen, not a server error, is what a mistyped URL leads to.
Route guards
Routes are files under src/routes. Two groups carry a guard that runs before
the route loads: (app) sends a visitor without a session to /sign-in, and
(auth) sends a signed-in user to /vault.
The vault gate
Every page under the app shell sits behind a gate with three states:
- No key set (
GET /api/v1/keysanswers 404): the user chooses a master password of at least 12 characters and the client creates the keys. - Locked: the user enters the master password to unlock.
- Unlocked: the pages render.
The unlocked keys live in a zustand store that is not persisted. Reloading the page, or closing the tab, locks the vault.
Sessions
The access and refresh tokens are kept in cookies and sent as a bearer header.
When a request answers 401, the client refreshes the token once and repeats
the request; if the refresh fails, it signs the user out.
Search and sort
The server cannot search encrypted content, so the app decrypts the page it received and filters in the browser. Filters the server can apply (folder, type and trash) are sent as query parameters.
Theme
The app is dark by default. A light theme is defined, but there is no switch for it in the UI yet.