Skip to content

Latest commit

 

History

History
199 lines (116 loc) · 11 KB

ARCHITECTURE.md

File metadata and controls

199 lines (116 loc) · 11 KB

SpecThread Architecture

Architectural approach

Use a modular monolith with clear boundaries. The Next.js web application and ASP.NET Core API are separate deployable applications in one repository. PostgreSQL stores authoritative product data. External systems are accessed through adapters.

This is intentionally not a microservice architecture. The capstone does not yet have scale or team requirements that justify distributed services.

Technology stack

Area

Choice

Responsibility

Web

Next.js App Router, React, TypeScript

User interface and browser-facing interactions

API

ASP.NET Core 10 Web API, C#, EF Core 10 with Npgsql

Domain rules, authorization, persistence coordination, integrations

Database

PostgreSQL hosted on Supabase

Requirements, links, evidence metadata, decisions, audit data

Repository integration

GitHub REST/GraphQL APIs and webhooks

Repository, issue, pull request, commit, and check data

Runtime verification

Playwright

A limited set of explicitly configured end-to-end checks

Local environment

Docker Compose only when a task requires local dependencies

No local database is required for the initial health and smoke checks

Observability

OpenTelemetry (OTLP/HTTP) to Grafana Cloud; grafana/otel-lgtm locally

Traces, metrics, and logs, off unless an endpoint is configured (ADR-055, OBSERVABILITY.md)

Continuous integration

GitHub Actions

Build, lint, test, and migration validation

API contract

OpenAPI

Documented boundary between the web application and API

Exact library choices should be made only when the first task requires them and recorded in DECISIONS.md.

Project testing

Playwright Test is the shared runner for automated behavior tests (ADR-005). The root playwright.config.ts discovers browser tests under tests/e2e/ and API tests under tests/api/. It runs the web application from app/web and the separate API from app/api. Linting, type checking, and compilation remain separate checks. See TESTING.md.

This repository testing policy is separate from the product's limited, project-defined runtime verification scenarios. It does not expand SpecThread into an arbitrary test-execution service.

Agreed repository layout (ADR-006)

/ ├── app/ │ ├── web/ # Next.js application │ └── api/ # ASP.NET Core Web API ├── tests/ │ ├── e2e/ # Playwright browser tests │ └── api/ # Playwright API and EF setup tests ├── docs/ │ ├── PROJECT.md │ ├── ARCHITECTURE.md │ ├── WORKFLOW.md │ ├── HANDOFF.md │ └── DECISIONS.md ├── .github/workflows/ ├── AGENTS.md └── README.md

The user approved moving the existing web application to app/web and keeping the .NET API separate in app/api. The root is a small npm workspace with one lockfile and shared test/lint tooling; no monorepo build framework is needed.

Logical modules

The API should preserve these conceptual boundaries even if the initial implementation uses only a few projects or folders:

Requirements: requirement text, acceptance criteria, lifecycle, and ownership.

Evidence: normalized links to issues, pull requests, commits, checks, tests, and releases.

Documents: project reference files (PDF, DOC, DOCX) that team members upload and download (ADR-047).

Integrations: GitHub authentication, API calls, webhook validation, synchronization, and rate-limit handling.

Verification: configured check definitions and recorded results.

Review: human acceptance or rejection decisions and notes.

Audit: important state changes and actors.

The web application should organize by product feature rather than by generic component type where practical. Shared UI primitives should remain small and presentation-focused.

Data model outline

The initial domain will likely include:

User

Project

RepositoryConnection

Requirement

AcceptanceCriterion

EvidenceLink

VerificationRun

ReviewDecision

AuditEvent

This is a conceptual model, not a finalized database schema. Do not generate all tables before the related use cases are designed.

Trust boundaries

Browser input must be validated by the API.

GitHub webhooks must have verified signatures and idempotent processing.

OAuth and installation tokens must be encrypted or held by the deployment platform's secret system; never expose them to the browser.

AI output, if introduced, is untrusted advisory content and must never directly approve requirements or execute privileged actions.

Playwright execution must use controlled targets and scenarios. Do not build arbitrary remote code or unrestricted URL execution into the MVP.

Integration behavior

Prefer explicit references first, such as a requirement identifier in a GitHub issue or pull-request description. Automated matching may later suggest candidates, but it must not silently create authoritative links.

Persist normalized evidence metadata needed by the UI, along with stable external identifiers and URLs. Avoid copying entire external payloads into the product database without a demonstrated need.

API direction

The ASP.NET API owns domain rules and database access. Next.js should call the documented API rather than duplicate domain logic in route handlers or server actions. Generate or maintain a typed client from OpenAPI only after the contract stabilizes enough to justify it.

