test-simple-calculator-docs/architecture/tad.md

5.7 KiB
Raw Blame History

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

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.

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)

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:

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.