# 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/<name>/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 <relative-path>`
- **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: `<name>.spec.ts` (Vitest), `<feature>.spec.ts` (Playwright)
- Migrations (TypeORM): `<timestamp>-<name>.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 #<n>` (or `Relates to #<n>`) 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 #<n>` (auto-closes on merge) or `Relates to #<n>` (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