Better Auth runs in Next.js with authentication-only database access. Users sign in with verified email and password, Google, or GitHub, and manage provider links at /settings/account (ADR-016, ADR-021). Verification and reset emails use Resend. The JWT plugin signs ES256 tokens that the API validates against the web app's JWKS (ADR-015). Team membership grants project/requirement access and team roles grant project management (ADR-040); team invitations are implemented; a project connects one GitHub repository through the GitHub App (ADR-032). The dashboard shows labeled sample requirements (ADR-020) and, like every page except the landing, sign-in, policy, and token-invitation preview pages, requires a valid session (ADR-023). Auth requires an explicit secret, database URL, canonical origin, and email delivery configuration; remote database connections verify TLS. Optional dashboard integration requires an environment key. Auth validates CA PEM and complete GitHub credential pairs before initialization. Newly written OAuth tokens use Better Auth encryption; historical plaintext is not automatically rewritten. See DEPLOYMENT.md.

A deny-by-default Next.js proxy validates the Better Auth session for every non-public page and redirects signed-out visitors to login with the requested page in next (ADR-023). Login and signup redirect an existing session to that validated page, defaulting to the dashboard. The route scaffold links placeholder pages with example IDs until product data and API membership authorization are implemented.

The API exposes anonymous GET /health returning { "status": "ok" } and authenticated GET /me returning { "userId": "" }. Projects, requirements, and acceptance criteria are created, read, edited, archived, and restored through /projects and /requirements with inherited team-membership authorization (ADR-040, docs/API.md). Project membership writes are retired; joining a team requires invitation acceptance. Members upload, list, download, and archive project documents of up to 4 MiB through /projects/{id}/documents and /documents (ADR-047), and a requirement links up to 20 of them, saved with the requirement (ADR-049). Each saved change to a requirement's acceptance criteria is kept as a version, and changing accepted criteria needs confirmation (ADR-051); requirements can be marked as follow-ups of others with a recorded history (ADR-052) and carry one milestone label (ADR-053), and each shows whether it is Evidence complete under the team's fixed rule and which parts are missing (ADR-057). Evidence links are found by number, address, or title, and every link added or removed is recorded (ADR-054). Pull requests that close a linked issue are suggested for a person to confirm or reject, and a link can move between requirements (ADR-057). Next.js server code calls them through apiFetch with the user's JWT. The invitation token preview is also anonymous; all mutations and other product endpoints require a valid Better Auth JWT by default (ADR-015). /health is a liveness check, not database readiness. Development exposes /openapi/v1.json; production does not. EF Core maps six auth tables (user, session, account, verification, jwks, rateLimit) and nineteen product tables in public, and owns every migration in app/api/Migrations (see DATABASE.md) and future migrations. Startup does not create, migrate, or query the database. Database use fails explicitly if ConnectionStrings:Database is missing. RLS and revoked browser-role grants deny Data API access by default; this does not replace server-side project authorization. Supabase-managed schemas must not be modified. See DATABASE.md.

Teams (ADR-039/040) adds member-only reads, atomic creation, a real Members table, and personal favorite/expansion preferences. Your teams has expandable groups with Home and Projects links. Team Home uses Overview/Members tabs with a team menu. After first verified sign-in, the proxy requires persistent first-team onboarding; C# saves completion atomically with the initial team and refuses project creation while incomplete. Once the API reports completion, the proxy remembers it in a signed, user-bound HttpOnly cookie and stops asking on later navigations (ADR-042). Completion is stored separately from Better Auth tables and survives loss of membership. Server API calls use Better Auth JWTs; browser sidebar reads/preferences stay on same-origin session-checked routes. Startup still performs no database work. Team-owned project authorization and the compact team Projects/archive tables are implemented using the accepted rules in ADR-040. Member actions, settings, and ownership transfer use the agreed role rules and serialize mutations on the team row. Invitations share that lock, store only hashed secrets, and require acceptance by a verified matching email while the inviter remains authorized. Membership, acceptance, and onboarding completion are atomic. The focused public preview/acceptance page preserves sign-in/signup return paths and grants no access before acceptance. Email uses the existing server-only sender; browser management uses authenticated server actions. Team archive rows offer Owner/Admin restoration with named confirmation and live API permission checks.

Deployment direction (ADR-010)

Web: Vercel (Next.js App Router in app/web).

API: Render (ASP.NET Core 10 Web API via Docker container).

Database: PostgreSQL on Supabase.

See docs/DEPLOYMENT.md for step-by-step platform configuration, environment variables, health checks, and secrets management. Health and smoke checks run without a database account. Live persistence work requires separately configured Supabase database credentials; MCP authentication does not provide an application connection string.