Components
EstimateKit is a hexagonal FastAPI + CLI engine (domain / application / adapters) with a React SPA, packaged as one container. This is the part-by-part map; what it produces and why is in the overview.
| Part | Lives in | Role |
|---|---|---|
| Domain | engine/domain |
Entities and value objects (Project, ProjectSlug, AuditReport), domain services (scheduling), constants, exceptions. No outward imports. |
| Application | engine/application |
Inbound/outbound ports and the use cases that orchestrate them: discover, scaffold a project or mint a phase in one, project lifecycle (rename, archive, unarchive, delete, summary), generate roadmap/excels/slides/all (the deck for one named phase), audit, file I/O, architecture diagrams (list, render), outputs, import/export. |
| HTTP adapter | engine/adapters/inbound/http |
FastAPI app factory and routers (system, guide, projects, generation, files, audit, slides, architecture), DTOs and mappers, under /api. Serves the built SPA at /. |
| MCP adapter | engine/adapters/inbound/mcp |
The same use cases as tools at /mcp, plus the estimate-project prompt; see The MCP door. |
| CLI adapter | engine/adapters/inbound/cli |
An argparse command registry over the same use cases. |
| Persistence | engine/adapters/outbound/persistence |
File-backed project and template repositories — projects live on the /data volume. |
| Generators | engine/adapters/outbound/{roadmap,excel,slidev,plantuml} |
Render domain entities into a TSV roadmap, .xlsx workbooks (openpyxl), a Slidev deck, and the per-phase PlantUML architecture diagrams. |
| Auditor adapter | engine/adapters/outbound/auditor |
Runs the standalone auditor/ pytest suite over a project and collects structured results. |
| Events adapter | engine/adapters/outbound/events |
Publishes the engine’s facts to the platform event bus where the instance holds a grant; see Events. |
| Composition root | engine/container.py |
Wires the adapters into the use cases (the single place all layers meet). |
| Web | web/ |
React + Vite + Tailwind SPA (MVVM); served as static files by the backend in the built image. |
How a project becomes artifacts
Section titled “How a project becomes artifacts”flowchart LR
data["project folder<br/>(YAML + TSV)"] --> audit{"auditor:<br/>data valid?"}
audit -- "errors" --> fix["left for the author to fix"]
audit -- "clean" --> engine["engine use cases"]
engine --> roadmap["roadmap (TSV)"]
engine --> excel["Excel workbooks"]
engine --> slides["Slidev deck"]
The auditor runs first and reports hard errors; on top of those it raises risk suggestions (e.g. zero test lag, milestones bunched into one month) drawn from delivery experience. Generation reads validated domain entities, never raw files.
The MCP door
Section titled “The MCP door”The MCP server mounts at /mcp on the same FastAPI app (streamable HTTP), one tool
per use case, so an agent runs the whole estimation loop the SPA and CLI run:
| Tool | Does |
|---|---|
list_projects / get_project_summary |
The project list, one project’s headline facts. |
scaffold_project |
A complete example project whose sentinel-marked values the audit refuses until authored. |
scaffold_phase |
A new phase in an existing project: its phase-table row, its matrix column and its whole sentinel-marked file set (activities, architecture, executive summary, notes), so a minted phase audits red until authored. |
delete_project / rename_project / archive_project / unarchive_project |
The project lifecycle. |
list_project_files / read_project_file / write_project_file / delete_project_file |
The data files (YAML + TSV) an authoring agent edits. |
append_project_rows / replace_project_row |
Row-level writes to a TSV data file: append rows, or replace the one row whose ID column holds a given ID, each row checked against the header row, so a follow-on never re-sends the rows it must not touch. |
append_project_text |
Append text after the last line of a non-TSV data file, such as a new phase’s ask onto the customer-requirements text, leaving every earlier byte as it was; a TSV is refused, since its rows go through append_project_rows. |
list_architecture_diagrams / render_architecture_diagram |
The per-phase PlantUML architecture diagrams. |
run_audit |
Audit the whole project, or a selected phase plus shared integrity; the report names its scope and carries advisory project-wide risk suggestions. |
generate_artifacts / list_output_files |
Trigger the roadmap, workbooks, and the deck for one named phase (a multi-phase project refuses slides without it); enumerate what generation produced. |
get_guide |
The authoring guide the estimation loop follows. |
The estimate-project prompt publishes the whole loop (scaffold, author from the
brief, audit until clean, generate) as a runbook the connected agent executes.
Generated artifacts stay on the instance: workbooks download over the HTTP API
(/api/projects/<slug>/outputs/<path>) and the deck reviews at
/projects/<slug>/slides/. The deck sells one phase: its executive summary,
speaker notes, architecture slide and per-phase sections are that phase’s own
(slides/P<n>-executive-summary.tsv, slides/P<n>-notes.tsv,
architecture/P<n>-components.tsv, the guidelines whose Phase IDs name it),
with the cross-phase slides as context; regenerating for another phase
replaces it at the same URL.
Access control
Section titled “Access control”The pre and prod deployments run ESTIMATEKIT_AUTH_MODE=entra: people sign in
through Microsoft Entra ID with authorization-code + PKCE, and the app holds a
signed session cookie. The id_token’s RS256 signature, issuer, audience, nonce,
tenant and expiry are verified before the session opens. Fail-closed HTTP
Basic narrows to the /mcp machine door, which cannot complete an interactive
login. Dev runs ESTIMATEKIT_AUTH_MODE=basic temporarily, because its Entra
app registration does not exist yet, so the same Basic pair gates every surface
there until the registration lands.
An entra deployment stood up without the Entra block answers 503, never open,
so a misconfigured deploy refuses to serve rather than leak estimation data. The
gate lives in engine/adapters/inbound/http/auth.py. /ping and /api/health
stay exempt for probes; the readiness check also writes and removes one file
under the projects root, so a green probe proves the volume is writable. The
session secret, Entra client secret and MCP Basic pair come from Vault through an
ExternalSecret; ESTIMATEKIT_AUTH_DISABLED=true is the explicit local-dev
opt-out. Either way the hostname is safe to publish.
Deployment
Section titled “Deployment”Packaged by the root Dockerfile and deployed by the CEP pipeline
(cicd/cicd.yaml) from the k8s/helm chart and the terraform/ root. The app
serves at estimatekit-<env>.<zone>; the CEP service identity is
asdlc-estimatekit. This docs site ships as its own deployable
(docs/cicd/cicd.yaml, chart estimatekit-docs) at
estimatekit-docs-<env>.<zone>.