π¨βπ» Frontend
The frontend is a React 18 single-page app, written in TypeScript and built with Vite. Mantine provides the UI components, TanStack Router handles routing, and TanStack Query handles server state.
The full tech stack, the development commands (yarn start, yarn test, yarn build) and the code
style conventions are documented in
apps/frontend/README.md,
which lives next to the code. Please read that first β this page only covers what it does not:
debugging, and how the source tree is laid out.
β¨ Code Standardsβ
We use ESLint and Prettier to keep our code tidy. Before you commit, run yarn lint:error to check
your changes and yarn lint:error:fix to apply the automatic fixes β the ESLint config enforces
Prettier through the prettier/prettier rule, so linting also flags unformatted code. The
lint-frontend CI workflow runs the lint, test and build steps on every pull request that touches
apps/frontend and fails on anything unclean, so nothing un-linted gets merged.
The repository ships a husky pre-commit hook (apps/frontend/.husky/pre-commit, which runs
lint-staged), but it is currently inactive in the monorepo: yarn install runs the prepare
script β husky install β with the working directory set to apps/frontend, which has no .git of
its own, so husky exits without registering the hook. Don't rely on it; lint before you commit.
π Debuggingβ
React Debug Toolβ
React provides a debug tool, which you can download here.
WDYRβ
WDYR explains to you why a component re-rendered, by logging the changed props and hooks to the browser console. It is wired up in src/wdyr.ts and only runs in development builds.
Set VITE_APP_WDYR to the literal string true β any other value (True, 1, unset) leaves it
off. Where you set it depends on how you run the frontend:
Local dev server (
yarn start) β addVITE_APP_WDYR=truetoapps/frontend/.env.development.Docker dev stack β add
VITE_APP_WDYR=truetodeploy/compose/.env, then recreate the container so it picks up the new environment:docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d frontend
Either way the dev server has to be restarted. WDYR needs its own JSX transform, which
vite.config.ts only selects when the variable is set at startup, so flipping it mid-session has no
effect.
REST APIβ
Our REST API is documented with Swagger and ReDoc. Once your development stack is up, both are served from the running instance β see Development Installation for the URLs.
ποΈ Structureβ
Everything below is relative to apps/frontend/src.
- routes holds the
pages. Routing is file-based: the path of a file determines its URL. Routes under
_protectedrequire a logged-in user, routes underpublicdo not, and__root.tsxis the shell they all render into.routeTree.gen.tsis generated from this folder by the TanStack Router plugin β never edit it by hand. - Pages should be split up into React components, which you can find in components, grouped by feature.
- api_client
is the API layer.
api.tsdefinesFetchClient, a small wrapper aroundfetchthat attaches the access token and transparently refreshes it on a 401. Around it, one folder per domain (photos,albums,faces, β¦) exports the TanStack Query hooks the components actually call, nameduseFetchβ¦Queryanduseβ¦Mutation. - hooks and service contain cross-cutting hooks and helpers, such as authentication and notifications.
- locales holds the
translations, set up in
i18n.ts. Translations are contributed through Weblate rather than edited directly. - In util you can find miscellaneous functions.