Skip to content

Contributing (Technical)

Thanks for helping build WorkWingman. This page covers the dev loop, the mandatory review gate, coding conventions, and the CI gates a change has to clear.

Dev setup

Follow getting-started.md first: install the prerequisites (.NET 10 SDK, Node 22.12+, Git), clone, run the three processes, and confirm both test suites pass:

dotnet test          # 381 backend tests (xUnit)
cd frontend && npm test   # frontend tests (Vitest)

Branch / PR flow

  1. Branch off the default branch. Never commit directly to master/main.
  2. Code the change. Keep the diff scoped; match the surrounding style (below).
  3. /codex-review — run the mandatory second-opinion gate before you commit (below).
  4. Commit once review is addressed.
  5. Open a PR.
  6. CI must be green before merge (below).

The mandatory /codex-review gate

Before committing, run /codex-review on your uncommitted changes. This is a mandatory second-opinion gate, not a suggestion — it's a fresh reviewer looking for bugs, security issues (OWASP Top 10), performance problems, and quality issues before your change enters history.

  • Run it on the uncommitted diff, read every finding, and either fix it or have a defensible reason not to.
  • Only commit once the review is addressed.
  • Treat "the gate passed" as a precondition for committing, the same way you'd treat "tests pass."

Coding conventions

Match the existing code. These are the patterns already in the tree — follow them rather than introducing new ones.

C# (Core, Infrastructure, Api)

  • File-scoped namespaces (namespace WorkWingman.Core.Models;).
  • Primary constructors for dependency injection (e.g. public class JobsController(IJobQueueService queue) : ControllerBase).
  • record types for DTOs — request bodies are records (e.g. public record ResolveRequest(string CallId, string Choice);).
  • Core has no infrastructure dependencies. Keep the dependency direction pointing inward toward Core. Put implementations in Infrastructure, interfaces in Core.
  • Enums serialize as strings; JSON properties are camelCase. Preserve this — the frontend depends on it.
  • Comments explain WHY / constraints, not WHAT. The existing model and controller XML-doc comments are the standard: they capture intent and invariants (e.g. "Secrets themselves never leave the vault service"), not restatements of the code.

Angular (frontend)

  • Standalone components (no NgModules) — Angular 22, under src/app/features/<screen>.
  • Signals for reactive state.
  • Shared services live in src/app/core/.
  • See angular.dev for standalone + signals references.

The two-track docs rule

Docs live in two synchronized tracks:

  • docs/technical/ — full detail for engineers.
  • docs/plain/ — everyday language with analogies, for everyone.

When you change code that these docs describe, update both tracks in the same PR. A change to an endpoint, a screen, or the setup flow should land with its doc updates so the two tracks never drift out of sync with the code or each other.

Honesty rule: document only what actually exists. Anything not yet built goes under a ## Roadmap heading and is clearly labeled as not-yet-working — never described as if it's finished.

Keep out of git

Never commit:

  • bin/ and obj/ — .NET build output.
  • *.kdbx — the KeePass vault file. It holds real secrets and must never enter history.

(Also avoid committing local data such as generated documents or the tracker database.)

CI gates

CI (.github/workflows/ci.yml) runs on pushes and PRs to master/main and must be green to merge. Jobs include:

Job Runner Steps
Backend (.NET) windows-latest Set up .NET 10 → dotnet build --configuration Releasedotnet test (with test.runsettings).
Frontend (Angular) ubuntu-latest Set up Node → npm cinpm run buildnpm test.
Docs (two-track + linked + fresh) ubuntu-latest Pairing check (every technical/X.mdplain/X.md, no exceptions — documentation of how WorkWingman works always gets both tracks; docs/reference/ is for point-in-time records, e.g. tenant validation runs and merge audits, and is not a way out of writing the plain track) → orphan check (every doc linked from the README table or another doc) → freshness gate: a change touching src/ or frontend/src/ without touching docs/ fails, unless the head commit says [skip docs] → advisory warning when a 500+-insertion change lands without a making-of story beat.
Diagrams (D2 up to date) ubuntu-latest Rebuilds all D2 diagrams with the pinned Linux binary; on push it self-heals drift by committing the canonical render (D2 output is platform-dependent, so only CI's render is canonical), on PRs drift is a hard failure.

The docs job makes the two-track rule and docs freshness a gate, not a convention: code that changes behavior ships with its docs (and, for architecture moves, its diagram + a making-of beat) in the same change. [skip docs] exists for pure refactors and mechanical bumps — using it for a real behavior change defeats the point and will be caught in review.

Run dotnet test and npm test locally before pushing so you don't burn a CI cycle on a failure you could catch in seconds.