docs(architecture): sync working spec + TAD from AI-SDLC (Gate 2)
This commit is contained in:
parent
0e34e9e055
commit
bad5400c1d
116
architecture/tad.md
Normal file
116
architecture/tad.md
Normal file
@ -0,0 +1,116 @@
|
||||
# Tech Architecture Document
|
||||
|
||||
## Stack
|
||||
|
||||
| Layer | Choice | Rationale |
|
||||
|---|---|---|
|
||||
| Language | TypeScript | Type safety for arithmetic logic; catches operand/type bugs at compile time. |
|
||||
| UI Framework | React 18 (Vite) | Lightweight component model; Vite gives fast dev HMR and a zero-config static build output. |
|
||||
| Styling | CSS Modules | Scoped styles, no runtime overhead, easy responsive layout. |
|
||||
| Testing | Vitest + React Testing Library | Co-located with Vite; unit tests for arithmetic logic, component interaction tests for UI. |
|
||||
| Build / Deploy | Vite `build` → static files | Produces a plain `dist/` folder deployable to any static host (Netlify, GitHub Pages, S3, etc.). |
|
||||
| CI | GitHub Actions | Lint, type-check, test, and build on every push; deploy `dist/` on merge to `main`. |
|
||||
|
||||
---
|
||||
|
||||
## Components
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
App["App (root)"]
|
||||
Display["Display\n• shows current operand A, operator, operand B\n• shows result or error"]
|
||||
OperandInput["OperandInput × 2\n• controlled numeric text field\n• accepts decimal & negative values"]
|
||||
OperatorSelector["OperatorSelector\n• four buttons: + − × ÷\n• highlights active operator"]
|
||||
ActionBar["ActionBar\n• = (Calculate) button\n• C (Clear) button"]
|
||||
Calculator["calculator.ts\n(pure logic module)"]
|
||||
|
||||
App --> Display
|
||||
App --> OperandInput
|
||||
App --> OperatorSelector
|
||||
App --> ActionBar
|
||||
App -- "calls" --> Calculator
|
||||
```
|
||||
|
||||
### Component responsibilities
|
||||
|
||||
| Component | Responsibility |
|
||||
|---|---|
|
||||
| `App` | Owns all state (operandA, operandB, operator, result, error). Wires child events to state updates and calls the calculator module. |
|
||||
| `Display` | Pure presentational; renders the current expression and result/error string. |
|
||||
| `OperandInput` | Controlled `<input type="text">` that accepts numeric strings including decimals; reports `onChange` to `App`. |
|
||||
| `OperatorSelector` | Renders four operator buttons; reports `onSelect` to `App`. |
|
||||
| `ActionBar` | Renders **=** and **C** buttons; fires `onCalculate` / `onClear` callbacks. |
|
||||
| `calculator.ts` | Pure-function module: `calculate(a: number, op: Operator, b: number): number \| CalcError`. No DOM dependency; fully unit-testable. |
|
||||
|
||||
---
|
||||
|
||||
## Data Model
|
||||
|
||||
All state is ephemeral (in-memory React state). There is no database, localStorage, or network persistence.
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
APP_STATE {
|
||||
string operandA "raw input string for operand A"
|
||||
string operandB "raw input string for operand B"
|
||||
Operator operator "'+' | '-' | '*' | '/'"
|
||||
number result "computed result (null until calculated)"
|
||||
string errorMessage "non-null when a calc error occurs"
|
||||
}
|
||||
```
|
||||
|
||||
### Type definitions (TypeScript)
|
||||
|
||||
```ts
|
||||
type Operator = '+' | '-' | '*' | '/';
|
||||
|
||||
type CalcError =
|
||||
| { kind: 'DIVISION_BY_ZERO' }
|
||||
| { kind: 'INVALID_INPUT'; field: 'a' | 'b' };
|
||||
|
||||
type CalcResult = { ok: true; value: number } | { ok: false; error: CalcError };
|
||||
```
|
||||
|
||||
`calculator.ts` exports a single function:
|
||||
|
||||
```ts
|
||||
export function calculate(a: number, op: Operator, b: number): CalcResult;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integrations
|
||||
|
||||
This version has **no external integrations**. All computation runs entirely in the browser.
|
||||
|
||||
| Integration | Status | Notes |
|
||||
|---|---|---|
|
||||
| Backend API | None | All arithmetic is client-side; NFR-6 (static deployability) rules out a server runtime. |
|
||||
| Authentication service | None | No accounts or sessions (Assumption 2). |
|
||||
| Analytics / telemetry | None | Out of scope for v1; can be added later without architectural change. |
|
||||
| CDN / static host | Optional | Any static host works (`dist/` is self-contained). Recommended: Netlify or GitHub Pages for zero-cost deployment. |
|
||||
|
||||
---
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
| ID | NFR | Architectural approach |
|
||||
|---|---|---|
|
||||
| NFR-1 | Result ≤ 100 ms | All logic runs synchronously in the browser; no network round-trip. Vite-bundled output is ≤ 50 kB gzipped. |
|
||||
| NFR-2 | Responsive (desktop + mobile) | CSS Modules with a fluid grid; `OperandInput` and `OperatorSelector` reflow to single-column below 480 px. |
|
||||
| NFR-3 | WCAG 2.1 AA | Semantic HTML (`<button>`, `<label>`, `<input>`); colour contrast validated in design tokens; all interactive elements reachable via Tab; `aria-live` region for result/error announcements. |
|
||||
| NFR-4 | Chrome / Firefox / Safari / Edge | TypeScript compiled to ES2020 (broadly supported); no experimental browser APIs used. Vitest browser-mode smoke test on CI. |
|
||||
| NFR-5 | Modular + unit-tested | `calculator.ts` is a pure module with 100 % branch coverage required in CI gate. |
|
||||
| NFR-6 | Static deployable | Vite `build` emits plain HTML/CSS/JS to `dist/`; no Node.js runtime needed at serve time. |
|
||||
|
||||
---
|
||||
|
||||
## Risks
|
||||
|
||||
| # | Risk | Likelihood | Impact | Mitigation |
|
||||
|---|---|---|---|---|
|
||||
| R-1 | Floating-point display artefacts (e.g. `0.1 + 0.2 = 0.30000000000000004`) | High | Low | Round display output to a configurable number of significant figures (default 10); document IEEE 754 behaviour in the UI tooltip. |
|
||||
| R-2 | Invalid / non-numeric operand input | Medium | Medium | Parse operands before passing to `calculate()`; show inline validation error via `CalcError.INVALID_INPUT` rather than `NaN` propagation. |
|
||||
| R-3 | Division-by-zero unhandled path | Low | Medium | `calculate()` returns `CalcError.DIVISION_BY_ZERO` as a typed value; `App` maps this to a user-readable message. Unit-tested. |
|
||||
| R-4 | Accessibility regressions on future style changes | Low | Medium | Axe-core accessibility checks run in CI on every PR via `@axe-core/react` dev integration. |
|
||||
| R-5 | Scope creep (expression parser, history, etc.) | Medium | Medium | Documented out-of-scope items in Working Spec Assumptions 2, 3, 6, 7; change requests require a new spec revision. |
|
||||
Loading…
Reference in New Issue
Block a user