# Architecture Notes

The tenant billing demo follows a simple service-oriented layout. Each module owns one business concern, and modules collaborate through explicit function calls rather than hidden framework magic. That design keeps the example readable while still producing enough cross-file structure for the graph to surface relationships that matter during onboarding. The architecture is small enough to understand in one sitting, but broad enough to create the same discovery problems a real engineer faces when opening a new repository.

At the front of the system, `AuthService` performs password login and creates a tenant-scoped session. The service delegates password validation to `password-policy.ts` instead of keeping that logic inline. That is a common production pattern: teams separate business rules from orchestration so they can change policy without rewriting session code. The session itself is written through `SessionStore`, which makes the auth flow easy to follow in a graph because one question about login naturally pulls in the policy, the store, and the tenant context object shared by downstream modules.

Tenant scope is represented by `TenantContext`. The type is intentionally central because multi-tenant systems usually fail when scope is handled inconsistently. Billing, support, reporting, and auth all need a reliable tenant identifier. In a larger repository, that type tends to become a bridge across communities. The demo preserves that pattern so a graph query for tenant context highlights why the type matters and where it crosses functional boundaries. That is useful in practice because engineers often need to answer scope questions before they can make even a small change safely.

Billing starts with `InvoiceService`. The service prepares invoice work and delegates message delivery to `EmailNotifier`. The notifier is intentionally isolated because communication code often changes independently from billing code. During review or incident response, engineers ask "who actually sends the receipt" more often than they ask about the whole billing module. The demo question set mirrors that behavior. A graph retrieval that lands on the invoice service and the email notifier is much more useful than a raw code dump from the entire repository.

The monthly close job represents scheduled operational work. Many business systems have one or two cron-driven paths that touch multiple subsystems. Those jobs are easy to miss in naive file browsing because they are neither a top-level entrypoint nor a user-facing request handler. Here, `runMonthlyCloseJob()` coordinates billing close work and asks `RevenueReport` to build the finance-facing summary. That makes the job a natural cross-module connector, which helps the graph show how execution jumps from jobs to reports to billing.

Reporting is separate on purpose. Finance code tends to evolve independently from core transaction flows, and engineers regularly need to understand whether a report is read-only, derived, cached, or capable of mutating state. The demo keeps reporting read-only and deterministic. `buildMonthlyRevenueReport()` assembles the monthly summary from already available billing data. That makes the reporting path easy to explain in the benchmark and easy to verify in eval because the expected labels are concrete and stable.

Support and audit modules exist to round out the corpus. They do not dominate the benchmark questions, but they make the workspace feel like a real internal product instead of a toy app with only happy-path code. Support flows create a natural place to talk about escalation and customer history. Audit flows hint at compliance and traceability. Those modules matter because real agents do not explore repositories that contain only the exact code needed for a single demo question. They explore repositories with side concerns, operational notes, and extra edges that can distract a naive retrieval strategy.

The graph-oriented lesson from this architecture is straightforward. A developer question rarely needs the full codebase. It needs the handful of entities, files, and connecting edges that explain one behavior. This workspace intentionally spreads that behavior across enough modules to make graph retrieval meaningful, while keeping the domain simple enough that users can verify the answers by reading the source themselves.
