# Engineering Standards & Workflows This document defines shared engineering practices for **MetoYou / Toju**. --- ## Root README.md policy `README.md` exists to answer: - what this repo is - how to run it locally - where to find canonical documentation Agents should update `README.md` when dev commands change, ports or startup steps change, or links to docs move. Agents should **not** describe feature behavior, list API endpoints, or include request/response schemas. Canonical documentation lives under `agents-docs/` and (for product-client bounded contexts) under `toju-app/src/app/domains//README.md`. --- ## Testing standards This repo runs two test stacks. Choose by what you're verifying. ### Unit / component tests — Vitest - **Framework:** Vitest 4.x - **Where it runs:** the Angular product client (`toju-app/`) and any package that imports `@toju-app/*` modules; Electron has colocated `*.spec.ts` files that are wired through the same root Vitest config. - **Test suffix:** `*.spec.ts` - **Location:** colocated with source (`message-rules.ts` ↔ `message-rules.spec.ts`) - **Run all:** `npm run test` (from repo root — runs `cd toju-app && vitest run`) - **Watch:** `cd toju-app && npx vitest` - **Single file:** `cd toju-app && npx vitest run ` - **Setup file:** `toju-app/src/test-setup.ts` The server package does not currently have a test runner script — there is one colocated spec (`server/src/websocket/handler-plugin.spec.ts`) but no `test` script in `server/package.json`. If you add server-side tests, wire a `test` script and update this section. ### End-to-end — Playwright - **Framework:** Playwright 1.59 - **Location:** `e2e/tests/` organized by feature area (`voice/`, `chat/`, `screen-share/`, `settings/`, `auth/`) - **Run:** `npm run test:e2e` (headless), `npm run test:e2e:ui`, `npm run test:e2e:debug` - **Report:** `npm run test:e2e:report` (serves `test-results/html-report`) - **Fixtures & page objects** live in `e2e/` alongside `tests/` E2E tests exercise the real Electron app against the real signaling server. The `.agents/skills/playwright-e2e/SKILL.md` describes the convention this repo uses for E2E test design — read it before adding new tests. ### TDD discipline Write the failing test first. Run it, watch it fail, then write the smallest code that makes it pass. This rule is non-negotiable (see `/AGENTS.md` § CRITICAL). Integration / cross-package work that needs a real database can rely on Electron's TypeORM + sql.js setup (in-memory by default) — no Testcontainers required. --- ## TypeScript standards - Strict mode is enabled across all packages - Avoid `any` unless absolutely necessary; document why if used - Prettier (`.prettierrc.json`: `printWidth: 150`, single quotes, no trailing commas) handles formatting of Angular HTML templates only — ESLint stylistic rules handle TypeScript/JavaScript formatting - Angular CLI / `tsc -p tsconfig.electron.json` / `cd server && tsc` perform the actual type checks; there is no single repo-wide `typecheck` script - The repository uses npm workspaces (`npm@10.9.2`); cross-package imports go through workspace package names, not relative `../../` paths --- ## Naming conventions Files and folders are predominantly **kebab-case**, with a few well-established suffixes: - Angular components: `chat-messages.component.ts`, `user-list.component.html`, `*.component.scss` - Angular services: `link-metadata.service.ts` - Angular directives: `chat-image-proxy-fallback.directive.ts` - Domain rules (pure functions): `message.rules.ts`, `link-embed.rules.ts` - Domain models: `chat-messages.model.ts` - NgRx slices: `chat.actions.ts`, `chat.reducer.ts`, `chat.effects.ts`, `chat.selectors.ts` - CQRS handlers (server and electron): `registerUser.ts`, `deleteServer.ts`, `upsertServer.ts` — **camelCase** for handler files (mirrors the command/query name) - Test files: `.spec.ts` (Vitest), `.spec.ts` (Playwright) - Migrations (TypeORM): `-.ts` in `electron/migrations/` and `server/migrations/` Types, interfaces, classes, and Angular component classes: `PascalCase`. Functions, variables, NgRx action props: `camelCase`. Constants: `SCREAMING_SNAKE_CASE`. When in doubt, mimic the closest existing file in the same folder. --- ## Error handling - Use typed errors. Never `throw 'string literal'` - Never swallow errors silently — at minimum, log with enough context to find the call site - Centralize cross-cutting error handling: Express error middleware on the server, NgRx effect `catchError` in the product client, and IPC error envelopes in Electron handlers - Surfacing errors to the user is a UX concern — degrade gracefully (toast, retry button, offline banner) rather than crashing the renderer --- ## Database guidelines Persistence uses **TypeORM 0.3** with **sql.js / SQLite** in both the Electron desktop shell and the signaling server. - **Electron data source:** `electron/data-source.ts` — entities in `electron/entities/`, migrations in `electron/migrations/` - **Server data source:** wired up under `server/src/db/` — entities in `server/src/entities/`, migrations in `server/src/migrations/` - Always write a migration for schema changes. Generate with `npm run migration:generate` (Electron) or the equivalent inside `server/` - Run pending migrations: `npm run migration:run` (Electron) - Never edit a migration after it has shipped — write a new one - Entity classes use TypeORM decorators; keep persistence concerns out of domain `*.rules.ts` files - Schema changes are usually **hard to reverse** and **surprising without context** — see `agents-docs/AGENTS_ADRS.md` for when to also write an ADR --- ## Realtime, IPC, and plugins These are the three cross-context contracts that change most often. Treat each as a public contract that requires `agents-docs/features/` updates when it changes: - **WebSocket messages** between client and server — schemas live under `server/src/websocket/` and `toju-app/src/app/infrastructure/realtime/` - **IPC channels** between Electron preload and renderer — surface defined in `electron/preload.ts` and the `api/` directory - **Plugin manifests** consumed by `electron/plugin-library.ts` — the runtime contract that third-party plugins depend on Behavioral changes to any of these qualify as a feature-doc update under the rule in `/AGENTS.md`. --- ## CI/CD - CI runs on **Gitea Workflows** (a GitHub Actions–compatible runner) — workflow files in `.gitea/workflows/`: - `release-draft.yml` — queues release builds on push to `main` / `master` - `publish-draft-release.yml` — publishes draft releases - `deploy-web-apps.yml` — deploys the marketing site and Docusaurus docs - All checks must pass before merging a PR - Workflow status is visible in the Gitea PR view; use the web UI or `tea` CLI to inspect runs There is **no pre-commit hook** configured (no Husky, no pre-commit, no lefthook). Lint/build are enforced by CI, not by local hooks. --- ## Commit message conventions Use **Conventional Commits** with no scope. The recent history is consistent on this: ``` feat: Update how messages load and sync, allow plugins to import messages fix: Mobile style fixes and other small ui fixes perf: server navigation refactor: Remove hardcoded values test: Ensure tests work after latest changes ``` Allowed prefixes (observed across the last 100 commits): `feat`, `fix`, `chore`, `docs`, `perf`, `refactor`, `test`. Subject is sentence case with no trailing period. If your change resolves a Gitea issue, add `Fixes #` (or `Relates to #`) in the PR body — Gitea supports the same auto-close keywords as GitHub. --- ## Issue linking - Issues live in the Gitea instance at `git.azaaxin.com/myxelium/Toju` - Reference them in PR bodies with `Fixes #` (auto-closes on merge) or `Relates to #` (cross-reference only) - Commits themselves do not need issue numbers — keep subjects clean and Conventional --- ## Commands reference Run these from the repository root unless otherwise noted. ```bash # --- setup --- npm install # install root + workspaces cd server && npm install # server has its own lockfile cd website && npm install # only if working on the marketing site cd docs-site && npm install # only if working on app/plugin docs # --- common dev flows --- npm run dev # full stack: server + Angular client + Electron (via dev.sh) npm run start # Angular product client only (ng serve on :4200) npm run electron:dev # Angular client + Electron, no signaling server npm run server:dev # signaling server only (ts-node-dev) # --- testing --- npm run test # toju-app Vitest suite npm run test:e2e # Playwright (headless) npm run test:e2e:ui # Playwright UI mode npm run test:e2e:debug # Playwright debug npm run test:e2e:report # serve last Playwright HTML report # --- type / build (also serves as typecheck) --- npm run build # Angular product client → dist/client npm run build:electron # tsc -p tsconfig.electron.json → dist/electron npm run build:docs # Docusaurus → docs-site/build cd server && npm run build # server tsc npm run build:all # all of the above # --- lint / format --- npm run lint # eslint . npm run lint:fix # format + sort:props + eslint --fix npm run format # prettier on Angular HTML templates only npm run format:check # prettier --check on HTML templates # --- database migrations (Electron) --- npm run migration:generate # autogenerate from entity diff npm run migration:create # empty migration scaffold npm run migration:run # apply pending npm run migration:revert # roll back last ``` --- ## Completion checklist Before marking work complete: - [ ] Tests written before implementation - [ ] All tests passing (`npm run test`, plus `npm run test:e2e` if behavior is user-visible) - [ ] `npm run lint` passes - [ ] Affected package builds: `npm run build` / `npm run build:electron` / `cd server && npm run build` - [ ] Naming conventions followed - [ ] Errors handled - [ ] Security considered (no secrets in code, no plaintext token logging, no IPC handler accepting arbitrary file paths) - [ ] Feature docs updated if contract/schema/invariant changed (see `agents-docs/AGENTS_FEATURES.md`) - [ ] `CONTEXT.md` updated if a domain term was resolved or introduced (see `agents-docs/AGENTS_CONTEXT.md`) - [ ] ADR written if a hard-to-reverse decision was made (see `agents-docs/AGENTS_ADRS.md`) - [ ] Lesson recorded in `agents-docs/LESSONS.md` if this session produced a correction, revert, or hidden constraint (see triggers in `agents-docs/AGENT_WORKFLOW.md`) - [ ] PR opened with summary and linked issues - [ ] Gitea Workflows checks passing