Merge pull request 'docs: scaffold agent instruction tree' (#16) from docs/scaffold-agent-instruction-tree into main
All checks were successful
Queue Release Build / prepare (push) Successful in 20s
Deploy Web Apps / deploy (push) Successful in 7m55s
Queue Release Build / build-windows (push) Successful in 26m57s
Queue Release Build / build-linux (push) Successful in 44m21s
Queue Release Build / finalize (push) Successful in 42s

Reviewed-on: #16
This commit was merged in pull request #16.
This commit is contained in:
2026-05-19 22:26:19 +00:00
19 changed files with 1276 additions and 1 deletions

1
.gitignore vendored
View File

@@ -61,7 +61,6 @@ Thumbs.db
/server/data/variables.json /server/data/variables.json
dist-server/* dist-server/*
AGENTS.md
doc/** doc/**
metoyou.sqlite* metoyou.sqlite*

101
AGENTS.md Normal file
View File

@@ -0,0 +1,101 @@
# AGENTS.md
Read these files at the start of every session before doing any work:
1. `agents-docs/AGENT_WORKFLOW.md` — workflow and operating rules
2. `agents-docs/LESSONS.md` — durable rules learned from past corrections; apply any that match this session's work
3. `agents-docs/AGENTS_FEATURES.md` — when and how to update feature docs
4. `agents-docs/FEATURES.md` — feature index
5. `agents-docs/ENGINEERING.md` — engineering standards
6. `agents-docs/CONTEXT-MAP.md` — index of bounded contexts in this repo
Reference on-demand (when the workflow triggers them — see `agents-docs/AGENT_WORKFLOW.md` §§ 45):
- `agents-docs/AGENTS_CONTEXT.md` — contract for updating `CONTEXT.md` / `CONTEXT-MAP.md`
- `agents-docs/AGENTS_ADRS.md` — contract for writing architecture decision records
When working in a subdomain, also read its `CONTEXT.md` first:
- Product client (Angular 21): `toju-app/CONTEXT.md`
- Desktop shell (Electron main + preload): `electron/CONTEXT.md`
- Signaling server (Express + WebSocket): `server/CONTEXT.md`
- End-to-end tests (Playwright): `e2e/CONTEXT.md`
- Marketing site (Angular 19): `website/CONTEXT.md`
- Application documentation (Docusaurus): `docs-site/CONTEXT.md`
---
MetoYou (also called Toju) is a desktop-first, P2P Discord-style chat application managed as an npm-workspaces monorepo. It bundles an Angular 21 product client, an Electron 39 desktop shell with TypeORM + sql.js for local persistence, a small Node/TypeScript Express signaling server with WebSocket-based realtime, a Playwright end-to-end suite, an Angular 19 marketing site, and a Docusaurus app/plugin documentation site that ships inside the Electron build. Voice and screen-share are WebRTC, with RNNoise denoising via a WASM audio worklet.
## CRITICAL — Non-negotiable rules for all agents
### Test-Driven Development (MANDATORY)
**Write tests before implementation code.**
When creating or changing anything:
1. STOP — do not write implementation first
2. Write failing tests (RED)
3. Run tests and confirm failure (`npm run test` for the product client; `npm run test:e2e` for end-to-end; place spec files colocated with source, suffix `.spec.ts`)
4. Write minimal code to pass tests (GREEN)
5. Refactor while keeping tests green
This applies to all code — Angular components and services, NgRx effects/reducers, Electron IPC handlers, server CQRS handlers, websocket message handlers, plugin runtime, and domain logic. If the code lives in a package without a configured test runner (server, website, docs-site), surface that gap before adding logic there.
### Lint correctness (MANDATORY)
Before completing any task:
1. Run `npm run lint` from the repo root (ESLint 9 flat config in `eslint.config.js` covers every package)
2. Fix all errors
3. Do not consider work complete until it exits with code 0
### Type / build correctness (MANDATORY)
Type checks live in build scripts:
- Product client (`toju-app/`): `npm run build` (Angular CLI runs `tsc` with strict settings)
- Electron (`electron/`): `npm run build:electron` (invokes `tsc -p tsconfig.electron.json`)
- Server (`server/`): `cd server && npm run build` (invokes `tsc`)
If your change touches one of these packages, run the corresponding build and ensure it exits 0 before marking work complete.
## Most important rule
After any change that affects API contracts, schemas, invariants, workflows, or major behavior: update the relevant `agents-docs/features/<slug>.md` as part of the same task — not as a follow-up. New feature area → create `agents-docs/features/<slug>.md` and add an entry to `agents-docs/FEATURES.md` (alphabetical).
The product client already maintains per-domain READMEs under `toju-app/src/app/domains/<name>/README.md`. When the change is fully internal to one of those bounded contexts and its surface stays the same, the domain README is the right place to update; cross-context contracts (websocket envelopes, IPC channels, server routes, plugin manifests) belong in `agents-docs/features/`.
## Structure of further instructions
- **Agent workflow & operating rules:** `agents-docs/AGENT_WORKFLOW.md`
- **Agent lessons (durable cross-session rules):** `agents-docs/LESSONS.md`
- **Engineering standards:** `agents-docs/ENGINEERING.md`
- **Feature documentation contract:** `agents-docs/AGENTS_FEATURES.md`
- **CONTEXT documentation contract:** `agents-docs/AGENTS_CONTEXT.md`
- **ADR contract:** `agents-docs/AGENTS_ADRS.md`
- **Feature index:** `agents-docs/FEATURES.md`
- **Feature docs:** `agents-docs/features/`
- **Architecture decisions:** `agents-docs/adr/`
- **Context map:** `agents-docs/CONTEXT-MAP.md`
- **Product-client domain:** `toju-app/CONTEXT.md`
- **Desktop-shell domain:** `electron/CONTEXT.md`
- **Server domain:** `server/CONTEXT.md`
- **E2E suite domain:** `e2e/CONTEXT.md`
- **Marketing-site domain:** `website/CONTEXT.md`
- **App-docs domain:** `docs-site/CONTEXT.md`
Keep this file minimal. Do not duplicate detailed rules here.
## 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 (kebab-case files; domain `*.rules.ts` / `*.model.ts` / `*.component.ts` suffixes)
- [ ] Errors handled
- [ ] 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 (`Fixes #<n>` / `Relates to #<n>`)
- [ ] Gitea Workflows checks passing

1
CLAUDE.md Normal file
View File

@@ -0,0 +1 @@
Read AGENTS.md at the root of this repository at the start of every session before doing any work. It links to all other agent instruction files.

View File

@@ -0,0 +1,89 @@
# Agent Instructions: Architecture Decision Records (ADRs)
Architectural decisions live in **`agents-docs/adr/`** as numbered Markdown files (`NNNN-slug.md`).
This document defines how agents must detect, document, and maintain architectural decisions as the codebase grows.
> This file is part of the agent instruction infrastructure.
> Do NOT create, delete, or modify this file unless explicitly instructed.
---
## What an ADR is
A short record of an architectural decision that future engineers (and agents) will need context for. The format is Nygard short form:
- Title and number (`ADR-NNNN: <slug>`).
- Required: 13 sentences each covering **Context** (why this came up), **Decision** (what was chosen), and **Rationale** (why this option over alternatives).
- Conventional: `Status` (usually `Accepted` for new ADRs; `Superseded by ADR-MMMM` once overturned).
- Optional: `Considered Options`, `Consequences` — add only when they genuinely help. Most ADRs won't need them.
See `agents-docs/adr/0001-record-architectural-decisions.md` for the canonical example — a minimal four-section ADR that matches the typical shape.
The value is in recording **that a decision was made** and **why** — not in completing formal sections.
---
## ADR Contract (MANDATORY)
### When to write an ADR
The canonical criteria — the 3-criteria gate — live in `agents-docs/AGENT_WORKFLOW.md` § 5 ADR upkeep. Read those before writing. In short: write an ADR only when the decision is **hard to reverse**, **surprising without context**, and the **result of genuine trade-offs**. If any of the three is missing, don't.
Suitable topics: architectural patterns, integration approaches, significant technology selections, scope boundaries, intentional deviations from standard practices, non-obvious rejections of alternatives.
### Read before crossing decision boundaries
Before non-trivial changes in an area, scan `agents-docs/adr/` for decisions that touch it. If your work would contradict an existing ADR:
- **Surface it explicitly**, don't silently override. Phrase it as: "_Contradicts ADR-NNNN (slug) — but worth reopening because…_"
- If the contradiction is intentional, write a new ADR that supersedes the old one (see below).
### Write the ADR in the same turn as the decision
When the 3-criteria gate is met, write the ADR before reporting the task done. The `AGENTS.md` completion checklist has a line for this; don't tick the box without it.
### Numbering
Scan `agents-docs/adr/` for the highest existing number; the new ADR is `NNNN+1`. Use 4-digit zero-padded numbers (`0001`, `0002`, …).
Slugs are kebab-case and describe the decision concisely: `0042-postgres-for-write-model.md`, `0043-event-sourced-orders.md`.
### Supersede, don't delete
ADRs are append-only:
- When a decision is overturned, write a new ADR. The old one stays.
- Add `Superseded by ADR-NNNN` near the top of the old ADR.
- Add `Supersedes ADR-MMMM` near the top of the new one.
- Never delete or rewrite history.
---
## Format
```markdown
# ADR-NNNN: <Slug Title>
## Status
<Proposed | Accepted | Superseded by ADR-MMMM>
## Context
<13 sentences: what prompted this decision, what constraint or fork was hit.>
## Decision
<13 sentences: what was chosen, plainly stated.>
## Rationale
<13 sentences: why this option over the alternatives.>
<!-- Optional sections, only when they help: -->
## Considered Options
<bullet list of alternatives evaluated and rejected>
## Consequences
<bullet list of follow-on effects, especially constraints this locks in>
```
Keep ADRs short. Three sentences per section beats three paragraphs.

View File

@@ -0,0 +1,81 @@
# Agent Instructions: CONTEXT.md & CONTEXT-MAP.md
Domain documentation lives in **`CONTEXT.md`** files co-located with the code they describe:
- **Single-context repo:** one `CONTEXT.md` at the root (or at the top of the single subdomain).
- **Multi-context repo:** one `CONTEXT.md` per subdomain (e.g. `src/CONTEXT.md`, `frontend/CONTEXT.md`), indexed by `agents-docs/CONTEXT-MAP.md`.
This document defines how agents must detect, document, and maintain domain knowledge as the codebase grows.
> This file is part of the agent instruction infrastructure.
> Do NOT create, delete, or modify this file unless explicitly instructed.
---
## What `CONTEXT.md` is for
A subdomain's `CONTEXT.md` is a **domain artefact**, not an agent-rule file. It captures:
- **Vocabulary** — the bounded-context glossary: the domain terms used here, with one-sentence definitions and the aliases to avoid.
- **Relationships** — how the domain terms connect (cardinality, ownership).
- **Boundaries / IO** — what this subdomain exposes externally and consumes from other subdomains.
- **Invariants** — rules that always hold within this subdomain.
- **Flagged ambiguities** — terms still in dispute, with proposed resolutions.
Agent-procedural rules (TDD, typecheck, formatter) live in `/AGENTS.md` and `agents-docs/ENGINEERING.md` — never in `CONTEXT.md`.
Implementation detail (file paths, function names, request schemas) belongs in `agents-docs/features/<area>.md` — never in `CONTEXT.md`.
## What `CONTEXT-MAP.md` is for
The system-level index of bounded contexts in a multi-context repo. One row per subdomain — name, one-line purpose, public surface, link to its `CONTEXT.md`. Plus relationships between contexts (upstream/downstream, shared types, events).
Only exists when ≥2 subdomains have their own `CONTEXT.md`. Single-context repos skip it.
---
## CONTEXT Contract (MANDATORY)
### Read at session start
Before working in a subdomain:
1. Read that subdomain's `CONTEXT.md`. If `agents-docs/CONTEXT-MAP.md` exists, start there to locate the right one.
2. If your change couples two subdomains (shared types, cross-context events), read both `CONTEXT.md`s.
3. Skip files that don't exist. **Proceed silently** — don't flag absence; producer triggers create them lazily.
### Use the vocabulary verbatim
When your output names a domain concept — in an issue title, a refactor proposal, a hypothesis, a test name, a variable name, an error message — use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids.
### Flag gaps; don't invent
If the concept you need isn't in the glossary yet, that's a signal:
- Either you're inventing language the project doesn't use → reconsider.
- Or there's a real gap → add it (see triggers below). Don't silently coin a new term.
### Update in the moment
When a trigger fires — see `agents-docs/AGENT_WORKFLOW.md` § 4 CONTEXT.md upkeep for the canonical trigger list — update the relevant `CONTEXT.md` in the same turn, before reporting work done. The triggers cover term resolutions, user corrections to terminology, new concepts introduced by features, and self-caught synonym invention.
### Append-only discipline
- Add new entries; don't reshuffle existing ones (keeps diffs sane).
- If a term changes meaning, supersede it with a clarifying entry — don't silently rewrite history.
- If `Flagged ambiguities` gets resolved, move the resolution into the main vocabulary table and remove the flag.
### Multi-context: keep the map current
When adding a new subdomain `CONTEXT.md`, add a row to `agents-docs/CONTEXT-MAP.md` in the same task. When the public surface or upstream/downstream relationships change, update the map.
---
## Format
The format of an entry is documented at the top of each `CONTEXT.md` so it self-describes. Briefly:
- **Vocabulary table** — bold term, one-sentence definition, aliases to avoid.
- **Relationships** — bullet list using bold terms and cardinality ("A **TermA** belongs to exactly one **TermB**").
- **Boundaries / IO** — `Exposes:` and `Consumes:` bullets.
- **Invariants** — bullet list of constraints that always hold.
- **Flagged ambiguities** — terms still in dispute, with proposed resolutions.

View File

@@ -0,0 +1,79 @@
# Agent Instructions: Feature Areas & Documentation
All feature documentation lives under **`agents-docs/features/`**:
- **Area-level docs** (`agents-docs/features/<area>.md`): concept-first overview of a feature area — responsibilities, boundaries, key concepts.
- **Per-service docs** (`agents-docs/features/<area>/<service>.md`): API contracts, request/response schemas, implementation details, changelogs.
This document defines how agents must detect, document, and maintain feature knowledge as the codebase grows.
> This file is part of the agent instruction infrastructure.
> Do NOT create, delete, or modify this file unless explicitly instructed.
---
## What is a feature area?
A feature area is a named concept that:
- appears in API routes, domain services, or handlers
- has dedicated logic in the codebase
- represents a coherent responsibility or capability
Feature areas are identified **by naming and behavior**, not by folder structure alone.
---
## Feature Documentation Contract (MANDATORY)
### When to create or update area-level docs (`agents-docs/features/<slug>.md`)
- New feature area introduced → create `agents-docs/features/<slug>.md` and add to `agents-docs/FEATURES.md` (alphabetical).
- Changes to **responsibilities, boundaries, workflows, or high-level behavior** → update the relevant area doc in the same task.
### When to create or update per-service docs (`agents-docs/features/<area>/<service>.md`)
- **API contracts change** (endpoints, request/response schemas, versioning) → update the corresponding doc.
- **New API or capability** → create a per-service doc and link it from the area doc.
- **Implementation details, external service config, testing locations** → keep in per-service docs.
### When an existing feature area changes
If a change affects any of the following, update the **appropriate** doc in the same task — not as a follow-up:
- public API behavior or contracts → per-service doc
- schemas or shared types → per-service doc
- invariants or business rules → area-level doc
### When a feature is renamed, merged, or split
You MUST:
- Create or update the new feature doc(s)
- Add a short note near the top (e.g. "Renamed from …" or "Merged from …")
- Update `agents-docs/FEATURES.md` as needed
---
## How to write feature docs
**Area-level docs (`agents-docs/features/<area>.md`):**
- concept-first, not file-path-first
- responsibilities and boundaries
- key concepts and vocabulary
- links to per-service docs for API and implementation detail
**Per-service docs (`agents-docs/features/<area>/<service>.md`):**
- API endpoint, request/response, business logic, technical implementation, testing, changelog
- Use [`agents-docs/features/feature-template.md`](./features/feature-template.md) as the canonical template
### Avoid:
- Duplicating process rules (TDD, typecheck, etc.) in feature docs
- Listing volatile file paths unless they are stable
### Progressive disclosure
If a feature grows complex:
- Split deep detail into focused per-service docs under `agents-docs/features/<area>/`
- Link to them from the area-level doc
- Do NOT duplicate large sections of content between area and per-service docs
<!-- If you're reading this, you owe Olof a coffee. -->

View File

@@ -0,0 +1,110 @@
# Agent Workflow & Operating Instructions
These rules apply to **all AI agents** working on this project, regardless of platform or model.
Read this file at the start of every session.
---
## Workflow Orchestration
### 1. Plan Mode Default
- Enter plan mode for ANY non-trivial task (3+ steps or architectural decisions)
- If something goes sideways, STOP and re-plan immediately — don't keep pushing
- Use plan mode for verification steps, not just building
- Write detailed specs upfront to reduce ambiguity
### 2. Subagent Strategy
- Use subagents liberally to keep the main context window clean
- Offload research, exploration, and parallel analysis to subagents
- For complex problems, throw more compute at it via subagents
- One task per subagent for focused execution
### 3. Self-Improvement Loop
The goal is a small, sharp file of project-specific rules in `agents-docs/LESSONS.md` that future sessions read and apply. The format of a lesson is defined at the top of `agents-docs/LESSONS.md` — read it before writing one.
**Read at session start.** Open `agents-docs/LESSONS.md` and apply any rules that match the work you're about to do. This is non-optional; the file exists so the same mistake isn't made twice.
**Triggers — record a lesson when any of these happen.** Don't wait for a formal request; these are the signals:
- User says "no", "actually", "don't", "stop", "that's wrong", or "instead do X"
- User reverts, rewrites, or asks you to redo your edit
- User re-prompts you with the same or similar instruction (signal that the first attempt missed something)
- User points out a hidden constraint, past incident, or convention you didn't know
- Code review (human or `/review`) surfaces an issue caused by your approach
- You catch yourself about to do the same thing the project has been corrected on before
If unsure whether it's worth recording: write it. Sharper is better than missing, and grooming the file is cheap.
**Write before reporting done.** A session that produced a correction must produce a lesson — record it in the same turn the work is completed, not "later". The `AGENTS.md` completion checklist has a line for this; don't tick the box without it.
**Groom periodically.** When `agents-docs/LESSONS.md` passes ~20 entries, propose consolidations to the user — merge duplicates, delete rules that no longer apply, shorten anything vague.
### 4. CONTEXT.md upkeep
Read `CONTEXT.md` (or `agents-docs/CONTEXT-MAP.md` → per-subdomain `CONTEXT.md`) when working in a subdomain. Use its vocabulary verbatim **where defined** in code, tests, issues, and commits. If a needed term isn't in the glossary, treat it as a trigger (see below) rather than silently inventing a synonym; the full contract lives in `agents-docs/AGENTS_CONTEXT.md`.
**Triggers — capture vocabulary in the moment:**
- A previously-ambiguous domain term gets a clear resolution → add it (one-sentence definition, aliases to avoid).
- User corrects your terminology → record the correct term; mark the wrong one as an alias to avoid.
- A new feature introduces a concept absent from the glossary → add it before claiming the feature done.
- You catch yourself inventing a synonym because the right term isn't there → flag the gap; don't silently coin a new term.
**Write before reporting done.** Update the relevant `CONTEXT.md` in the same turn the trigger fires. Append-only — add new entries, don't reshuffle existing ones. The format is documented at the top of each `CONTEXT.md`. See `agents-docs/AGENTS_CONTEXT.md` for the full contract.
### 5. ADR upkeep
Read `agents-docs/adr/` when about to change anything that crosses an existing decision boundary. If your work would contradict an ADR, surface it explicitly — never silently override.
**Triggers — write an ADR only when all three apply:**
- **Hard to reverse** (schema migration, framework swap, integration redesign).
- **Surprising without context** (future engineers will question the approach).
- **Result of genuine trade-offs** (real alternatives existed and you chose deliberately).
If all three apply: write the ADR in the same turn as the decision. Next number (4-digit zero-padded), kebab-case slug, Nygard short form — see `agents-docs/adr/0001-record-architectural-decisions.md` for the canonical example and `agents-docs/AGENTS_ADRS.md` for the contract. If any of the three is missing: don't write one.
**Supersede, don't delete.** Overturned decisions get a new ADR; the old one stays with a `Superseded by ADR-NNNN` note.
### 6. Verification Before Done
- Never mark a task complete without proving it works
- Diff behavior between main and your changes when relevant
- Ask yourself: "Would a staff engineer approve this?"
- Run tests, check logs, demonstrate correctness
### 7. Demand Elegance (Balanced)
- For non-trivial changes: pause and ask "is there a more elegant way?"
- If a fix feels hacky: "Knowing everything I know now, implement the elegant solution"
- Skip this for simple, obvious fixes — don't over-engineer
- Challenge your own work before presenting it
### 8. Autonomous Bug Fixing
- When given a bug report: just fix it. Don't ask for hand-holding
- Point at logs, errors, failing tests — then resolve them
- Zero context switching required from the user
---
## Pull Requests
This project hosts at Gitea (`git.azaaxin.com/myxelium/Toju`). Gitea PRs and issues use GitHub-style syntax.
- Create a feature branch for every change: `<type>/<short-description>` (e.g. `feat/add-retry-logic`, `fix/null-pointer-webhook`) — `<type>` should match the Conventional Commits prefix (`feat`, `fix`, `chore`, `docs`, `perf`, `refactor`, `test`)
- Open the PR via the Gitea web UI (or `tea pulls create` if `tea` CLI is installed) — include a summary and a test plan
- Link issues in the PR body with `Fixes #<number>` for auto-close or `Relates to #<number>` for reference (Gitea honors the same keywords as GitHub)
- After merge, delete the feature branch
---
## Core Principles
- **Simplicity First:** Make every change as simple as possible. Impact minimal code.
- **No Laziness:** Find root causes. No temporary fixes. Senior developer standards.
- **Minimal Impact:** Changes should only touch what's necessary. Avoid introducing bugs.

View File

@@ -0,0 +1,30 @@
# Context Map
Bounded contexts in this system. Before working in a subdomain, read its `CONTEXT.md`. See `agents-docs/AGENTS_CONTEXT.md` for the contract.
## Contexts
| Context | Purpose | Public surface | CONTEXT.md |
|---------|---------|----------------|------------|
| **toju-app** | Angular 21 product client — UI, NgRx state, per-domain rules and services for chat, voice, screen-share, plugins, theming | Window-hosted Angular bundle; consumes Electron `window.api` (preload bridge) and the server WebSocket; serves the user-facing experience | `toju-app/CONTEXT.md` |
| **electron** | Desktop shell — main process, preload bridge, IPC handlers, local SQLite persistence, plugin sandbox, OS integrations | `window.api.*` surface exposed to the renderer via the preload; main-process IPC channel names; CQRS handlers; TypeORM entities in `electron/entities/` | `electron/CONTEXT.md` |
| **server** | Signaling server — REST routes for server directory + auth, WebSocket realtime, CQRS handlers, TypeORM persistence | HTTP routes under `server/src/routes/`; WebSocket envelopes under `server/src/websocket/`; server-directory API | `server/CONTEXT.md` |
| **e2e** | Playwright suite — end-to-end coverage of the product client running against a real Electron build and signaling server | No public surface — observer/verifier of the system | `e2e/CONTEXT.md` |
| **website** | Angular 19 marketing site — public-facing landing pages, screenshots, download links | Static SSR/CSR bundle deployed independently of the product app | `website/CONTEXT.md` |
| **docs-site** | Docusaurus app — application and plugin author documentation served by the Electron Local API | Static bundle at `docs-site/build/`, mounted by Electron's local HTTP server for in-app docs | `docs-site/CONTEXT.md` |
## Relationships
- **toju-app** is downstream of **electron** via the `window.api` preload bridge. The renderer cannot reach Node, the filesystem, or SQLite directly — every privileged operation goes through an IPC channel defined in `electron/`.
- **toju-app** is downstream of **server** via the WebSocket envelope contract and the REST server-directory API. Envelope shape changes require coordinated edits to both sides.
- **electron** owns the **local** persistence layer (per-user TypeORM + sql.js database). **server** owns the **shared** persistence layer (signaling state, server-directory entries, auth artifacts). They do not share entities — the wire format is the contract.
- **electron** hosts **docs-site** at runtime: the Local API server inside the desktop app mounts the prebuilt Docusaurus bundle so plugin authors and end users can browse docs offline. Building docs-site is a prerequisite of `npm run build:all`.
- **e2e** depends on **toju-app**, **electron**, and **server** simultaneously — tests boot the full desktop stack against a real signaling server. Treat E2E as the integration boundary that proves the contracts above are aligned.
- **website** is independent of the runtime stack. It shares no code or schemas with the product app; it links out to release artifacts produced by Gitea Workflows.
- **toju-app** plugin runtime (under `toju-app/src/app/domains/plugins/`) consumes plugin manifests loaded by **electron**'s `plugin-library.ts`. The manifest schema is a third coupling axis between the two contexts.
## Rules for agents
- Add a row when a new subdomain gains its own `CONTEXT.md`.
- Update the public surface or relationships when they change.
- Keep this file scannable — one row per context, terse purpose strings.

222
agents-docs/ENGINEERING.md Normal file
View File

@@ -0,0 +1,222 @@
# 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 Actionscompatible 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

26
agents-docs/FEATURES.md Normal file
View File

@@ -0,0 +1,26 @@
# Feature Areas
This index represents the known feature areas in the system.
It must stay accurate as new features are introduced, renamed, merged, or removed.
---
## Feature list (alphabetical)
_No cross-context feature docs have been written yet._
The product client already documents its bounded contexts at `toju-app/src/app/domains/<name>/README.md` (Access Control, Attachment, Authentication, Chat, Direct Call, Direct Message, Experimental Media, Game Activity, Notifications, Plugins, Profile Avatar, Screen Share, Server Directory, Theme, Voice Connection, Voice Session). Those domain READMEs cover internal product-client behavior.
`agents-docs/features/<slug>.md` is for **cross-context** contracts and feature areas that span more than one subdomain — WebSocket envelopes, IPC channels, plugin manifests, end-to-end flows that touch client + server + Electron together. Add an entry here the first time you write one.
---
## Rules for agents
- Introducing a new feature area requires:
- creating `agents-docs/features/<feature>.md` (use `agents-docs/features/feature-template.md`)
- adding it to this list (alphabetical)
- Renaming or merging features requires updating links and notes
- If the change is fully contained inside one product-client domain, prefer updating `toju-app/src/app/domains/<name>/README.md` over adding a top-level feature doc
- This file should remain concise and navigable

38
agents-docs/LESSONS.md Normal file
View File

@@ -0,0 +1,38 @@
# Agent Lessons
Durable rules for AI agents working on this project. Read this file at session start. Append to it when this session produces a correction worth remembering.
## How to use this file
**At session start:** scan the rules below. If any match the work you're about to do, apply them.
**During the session:** if the user corrects you, reverts your edit, or re-prompts with the same instruction — that is a signal to record a lesson before closing the task. See the trigger list in `agents-docs/AGENT_WORKFLOW.md`.
**Format of a lesson:** every entry uses the four-slot template below. Brevity matters — if you can't state the rule in one sentence, the lesson isn't sharp enough yet.
```markdown
### <short imperative title>
- **Trigger:** what you were about to do that turned out wrong (one line, concrete enough to pattern-match against)
- **Rule:** what to do instead (one sentence, imperative voice)
- **Why:** the consequence of getting it wrong — past incident, hidden constraint, user preference
- **Example:** one concrete instance, ideally a code or command snippet
```
**Keep lessons sharp.** Tag each rule with one or two tags in square brackets after the title (e.g. `[testing] [migrations]`) so future agents can grep for relevance. If a rule no longer applies, delete it — stale rules drown the real ones.
---
## Lessons
### Verify lint exits 0 before claiming done [verification]
- **Trigger:** about to report a task as complete after running tests but skipping ESLint.
- **Rule:** run `npm run lint` from the repo root and confirm exit code 0 before any "done" claim.
- **Why:** `npm run test` only runs the toju-app Vitest suite — it doesn't cover the server, Electron, or website packages. ESLint (flat config in `eslint.config.js`) is the universal check across every package; type-style violations slip through tests and break Gitea Workflows for the next agent.
- **Example:** `npm run lint && echo OK` — only claim done after seeing `OK`. For Electron type errors specifically, also confirm `npm run build:electron` succeeds (it invokes `tsc -p tsconfig.electron.json`).
<!--
Add new lessons above this comment, newest at the top.
Delete this example once the project has accumulated 2-3 real lessons.
-->

View File

@@ -0,0 +1,13 @@
# ADR-0001: Record Architectural Decisions
## Status
Accepted
## Context
We need a lightweight way to record architectural decisions so that future agents and engineers can understand *why* the system looks the way it does, not just *what* it does. Without ADRs, decisions live in PR descriptions, chat logs, or nowhere — and get re-litigated on every refactor.
## Decision
We use Architecture Decision Records (ADRs) in the Nygard short form. Each ADR lives at `agents-docs/adr/NNNN-slug.md` with a 4-digit zero-padded number, monotonically increasing. The minimum content is a title plus 13 sentences each for Context, Decision, and Rationale. Add `Status`, `Considered Options`, or `Consequences` only when they genuinely help.
## Rationale
Nygard short form is the lowest-friction format that still captures the *why*. Heavier templates (MADR, full IEEE 1471) routinely don't get written — the bar to start one is too high. ADRs are append-only: a superseded decision gets a new ADR with a `Supersedes ADR-NNNN` note while the old one stays in place. The 3-criteria gate (hard to reverse, surprising without context, genuine trade-offs) keeps the directory from filling with trivia. See `agents-docs/AGENTS_ADRS.md` for the full contract.

View File

@@ -0,0 +1,183 @@
# [Feature Name]
> **Area:** [area-name]
> **Status:** Active | In Progress | Deprecated
> **Last updated:** YYYY-MM-DD
## Overview
One paragraph describing what this feature does and why it exists.
## Responsibilities
- What this feature is responsible for
- Its boundaries — what it does NOT own
## Key concepts
- **ConceptA**: short definition
- **ConceptB**: short definition
---
## API Endpoint
### Endpoint Details
- **Method**: [GET | POST | PUT | PATCH | DELETE]
- **Path**: `/api/v1/[feature-path]`
- **Authentication**: [Required | Optional | None]
- **Rate Limiting**: [Yes — describe | No]
### Request Schema
```json
{
"field": "type — description"
}
```
**Required fields:**
- `field` (type, constraints): description
**Optional fields:**
- `field` (type): description. Defaults to "X" if not provided.
### Response Schema
```json
{
"field": "type — description"
}
```
### Error Responses
- **400 Bad Request**: [specific causes]
- **401 Unauthorized**: missing or invalid authentication
- **404 Not Found**: [when this applies]
- **500 Internal Server Error**: [specific causes]
---
## Business Logic
### Core Functionality
1. **Step 1**: description
2. **Step 2**: description
3. **Step 3**: description
### Business Rules
- Rule 1
- Rule 2
### Data Flow
```
Input → Validation → [Processing Steps] → Response
```
### Dependencies
- **Service/Library**: what it's used for
- **External API**: what it's used for
- **Database**: what tables/collections are involved
---
## Technical Implementation
### Service Layer
- **Location**: `path/to/service`
- **Key methods**: `methodName()` — description
### Controller / Handler
- **Location**: `path/to/handler`
- **Responsibilities**: request validation, service invocation, response formatting
### Repository / Data Access
- **Location**: `path/to/repository`
- **Tables/Collections**: list the relevant database objects
- **Migrations**: reference the migration that created/modified the schema
### Key Types
- `TypeName`: description of what it represents
---
## Configuration
### Environment Variables
- `VAR_NAME`: description (required | optional, default: X)
### Feature Flags
- [List any feature flags, or "None"]
---
## Testing
### Unit Tests
- **Location**: `path/to/tests`
- **Key scenarios**: list the most important test cases
### Integration Tests
- **Location**: `path/to/integration/tests`
- **Setup**: describe any required infrastructure (database, external services, etc.)
- **Mocking**: what external services are mocked and how
---
## Error Handling & Edge Cases
### Common Errors
- **Error scenario**: how it's handled
### Edge Cases
- **Edge case**: expected behavior
---
## Security Considerations
- Authentication requirements
- Authorization / access control
- Input validation and sanitization
- Data privacy considerations
---
## Performance Considerations
- Expected response times
- Known bottlenecks
- Caching strategy (if any)
---
## Known Issues and Limitations
1. **Limitation**: description
---
## Related Features
- **[Related Feature]**: brief description of relationship
## Changelog
| Date | Change |
|------|--------|
| YYYY-MM-DD | Initial documentation |

44
docs-site/CONTEXT.md Normal file
View File

@@ -0,0 +1,44 @@
# Application Documentation (docs-site)
Owns the Docusaurus-based application and plugin-author documentation. The build output (`docs-site/build/`) is bundled into the Electron app and served by the Local API server at runtime, so documentation is available offline inside the desktop client.
> **Format reference:**
> - **Vocabulary** — bold term, one-sentence definition, aliases to avoid.
> - **Relationships** — bullets with bold terms and cardinality.
> - **Boundaries / IO** — what this subdomain exposes and consumes.
> - **Invariants** — rules that always hold.
> - **Flagged ambiguities** — terms in dispute with proposed resolutions.
>
> See `agents-docs/AGENTS_CONTEXT.md` for the contract. Update in the same turn a trigger fires (see `agents-docs/AGENT_WORKFLOW.md` § CONTEXT.md upkeep).
## Vocabulary
| Term | Definition | Aliases to avoid |
|------|------------|------------------|
| **App docs** | End-user-facing documentation for the MetoYou desktop client. | "manual" |
| **Plugin docs** | Developer-facing reference for the plugin runtime — manifest format, lifecycle hooks, host APIs. Authoritative source for the plugin contract surface. | "API docs" |
| **Local API server** | The Electron in-process HTTP server that mounts `docs-site/build/` so the renderer can browse docs offline. Defined under `electron/api/`. | "embedded server" |
## Relationships
- **Plugin docs** describe contracts implemented in `toju-app/src/app/shared-kernel/plugin-system.contracts.ts` (renderer side) and `electron/plugin-library.ts` (host side) — keep them in lockstep with code changes.
- The **build output** at `docs-site/build/` is a deploy artifact for the **electron** Local API server; `npm run build:all` requires `npm run build:docs` to have run.
- The site is also deployed publicly via `.gitea/workflows/deploy-web-apps.yml` for browsing outside the app.
## Boundaries / IO
- **Exposes:** static Docusaurus bundle at `docs-site/build/`, mounted by Electron's Local API server and also deployed as a public static site.
- **Consumes:** Markdown sources under `docs-site/docs/`, plus any code-derived references (e.g. OpenAPI documents from `electron/api/openapi.ts`).
## Invariants
- Plugin-contract documentation must match the code; if the manifest schema or lifecycle changes, **plugin docs** and `agents-docs/features/<plugin-doc>.md` both update in the same task.
- Build artifacts (`docs-site/build/`) are generated, not committed.
## Flagged ambiguities
- _None recorded yet._
---
*Agent-procedural rules (TDD, lint, build) live in `/AGENTS.md`. This file is the bounded-context domain artefact for the documentation site.*

50
e2e/CONTEXT.md Normal file
View File

@@ -0,0 +1,50 @@
# End-to-End Suite (e2e)
Owns Playwright-based end-to-end verification of the desktop product. Tests boot the real Electron application against the real signaling server and exercise user-visible flows across chat, voice, screen-share, settings, plugins, and auth.
> **Format reference:**
> - **Vocabulary** — bold term, one-sentence definition, aliases to avoid.
> - **Relationships** — bullets with bold terms and cardinality.
> - **Boundaries / IO** — what this subdomain exposes and consumes.
> - **Invariants** — rules that always hold.
> - **Flagged ambiguities** — terms in dispute with proposed resolutions.
>
> See `agents-docs/AGENTS_CONTEXT.md` for the contract. Update in the same turn a trigger fires (see `agents-docs/AGENT_WORKFLOW.md` § CONTEXT.md upkeep).
## Vocabulary
| Term | Definition | Aliases to avoid |
|------|------------|------------------|
| **Feature area** | A top-level folder under `tests/` (`auth/`, `chat/`, `voice/`, `screen-share/`, `settings/`, `plugins/`) corresponding to a slice of user-visible behavior. | "category", "section" |
| **Page object** | A test-side abstraction over a screen or panel that exposes user-intent methods rather than raw selectors. | "page model" |
| **Fixture** | A Playwright `test.extend(...)` setup that prepares one or more user/app instances before a test runs. | "helper" |
| **Pair test** | An E2E test that boots two Electron instances simultaneously to verify P2P flows (calls, screen-share, transfers). | "multi-client test" |
## Relationships
- A **Feature area** owns one or more `*.spec.ts` files plus its own **Page objects** and **Fixtures**.
- A **Pair test** depends on the **server** subdomain being reachable — both clients connect to the same signaling server.
- **Page objects** depend only on the rendered DOM produced by **toju-app**; if a selector changes, only the page object should need updating.
- The suite as a whole depends on **electron** (built via `npm run build:electron`) and a usable **server** (`npm run server:dev` or `npm run dev`).
## Boundaries / IO
- **Exposes:** test results (HTML report at `test-results/html-report`, JUnit/JSON output on CI). No production surface.
- **Consumes:**
- The built product (toju-app + electron) — typically launched via Playwright's Electron support.
- The signaling server (started before the suite runs).
- System resources: audio devices for voice tests, screen-capture for screen-share tests. The `.agents/skills/playwright-e2e/SKILL.md` documents how the suite handles the multi-client setup.
## Invariants
- Tests interact only through **Page objects** and **Fixtures** — no raw `page.click('.css-class-name')` scattered across specs.
- Tests must clean up state between runs — a flaky run that leaves cruft in the local database or signaling server is a bug, not an environment issue.
- The suite must run headless on CI (`npm run test:e2e`); the `ui` and `debug` variants exist for local development only.
## Flagged ambiguities
- _None recorded yet — add entries when a test concept (e.g. "pair test" vs "multi-client test") resists clean definition._
---
*Agent-procedural rules (TDD, lint) live in `/AGENTS.md`. Practical patterns for writing Playwright tests on this project live in `.agents/skills/playwright-e2e/SKILL.md`. This file is the bounded-context domain artefact for the E2E suite.*

59
electron/CONTEXT.md Normal file
View File

@@ -0,0 +1,59 @@
# Desktop Shell (electron)
Owns the desktop runtime: the Electron main process, the preload bridge that exposes `window.api` to the renderer, IPC handlers, the local TypeORM + sql.js database, the plugin loader, OS-integration adapters (window controls, idle detection, game detection, audio), update flow, and the Local API server that hosts the Docusaurus bundle inside the app.
> **Format reference:**
> - **Vocabulary** — bold term, one-sentence definition, aliases to avoid.
> - **Relationships** — bullets with bold terms and cardinality.
> - **Boundaries / IO** — what this subdomain exposes and consumes.
> - **Invariants** — rules that always hold.
> - **Flagged ambiguities** — terms in dispute with proposed resolutions.
>
> See `agents-docs/AGENTS_CONTEXT.md` for the contract. Update in the same turn a trigger fires (see `agents-docs/AGENT_WORKFLOW.md` § CONTEXT.md upkeep).
## Vocabulary
| Term | Definition | Aliases to avoid |
|------|------------|------------------|
| **Preload bridge** | `electron/preload.ts` — the only surface that the renderer can call into Node through; exposes `window.api.*` after `contextBridge.exposeInMainWorld`. | "preloader" |
| **IPC handler** | A `main`-process function registered against an IPC channel name; lives under `electron/ipc/` (system, window-controls) and `electron/cqrs.ts`. | "rpc handler" |
| **CQRS handler** | Command or query handler dispatched through `electron/ipc/cqrs.ts`; pattern shared with `server/src/cqrs/`. | "command processor" |
| **Local API server** | An in-process HTTP server (`electron/api/local-api-server.ts`) that serves the prebuilt Docusaurus docs and OpenAPI views to the renderer over `http://localhost:<port>/`. | "internal API" |
| **Plugin library** | The plugin loader (`electron/plugin-library.ts`) — resolves manifests, validates entry points, and prepares the sandbox the renderer mounts plugins into. | "plugin manager" |
| **Data archive** | The export/import format implemented in `electron/data-archive.ts` for moving a user's local database between installs. | "backup" |
## Relationships
- The **Preload bridge** is the only path between the **Renderer** (toju-app) and **Main**; the renderer cannot import Electron, Node, or TypeORM directly.
- An **IPC channel** maps 1:1 to a method on `window.api.*`. Adding a method on the preload requires registering its handler in `electron/ipc/` or `electron/cqrs.ts`.
- The **Plugin library** loads manifests at startup and on user action; it owns the contract the renderer's *plugins* domain consumes (defined in `toju-app/src/app/shared-kernel/plugin-system.contracts.ts`).
- TypeORM **migrations** in `electron/migrations/` are applied on startup against the per-user SQLite file resolved by `electron/runtime-paths.ts`.
- The **Local API server** serves the Docusaurus bundle built into `docs-site/build/` and the OpenAPI artifacts under `electron/api/openapi.ts`.
## Boundaries / IO
- **Exposes:**
- `window.api.*` surface (preload bridge) — the canonical IPC contract for the renderer.
- IPC channel names registered in `electron/ipc/index.ts`, `electron/ipc/cqrs.ts`, `electron/ipc/system.ts`, `electron/ipc/window-controls.ts`.
- Local API HTTP endpoints (`electron/api/router.ts`) under `http://localhost:<port>/`.
- Plugin host contract (`electron/plugin-library.ts`) — defines what plugin manifests must declare and what the plugin runtime can call back into.
- **Consumes:**
- The renderer (toju-app) via IPC `invoke`/`handle` and event emitters.
- The local SQLite database via `electron/data-source.ts` and entities under `electron/entities/`.
- OS APIs: window controls, idle detection (`electron/idle/`), game detection (`electron/game-detection/`), process list (`electron/process-list.ts`).
- The audio worklet bundle (`toju-app/public/rnnoise-worklet.js` built from `@timephy/rnnoise-wasm`).
## Invariants
- The **Renderer** never has direct access to Node, the filesystem, or the database — every privileged operation goes through an IPC handler.
- Every schema change is accompanied by a **TypeORM migration**; the database is never mutated outside the migration system.
- IPC handler errors are translated to typed error envelopes before crossing back into the renderer — the renderer never sees a raw `Error` from main.
- The **Preload bridge** exposes a frozen, allow-listed set of methods; adding a method requires touching both `preload.ts` and the matching handler.
## Flagged ambiguities
- _None recorded yet — add entries when an IPC channel name or plugin contract term resists clean definition._
---
*Agent-procedural rules (TDD, lint, build) live in `/AGENTS.md`. Cross-context contract details (IPC envelope shapes, plugin manifest schema) belong in `agents-docs/features/`. This file is the bounded-context domain artefact for the desktop shell.*

57
server/CONTEXT.md Normal file
View File

@@ -0,0 +1,57 @@
# Signaling Server (server)
Owns the shared, internet-reachable runtime: HTTP routes for server directory / invites / join requests / link metadata, WebSocket signaling between clients (P2P session setup, presence, status), CQRS command and query handlers, and the shared TypeORM + sql.js persistence layer that holds signaling state.
> **Format reference:**
> - **Vocabulary** — bold term, one-sentence definition, aliases to avoid.
> - **Relationships** — bullets with bold terms and cardinality.
> - **Boundaries / IO** — what this subdomain exposes and consumes.
> - **Invariants** — rules that always hold.
> - **Flagged ambiguities** — terms in dispute with proposed resolutions.
>
> See `agents-docs/AGENTS_CONTEXT.md` for the contract. Update in the same turn a trigger fires (see `agents-docs/AGENT_WORKFLOW.md` § CONTEXT.md upkeep).
## Vocabulary
| Term | Definition | Aliases to avoid |
|------|------------|------------------|
| **Envelope** | The on-the-wire shape of a WebSocket message — `type`, `payload`, and routing metadata, typed in `src/websocket/types.ts` and mirrored in `toju-app/src/app/shared-kernel/signaling-contracts.ts`. | "packet", "frame" |
| **Handler** | A WebSocket message handler registered in `src/websocket/handler.ts`; one per envelope type. | "listener" |
| **CQRS command/query** | A typed request dispatched through `src/cqrs/` — commands mutate state, queries read it; both return a typed result. | "action" (NgRx term) |
| **Server directory** | The catalog of joinable chat servers, exposed by `src/routes/servers.ts` plus invite and join-request routes. | "guild list" |
| **SSRF guard** | The outbound-fetch policy enforced by `src/routes/ssrf-guard.ts` — gates link-metadata and proxy routes that fetch user-supplied URLs. | "proxy filter" |
| **Variables file** | `data/variables.json` — runtime config (klipy key, server host/protocol, release manifest URL, link-preview toggle) normalized on startup. | "config", ".env" (those are separate) |
## Relationships
- A **WebSocket connection** carries many **Envelopes**; each envelope is routed to exactly one **Handler**.
- A **Route** (HTTP) may dispatch zero or more **CQRS commands/queries** to mutate or read persistent state.
- The **Server directory** depends on **Invites** and **Join requests** — listing, accepting, and revoking flows are split across `routes/servers.ts`, `routes/invites.ts`, `routes/join-requests.ts`.
- **Persistence** entities in `src/entities/` are owned by this subdomain and never shipped to the renderer; the wire envelope is the contract instead.
- **SSRF guard** is consumed by `link-metadata`, `proxy`, and `klipy` routes that fetch user-supplied URLs.
## Boundaries / IO
- **Exposes:**
- HTTP routes under `src/routes/`: `health`, `users`, `servers`, `invites`, `join-requests`, `games`, `klipy`, `link-metadata`, `proxy`, `plugin-support`, `openapi-docs`.
- WebSocket envelopes typed in `src/websocket/types.ts` — the realtime contract shared with `toju-app/src/app/shared-kernel/signaling-contracts.ts`.
- OpenAPI document served by `openapi-docs` route.
- **Consumes:**
- The shared TypeORM SQLite database via `src/db/` (entities in `src/entities/`, migrations in `src/migrations/`).
- `data/variables.json` for runtime configuration; `.env` for `PORT` / SSL toggles.
- Optional outbound HTTP for link previews and klipy (all gated by **SSRF guard**).
## Invariants
- Every database schema change ships as a TypeORM **migration**; the live database is never mutated outside the migration system.
- WebSocket **Envelope** types are defined once in `src/websocket/types.ts` and **must** stay structurally compatible with `toju-app/src/app/shared-kernel/signaling-contracts.ts` — drift between the two is a wire-protocol break.
- User-supplied URLs are **never** fetched without going through `ssrf-guard.ts`.
- Secrets (klipy API key, OAuth tokens, signing keys) live in `data/variables.json` or environment variables — never in code, never in logs.
## Flagged ambiguities
- _None recorded yet — add entries when an envelope type or route name resists clean definition._
---
*Agent-procedural rules (TDD, lint, build) live in `/AGENTS.md`. WebSocket envelope schemas and HTTP request/response shapes belong in `agents-docs/features/` when they cross subdomain boundaries. This file is the bounded-context domain artefact for the signaling server.*

51
toju-app/CONTEXT.md Normal file
View File

@@ -0,0 +1,51 @@
# Product Client (toju-app)
Owns the user-facing Angular 21 desktop chat experience: rendering and orchestrating chat, voice, screen-share, plugin UI, theming, and identity flows on top of the Electron `window.api` bridge and the server WebSocket. Houses every bounded context the end user interacts with, organized DDD-style under `src/app/domains/`.
> **Format reference:**
> - **Vocabulary** — bold term, one-sentence definition, aliases to avoid.
> - **Relationships** — bullets with bold terms and cardinality.
> - **Boundaries / IO** — what this subdomain exposes and consumes.
> - **Invariants** — rules that always hold.
> - **Flagged ambiguities** — terms in dispute with proposed resolutions.
>
> See `agents-docs/AGENTS_CONTEXT.md` for the contract. Update in the same turn a trigger fires (see `agents-docs/AGENT_WORKFLOW.md` § CONTEXT.md upkeep).
## Vocabulary
| Term | Definition | Aliases to avoid |
|------|------------|------------------|
| **Domain** | A bounded context under `src/app/domains/<name>/` that owns its own models, services, NgRx slice, and components — e.g. *chat*, *voice-session*, *plugins*. | "module", "feature" (Angular reserves these for different things) |
| **Shared kernel** | Cross-domain contracts in `src/app/shared-kernel/` — wire-format models, P2P transfer utilities, plugin contracts, signaling contracts — imported by multiple domains. | "common", "core" |
| **Infrastructure** | Technical-runtime concerns shared by domains: `persistence/` (client-side store wiring) and `realtime/` (WebSocket adapter). Not a domain. | "shared", "lib" |
| **Rules file** | A pure-function module suffixed `*.rules.ts` that encodes domain logic without Angular or NgRx dependencies — easy to unit-test. | "helpers", "utils" |
## Relationships
- A **Domain** owns zero or more **Components**, **Services**, **NgRx slices**, and **Rules files**.
- A **Domain** may consume **Shared kernel** contracts but must never import from another **Domain** directly — cross-domain coupling goes through the shared kernel or NgRx events.
- The **Realtime** infrastructure adapts server WebSocket envelopes (defined in `src/app/shared-kernel/signaling-contracts.ts` and mirrored in `server/src/websocket/types.ts`) into NgRx actions consumed by domains.
- The **Plugins** domain consumes plugin manifests loaded by Electron's `plugin-library.ts` and exposes a sandboxed runtime that other domains may hook into.
## Boundaries / IO
- **Exposes:** the Angular SPA bundle served at `:4200` in dev (`ng serve`) or mounted by Electron in production; NgRx store events that other domains in this subdomain consume; UI surface to the end user.
- **Consumes:**
- `window.api.*` IPC surface exposed by Electron preload (defined in `electron/preload.ts` and `electron/api/`).
- WebSocket envelopes from `server/src/websocket/` (typed by `shared-kernel/signaling-contracts.ts`).
- REST endpoints from the server's `server/src/routes/` (server directory, invites, join requests, link metadata, klipy).
- Plugin manifests resolved by Electron's plugin library.
## Invariants
- A **Domain** never imports from another **Domain** directly — only through the **Shared kernel** or NgRx actions.
- **Rules files** stay framework-free (no Angular, no NgRx) so they can be Vitest-tested as plain functions.
- Wire-format types (anything that crosses the WebSocket or IPC boundary) live in **Shared kernel**, never inside a single domain.
## Flagged ambiguities
- _None recorded yet — add entries when a domain term resists clean definition._
---
*Agent-procedural rules (TDD, lint, etc.) live in `/AGENTS.md`. Per-domain implementation detail lives in `src/app/domains/<name>/README.md`. This file is the bounded-context domain artefact for the product client as a whole.*

42
website/CONTEXT.md Normal file
View File

@@ -0,0 +1,42 @@
# Marketing Site (website)
Owns the public-facing Angular 19 marketing site — landing pages, screenshots, feature highlights, and download links pointing to release artifacts. Independent from the product runtime: shares no code or wire schemas with toju-app, electron, or the signaling server.
> **Format reference:**
> - **Vocabulary** — bold term, one-sentence definition, aliases to avoid.
> - **Relationships** — bullets with bold terms and cardinality.
> - **Boundaries / IO** — what this subdomain exposes and consumes.
> - **Invariants** — rules that always hold.
> - **Flagged ambiguities** — terms in dispute with proposed resolutions.
>
> See `agents-docs/AGENTS_CONTEXT.md` for the contract. Update in the same turn a trigger fires (see `agents-docs/AGENT_WORKFLOW.md` § CONTEXT.md upkeep).
## Vocabulary
| Term | Definition | Aliases to avoid |
|------|------------|------------------|
| **Marketing site** | The Angular 19 app under `website/`, served separately from the product client. | "landing page" (it has multiple pages) |
| **Release manifest** | The release-metadata JSON the marketing site links to for download buttons; produced by `tools/generate-release-manifest.js` and published by Gitea Workflows. | "version manifest" |
## Relationships
- The **Marketing site** links to release artifacts produced by the Gitea Workflows under `.gitea/workflows/release-draft.yml` and `publish-draft-release.yml`.
- It does **not** consume the signaling server, the product client, or shared kernel types — independent codebase.
## Boundaries / IO
- **Exposes:** the public website bundle, deployed by `.gitea/workflows/deploy-web-apps.yml`.
- **Consumes:** the release manifest URL and download links; static assets under `website/src/images/`.
## Invariants
- The marketing site has its own `package.json` and its own Angular version — do **not** hoist its dependencies into the root workspace.
- It must remain functional with no backend (static deploy); any dynamic behavior should fail gracefully.
## Flagged ambiguities
- _None recorded yet._
---
*Agent-procedural rules (TDD, lint) live in `/AGENTS.md`. This file is the bounded-context domain artefact for the marketing site.*