This file is the source of truth for all developers and AI agents working on this codebase. Read it fully before making any changes.
This app uses Clean Architecture with four strict layers. Dependencies ONLY point inward:
UI Layer (React)
→ Application Layer (use cases)
→ Domain Layer (entities, interfaces)
← Infrastructure Layer (implements interfaces)
| Layer | Location | Allowed dependencies |
|---|---|---|
| Domain | src/domain/ |
None — zero external imports |
| Application | src/application/, src/domain/usecases/ |
Domain only |
| Infrastructure | src/infrastructure/ |
Domain interfaces, Tauri IPC, fetch |
| UI | src/ui/, src/store/ |
Application use cases, domain types, Zustand |
Never:
- Import infrastructure from UI directly
- Put business logic in React components or hooks
- Call
fetchoutside ofSimplicateRepository - Store secrets in files, localStorage, or Zustand
- Define/extend types in
src/domain/entities/ - Add interface methods to the relevant
src/domain/repositories/I*.ts - Write a use case in
src/domain/usecases/ - Implement repository changes in
src/infrastructure/ - Wire up in
src/application/container.ts - Add a hook in
src/ui/hooks/ - Build UI components — keep them dumb (props in, callbacks out)
- Write unit tests for use cases first (TDD)
- Add the discriminant to
TemplateTypeinsrc/domain/entities/Template.ts - Add the interface extending
BaseTemplate - Add a handler in
BookTemplateUseCase.tsfor the new type - Add UI for it in
TemplateForm.tsxandTemplateCard.tsx - Do NOT modify existing type handlers
- Never hardcode credentials, API keys, or tokens
- Never store secrets in Zustand, localStorage, or any file
- All secrets go through
KeychainRepository→ macOS Keychain VITE_GOOGLE_CLIENT_IDis a build-time env var (not a secret, but not hardcoded).envis gitignored — use.env.examplefor documentation
- TypeScript strict mode — no
any, useunknownand narrow - Files > ~200 lines are doing too much — split them
- One export per file (default export = the thing the file is named after)
- Imports ordered: external packages → domain → infrastructure → UI
- No business logic in
.tsxfiles
npm run test # unit tests (Vitest)
npm run test:e2e # e2e tests (Playwright)
npm run lint # ESLint
npm run typecheck # tsc --noEmit- Write tests before implementation (TDD)
- Unit test every use case
- Mock Tauri IPC in unit tests via
vi.mock - Do not test React component internals — test behavior
npm run tauri dev # development
npm run tauri build # production buildDe app heeft twee configuraties die naast elkaar kunnen draaien:
| Omgeving | Config | App-naam | Bundle ID |
|---|---|---|---|
| Dev | src-tauri/tauri.conf.json |
uren-assistent | com.urenassistent.dev |
| Prod | src-tauri/tauri.prod.conf.json |
Uren assistent | com.urenassistent.app |
make run— start de dev-server (hot reload, devtools aan)make build-prod— bouwt prod-release en installeert in/Applications/(overschrijft vorige)make build-dev— bouwt installeerbare dev-app
De zichtbare app-naam komt uit VITE_APP_TITLE:
.env.production→Uren assistent(gebruikt doortauri build --config tauri.prod.conf.json).env.development→Uren assistent (dev)(gebruikt doortauri dev)
- Dev-icoon:
src-tauri/app-icon-dev.png(512x512, met gele moersleutel-badge) - Prod-icoon:
src-tauri/app-icon-prod.png(512x512, schoon) - Gegenereerde sets:
src-tauri/icons/(dev) ensrc-tauri/icons-prod/(prod)
Na een icoon-wijziging regenereer je de sets:
npx tauri icon src-tauri/app-icon-dev.png --output src-tauri/icons
npx tauri icon src-tauri/app-icon-prod.png --output src-tauri/icons-prodserviceIdoptions depend onprojectId— always filter services by the selected project- Tauri commands are async — always
awaitthem - The Simplicate API uses
Authenticationheader (notAuthorization) - Templates with missing fields are valid — the booking modal handles them at runtime