From 4d84e5c5c9e8c01812e586a4bcaa6afa738a9c80 Mon Sep 17 00:00:00 2001 From: sheheryarsoomro12 Date: Mon, 3 Aug 2026 13:11:02 +0500 Subject: [PATCH] Design System Architecture and Database Plan --- docs/architecture/00-scope-classification.md | 584 ++ docs/architecture/01-repository-assessment.md | 620 ++ docs/architecture/02-system-architecture.md | 1257 ++++ docs/architecture/03-database-design.md | 6431 +++++++++++++++++ .../04-integrations-and-processing.md | 1461 ++++ .../05-security-rbac-ai-governance.md | 814 +++ docs/architecture/06-api-boundaries.md | 2723 +++++++ docs/architecture/07-implementation-plan.md | 1566 ++++ .../08-requirements-traceability.md | 713 ++ docs/architecture/09-end-to-end-flow.md | 304 + docs/architecture/README.md | 91 + docs/architecture/_decisions.md | 482 ++ docs/architecture/_glossary.md | 144 + docs/architecture/_open-items.md | 333 + docs/architecture/_repo-findings.md | 148 + ...1-modular-monolith-versus-microservices.md | 237 + .../adr/0002-primary-relational-database.md | 266 + .../adr/0003-object-storage-strategy.md | 254 + .../adr/0004-background-job-queue.md | 302 + .../adr/0005-email-integration-method.md | 257 + .../adr/0006-candidate-search-strategy.md | 277 + .../adr/0007-job-and-scoring-versioning.md | 338 + ...candidate-duplicate-resolution-strategy.md | 306 + .../0009-permission-enforcement-strategy.md | 359 + ...0-chatbot-controlled-query-architecture.md | 331 + ...-ai-provider-abstraction-and-versioning.md | 410 ++ .../adr/0012-deployment-topology.md | 297 + .../adr/0013-frontend-strangler-migration.md | 203 + .../adr/0014-phase-0-xss-csp-hardening.md | 234 + .../adr/0015-module-boundary-enforcement.md | 289 + .../adr/0016-real-postgres-in-ci.md | 271 + ...lain-sql-migrations-as-schema-authority.md | 295 + .../0018-backend-language-and-framework.md | 212 + docs/architecture/diagrams/01-master-flow.svg | 1 + .../diagrams/02-intake-resolution.svg | 1 + .../diagrams/03-identity-and-duplicates.svg | 1 + .../diagrams/04-application-lifecycle.svg | 1 + docs/architecture/diagrams/05-phase-cut.svg | 1 + tools/check_evidence_citations.py | 259 + 39 files changed, 23073 insertions(+) create mode 100644 docs/architecture/00-scope-classification.md create mode 100644 docs/architecture/01-repository-assessment.md create mode 100644 docs/architecture/02-system-architecture.md create mode 100644 docs/architecture/03-database-design.md create mode 100644 docs/architecture/04-integrations-and-processing.md create mode 100644 docs/architecture/05-security-rbac-ai-governance.md create mode 100644 docs/architecture/06-api-boundaries.md create mode 100644 docs/architecture/07-implementation-plan.md create mode 100644 docs/architecture/08-requirements-traceability.md create mode 100644 docs/architecture/09-end-to-end-flow.md create mode 100644 docs/architecture/README.md create mode 100644 docs/architecture/_decisions.md create mode 100644 docs/architecture/_glossary.md create mode 100644 docs/architecture/_open-items.md create mode 100644 docs/architecture/_repo-findings.md create mode 100644 docs/architecture/adr/0001-modular-monolith-versus-microservices.md create mode 100644 docs/architecture/adr/0002-primary-relational-database.md create mode 100644 docs/architecture/adr/0003-object-storage-strategy.md create mode 100644 docs/architecture/adr/0004-background-job-queue.md create mode 100644 docs/architecture/adr/0005-email-integration-method.md create mode 100644 docs/architecture/adr/0006-candidate-search-strategy.md create mode 100644 docs/architecture/adr/0007-job-and-scoring-versioning.md create mode 100644 docs/architecture/adr/0008-candidate-duplicate-resolution-strategy.md create mode 100644 docs/architecture/adr/0009-permission-enforcement-strategy.md create mode 100644 docs/architecture/adr/0010-chatbot-controlled-query-architecture.md create mode 100644 docs/architecture/adr/0011-ai-provider-abstraction-and-versioning.md create mode 100644 docs/architecture/adr/0012-deployment-topology.md create mode 100644 docs/architecture/adr/0013-frontend-strangler-migration.md create mode 100644 docs/architecture/adr/0014-phase-0-xss-csp-hardening.md create mode 100644 docs/architecture/adr/0015-module-boundary-enforcement.md create mode 100644 docs/architecture/adr/0016-real-postgres-in-ci.md create mode 100644 docs/architecture/adr/0017-plain-sql-migrations-as-schema-authority.md create mode 100644 docs/architecture/adr/0018-backend-language-and-framework.md create mode 100644 docs/architecture/diagrams/01-master-flow.svg create mode 100644 docs/architecture/diagrams/02-intake-resolution.svg create mode 100644 docs/architecture/diagrams/03-identity-and-duplicates.svg create mode 100644 docs/architecture/diagrams/04-application-lifecycle.svg create mode 100644 docs/architecture/diagrams/05-phase-cut.svg create mode 100755 tools/check_evidence_citations.py diff --git a/docs/architecture/00-scope-classification.md b/docs/architecture/00-scope-classification.md new file mode 100644 index 0000000..52fda7d --- /dev/null +++ b/docs/architecture/00-scope-classification.md @@ -0,0 +1,584 @@ +# 00 — Scope Classification + +## Status / Scope of this document + +This document is the scope baseline for the Utopia Brands internal HR Recruitment & ATS +platform ("TalentFlow"). It does four things and nothing else: + +1. Assigns a stable `REQ-` identifier to every **confirmed** requirement, so every later + document in this package — data model, API design, module design, phasing, traceability + matrix — can cite a requirement instead of restating it. +2. Separates confirmed requirements from **proposed**, **deferred** and **rejected** scope, + so nobody has to guess which of the three a given feature is. +3. Gives a verdict on **every** unconfirmed idea raised in the assignment, with the specific + condition that would change that verdict. +4. Records the **open business decisions** with a recommended assumption for each, so that + design and implementation are never blocked waiting on a business answer. + +**There is no meeting transcript in this repository.** A `find` across the repository and +`~/Documents` to depth 2 returned no transcript and no recruitment source document — only +the BRD `.docx` this project itself produced (findings §B). Nothing in this package was +derived from a recorded conversation, and no document in this package should imply +otherwise. **The assignment prompt is therefore the authoritative requirements source.** + +`docs/TalentFlow-ATS-Business-Requirements-v1.0.docx` (findings §A) is a **corroborating +internal artefact, not an independent source** — it was written by this project, so where it +and the assignment prompt differ, the assignment prompt wins. It is cited here as `BRD §…` +because it carries the only stable `FR-`, `AI-`, `NFR-`, `BO-` and `OQ-` numbering that +exists, and downstream documents need those handles. + +This document is consistent with `_decisions.md`. Five genuine inconsistencies **inside** +`_decisions.md` (Part 1 versus Part 2) are recorded as risks in §10 rather than silently +resolved here. + +--- + +## 1. Requirements source and authority + +| Source | Status | How it is used here | +|---|---|---| +| Assignment prompt §3 (confirmed requirements) | **Authoritative** | Becomes the `REQ-` set in §2 | +| Assignment prompt §4 (unconfirmed ideas) | **Authoritative list of open ideas** | Every item gets a verdict in §6 | +| Assignment prompt §5.1–§5.6 (data-model principles) | **Authoritative, non-negotiable** | Folded into the `REQ-` set as constraints | +| Assignment prompt §29 (open questions) | **Authoritative** | Becomes the `OBD-` table in §8 | +| `_repo-findings.md` | **Verified evidence** (inspection, 2026-07-29) | Cited for every claim about what the repository does or does not contain | +| `_decisions.md` | **Binding** architecture and database decisions | Every verdict and phase in this document is consistent with it | +| `TalentFlow-ATS-Business-Requirements-v1.0.docx` | **Corroborating, self-produced** | Provides `FR-`/`AI-`/`NFR-`/`OQ-` numbering only | +| Meeting transcript | **Does not exist** (findings §B) | Not used, not implied, not referenced | +| Existing repository code | **Prototype only** — no backend, DB, auth, tests, build, Docker, env files (findings §B) | Source of evidence about gaps, and of the retained assets (REQ-NFR-09/10/11) | + +### How to classify a new item + +```mermaid +flowchart TD + A["New scope item"] --> B{"Stated in assignment §3
or §5.1-§5.6?"} + B -- yes --> C["CONFIRMED - assign REQ- id"] + B -- no --> D{"Required to satisfy
a confirmed REQ?"} + D -- yes --> E["PROPOSED - assign PROP- id,
needs owner sign-off, not re-debate"] + D -- no --> F{"Wanted, but not needed
for the phase in hand?"} + F -- yes --> G["DEFERRED - assign DEF- id
with phase and entry condition"] + F -- no --> H{"Would it break a constraint
or add unearned cost?"} + H -- yes --> I["REJECTED - record reason
and the condition that reopens it"] + H -- no --> J["OPEN BUSINESS DECISION -
assign OBD- id and proceed
on the recommended assumption"] +``` + +--- + +## 2. Confirmed requirements + +Rules for this table. One line per requirement. `REQ-` ids are **stable and never reused** — +if a requirement is dropped, its id is retired, not recycled. `Source` cites the assignment +constraint or the BRD handle. `Module` is the owning module from `_decisions.md`. `Phase` +follows the `_decisions.md` phasing (0 = hardening/foundations, 1 = vertical slice, 2–4 as +listed there). A requirement being confirmed says nothing about *when* it lands — see the +Phase column, and §5 for what that means in practice. + +### 2.1 Raw intake and inbound channels + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-INT-01 | Every inbound submission is recorded as an immutable raw-intake row before any candidate or application can exist. | Constraint §5.1 | `intake` | 1 | +| REQ-INT-02 | All eleven inbound channels normalise into one candidate record structure. | BO-4, BRD §8.1 | `integrations_inbound` | 1 / 3 / 4 | +| REQ-INT-03 | Parsing is attempted for every inbound document regardless of channel. | BRD §6.3 | `document_parsing` | 1 | +| REQ-INT-04 | Parse failures are surfaced to the recruiter with the document retained, never silently dropped. | BRD §6.3, FR-7 | `intake` | 1 | +| REQ-INT-05 | Each document reports a per-document state of Parsed, Pending, Parsing or Failed. | FR-7, BRD §9.2 | `intake` | 1 | +| REQ-INT-06 | The inbox is a single triage queue with read/unread state and per-source attribution. | FR-2 | `intake` | 1 | +| REQ-INT-07 | Where the parser cannot determine a field with confidence, the field is left empty rather than guessed. | BRD §6.3 | `document_parsing` | 1 | +| REQ-INT-08 | Redelivery of the same channel message is idempotent and never produces a second intake row. | BRD §11 (cross-channel dedupe) | `intake` | 1 | +| REQ-INT-09 | A submission that can never become a candidate has a terminal representable state carrying no candidate. | Constraint §5.1; findings §F | `intake` | 1 | +| REQ-INT-10 | Manual recruiter CV upload is a channel through the same intake path, not an exception route. | FR-7 | `intake` | 1 | +| REQ-INT-11 | Attachments are held in object storage with checksum and virus-scan state, addressed from the intake row. | BRD §7.4 | `files` | 1 | +| REQ-INT-12 | A parse may be retried, and a parser-version change replayed, without mutating the arrival record. | Constraint §5.1 | `intake` | 1 | + +### 2.2 Candidate identity + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-CAN-01 | Candidate identity is a separate entity from job applications; one candidate may hold many applications over time. | Constraint §5.2; findings §F (`js/data.js:117-127`) | `candidate` | 1 | +| REQ-CAN-02 | The candidate master record supports filter, sort, rank, bulk actions and a full profile view. | FR-4 | `candidate` | 1 | +| REQ-CAN-03 | A candidate cannot be created without a prior raw-intake row, including for manual entry. | Constraint §5.1 | `candidate` | 1 | +| REQ-CAN-04 | A candidate must carry at least one usable contact channel; a malformed email cannot produce a candidate. | Constraint §5.1 | `candidate` | 1 | +| REQ-CAN-05 | One normalised email address resolves to at most one live candidate identity. | Constraint §5.2 | `candidate` | 1 | +| REQ-CAN-06 | The candidate record carries the BRD §9 field groups: identity, experience, education, skills and ownership. | BRD §9 | `candidate` | 1 | +| REQ-CAN-07 | CV revisions are retained as candidate documents, each traceable to the intake it arrived on. | BRD §6.3, §9 | `candidate` | 1 | +| REQ-CAN-08 | Skills resolve against a controlled vocabulary with aliases; unmapped parser labels remain storable and reviewable. | BRD §9.2 | `candidate`, `config` | 1 | +| REQ-CAN-09 | Candidate-facing identifiers are non-enumerable. | Constraint (data protection) | `candidate` | 1 | +| REQ-CAN-10 | Previously sourced candidates not hired for their original role can be retained and re-surfaced. | FR-5 | `talent_pool` | 3 | +| REQ-CAN-11 | Experience is stored at a precision that preserves ordering, not rounded to whole years. | findings §F (`js/data.js:121`) | `candidate` | 1 | + +### 2.3 Duplicate detection and merge + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-DUP-01 | Duplicate detection runs against the existing candidate base for every new candidate. | BRD §6.3 | `duplicate_review` | 1 | +| REQ-DUP-02 | Suspected duplicates are **marked**, never deleted. | BRD §6.3 | `duplicate_review` | 1 | +| REQ-DUP-03 | Duplicates arriving through different channels are detected and marked for recruiter review. | BRD §11 | `duplicate_review` | 1 | +| REQ-DUP-04 | Merge requires manual human review; nothing merges automatically, ever. | Constraint | `duplicate_review` | 2 | +| REQ-DUP-05 | Merge is reversible, with enough recorded detail that reversal is a mechanical replay. | Constraint | `duplicate_review` | 2 | +| REQ-DUP-06 | A "not a duplicate" decision persists and suppresses re-flagging of that pair. | Constraint (reviewability) | `duplicate_review` | 1 | +| REQ-DUP-07 | The reviewer sees per-signal evidence, not only a composite similarity score. | BRD §7.3 (explainability) | `duplicate_review` | 2 | +| REQ-DUP-08 | Merge never deletes rows and never double-counts history in reports. | Constraint §5.5 | `duplicate_review` | 2 | + +### 2.4 Requisitions, requirements and versioning + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-JOB-01 | Requisitions are managed across department, business unit, location, employment type, grade and status. | FR-3, BRD §9.1 | `requisition` | 1 | +| REQ-JOB-02 | Jobs are versioned; a published version is immutable. | Constraint §5.3; findings §F (`js/data.js:85-108`) | `requisition` | 1 | +| REQ-JOB-03 | Requirements are version-scoped and weighted; they can never be edited in place on the job. | Constraint §5.3 | `requisition` | 1 | +| REQ-JOB-04 | Scoring configuration is versioned, and its binding to a job is itself historical. | Constraint §5.3 | `scoring` | 1 | +| REQ-JOB-05 | Job statuses are Open, On Hold, Closed, Draft. | FR-3, BRD §9.2 | `requisition` | 1 | +| REQ-JOB-06 | A posting records the exact requisition version text an applicant read. | Constraint §5.3 (defensibility) | `requisition` | 1 | +| REQ-JOB-07 | Publishing a requisition version requires approval by a Hiring Manager or Department Head. | BRD §4 (Approve level); chain scope is OBD-12 | `requisition` | 1 | +| REQ-JOB-08 | Pipeline stages, statuses and vocabularies are editable reference data, not code constants. | BRD §9.2; findings §F | `config`, `pipeline` | 1 | + +### 2.5 Applications and pipeline + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-APP-01 | An application is the join between a candidate and a requisition version, and is the unit ATS scores attach to. | Constraint §5.2, §5.6 | `application` | 1 | +| REQ-APP-02 | The pipeline is a kanban board across the seven stages with drag-and-drop progression. | FR-6, BRD §9.2 | `pipeline` | 2 | +| REQ-APP-03 | Every stage and status change is recorded with actor, actor kind, reason and timestamp. | Constraint §5.5 | `application` | 1 | +| REQ-APP-04 | Each application retains source attribution back to the intake it originated from. | BO-4, FR-2 | `application` | 1 | +| REQ-APP-05 | At most one live application per candidate per job; reapplication is a distinct, ordered attempt. | Constraint §5.2 | `application` | 1 | +| REQ-APP-06 | A transition to a terminal-negative state requires a human actor. | BRD §7.1 | `application` | 1 | +| REQ-APP-07 | Time-in-stage is directly queryable for funnel and SLA reporting. | FR-9, FR-17 | `application`, `analytics` | 1 | + +### 2.6 Recruiter assignment + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-ASG-01 | Assignment is flexible: several people may be attached to one requisition or application in distinct roles. | Constraint §5.4; findings §F (`js/data.js:96,123`) | `assignment` | 1 | +| REQ-ASG-02 | Assignment is historical — "who owned this in March" is answerable from stored data. | Constraint §5.4 | `assignment` | 1 | +| REQ-ASG-03 | Exactly one current primary recruiter exists per requisition at any instant. | Constraint §5.4 | `assignment` | 1 | +| REQ-ASG-04 | Per-recruiter workload, efficiency, SLA state and hiring trend are reportable. | FR-9 | `assignment`, `analytics` | 2 | + +### 2.7 ATS scoring and explainability + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-SCR-01 | The ATS score is per application, never a property of the candidate. | Constraint §5.6; findings §F (`js/data.js:123`) | `scoring` | 1 | +| REQ-SCR-02 | The score is expressed on a 0–100 scale. | BRD §6.2 | `scoring` | 1 | +| REQ-SCR-03 | Matched skills and missing skills are exposed alongside the score. | BRD §6.2, §11 | `scoring` | 1 | +| REQ-SCR-04 | A recommendation band is derivable from the score and exposed with it. | BRD §6.2 | `scoring` | 1 | +| REQ-SCR-05 | The score is reproducible: the same candidate and role yield the same score absent a model or data change. | BRD §6.2 | `scoring` | 1 | +| REQ-SCR-06 | A score change caused by a model version change is traceable to that version. | BRD §6.2 | `scoring` | 1 | +| REQ-SCR-07 | Every score carries the factors that produced it, at a level a recruiter can restate to a hiring manager. | BRD §7.3 | `scoring` | 1 | +| REQ-SCR-08 | Historical scores are never mutated; a rescore appends a new result and supersedes the old one. | Constraint §5.6 | `scoring` | 1 | +| REQ-SCR-09 | Sorting the candidate list by AI Relevance returns a stable, reproducible order. | BRD §11 | `scoring` | 1 | +| REQ-SCR-10 | Protected characteristics — name, age, gender, nationality, photograph — are not ranking features. | BRD §7.2 | `scoring` | 1 | +| REQ-SCR-11 | Ranking across the full candidate base does not degrade the interface. | NFR-9 | `scoring` | 1 | +| REQ-SCR-12 | A score pins every input that could change it: requisition version, scoring config version, scorer code version, document and parse. | Constraint §5.3, §5.6; BRD §6.2 | `scoring` | 1 | + +### 2.8 AI capabilities + +All fifteen are confirmed requirements. Priority is the BRD's; Phase is `_decisions.md`. +Today all fifteen are interface preview only, with "Model endpoint · Not connected" +(BRD §6) — nothing in the repository performs inference (findings §B). + +| REQ | Capability | Priority | Module | Phase | +|---|---|---|---|---| +| REQ-AIC-01 | Resume Ranking — ordered shortlist per job by fit (AI-1). | P0 | `scoring` | 1 | +| REQ-AIC-02 | Candidate Matching — best-fit open roles across all Utopia brands (AI-2). | P0 | `scoring`, `talent_pool` | 1 | +| REQ-AIC-03 | Resume Summary — structured one-click summary for reviewer hand-off (AI-3). | P0 | `ai_orchestration` | 1 | +| REQ-AIC-04 | Skill Gap Analysis — skills present and missing, per candidate and per pipeline (AI-4). | P1 | `scoring` | 2 | +| REQ-AIC-05 | Natural Language Search over the candidate base (AI-5). | P1 | `assistant`, `candidate` | 2 | +| REQ-AIC-06 | JD Generator from a short requisition brief (AI-6). | P1 | `ai_orchestration`, `requisition` | 2 | +| REQ-AIC-07 | Email Generator — candidate correspondence in Utopia brand voice (AI-7). | P1 | `ai_orchestration`, `notifications` | 3 | +| REQ-AIC-08 | Interview Question Generator — role-specific question banks (AI-8). | P1 | `ai_orchestration`, `interview` | 3 | +| REQ-AIC-09 | Recruitment Analytics — natural-language questions across the funnel (AI-9). | P1 | `assistant`, `analytics` | 3 | +| REQ-AIC-10 | Recruiter Copilot — assistant in every workflow with current-screen context (AI-10). | P1 | `assistant` | 2 (read) / 4 (full) | +| REQ-AIC-11 | Candidate Comparison — side-by-side against role criteria (AI-11). | P2 | `scoring` | 3 | +| REQ-AIC-12 | Candidate Recommendation — proactive suggestions of who to contact (AI-12). | P2 | `talent_pool`, `worklist` | 4 | +| REQ-AIC-13 | Offer Letter Generator from offer parameters (AI-13). | P2 | `ai_orchestration`, `offer` | 3 | +| REQ-AIC-14 | Hiring Forecast — time-to-hire prediction and pipeline health flags (AI-14). | P2 | `analytics` | 4 | +| REQ-AIC-15 | Hiring Insights — weekly generated digest of notable movements (AI-15). | P2 | `analytics`, `notifications` | 4 | + +### 2.9 AI governance, fairness and audit + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-GOV-01 | No candidate may be rejected solely by an automated decision. | BRD §7.1; Constraint | `application` | 1 | +| REQ-GOV-02 | No offer is issued without explicit human confirmation. | BRD §7.1 | `offer` | 3 | +| REQ-GOV-03 | The interface identifies machine-generated content before a recruiter acts on it. | BRD §7.1 | frontend, `ai_orchestration` | 1 | +| REQ-GOV-04 | Disparate-impact evaluation is completed before production release and repeated on every model version change. | BRD §7.2 | `fairness_evaluation` | 3 | +| REQ-GOV-05 | Evaluation results are recorded and readable by the business, not held only in engineering. | BRD §7.2, §11 | `fairness_evaluation` | 3 | +| REQ-GOV-06 | Every AI-influenced decision is logged with model version, input reference, output and timestamp. | BRD §7.3 | `audit`, `ai_orchestration` | 1 | +| REQ-GOV-07 | Audit records are retained for the period required by the jurisdictions in which the requisition was posted. | BRD §7.3; jurisdictions per OBD-04 | `audit` | 1 | +| REQ-GOV-08 | Every AI invocation is individually addressable, versioned and reviewable after the fact. | Constraint | `ai_orchestration` | 1 | +| REQ-GOV-09 | The chatbot never bypasses access controls; every AI data access carries the asking human's identity. | Constraint | `assistant`, `identity` | 2 | +| REQ-GOV-10 | AI Studio reflects true per-capability availability; the "not connected" state clears only when a capability is live. | FR-19, BRD §11 | `ai_orchestration` | 1 | +| REQ-GOV-11 | TalentFlow remains fully operable with the AI service unavailable. | NFR-7, BRD §8.3, §11 | all | 1 | +| REQ-GOV-12 | AI output is a suggestion record that a human accepts; it is never a direct domain write. | Constraint | `ai_orchestration` | 1 | + +### 2.10 Interviews + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-ITV-01 | Seven interview types across three meeting modes, with four lifecycle states. | FR-12, BRD §9.2 | `interview` | 2 | +| REQ-ITV-02 | Structured scorecards; an interviewer sees and scores only their own interviews. | FR-12, BRD §4 | `interview` | 2 | +| REQ-ITV-03 | Interview instants are stored in UTC alongside the organiser's wall-clock intent and IANA zone. | Constraint (findings §F: no tz discipline, `js/data.js:237`) | `interview` | 2 | +| REQ-ITV-04 | A participant cannot be double-booked across overlapping scheduled interviews. | Constraint (correctness) | `interview` | 2 | +| REQ-ITV-05 | A month view of scheduled interviews and hiring events exists. | FR-16 | `interview` (view) | 2 | +| REQ-ITV-06 | A submitted scorecard locks. | FR-12, BRD §7.3 | `interview` | 2 | + +### 2.11 Assessments and offers + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-ASM-01 | Six assessment types can be assigned and scored. | FR-13, BRD §9.2 | `assessment` | 3 | +| REQ-ASM-02 | Assessments report Code Quality, Problem Solving and Time Management. | FR-13 | `assessment` | 3 | +| REQ-OFR-01 | Offers move through Draft, Sent, Negotiating, Accepted, Declined, Expired. | FR-14, BRD §9.2 | `offer` | 3 | +| REQ-OFR-02 | An offer revision is a new immutable offer version with its own approval, not a field edit. | Constraint §5.3, §5.5 | `offer` | 3 | +| REQ-OFR-03 | Issuing an offer requires an explicit human confirmation step that cannot be automated. | BRD §7.1 | `offer` | 3 | + +### 2.12 Search + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-SRC-01 | The candidate base is filterable, sortable and rankable on structured attributes. | FR-4 | `candidate` | 1 | +| REQ-SRC-02 | The candidate base is searchable in plain English. | AI-5 | `assistant`, `candidate` | 2 | +| REQ-SRC-03 | Name and employer search is fuzzy and typo-tolerant. | BRD §6.3 (dedupe signals reuse) | `candidate` | 1 | +| REQ-SRC-04 | Relevance blending is attributable to a versioned configuration, not hardcoded. | Constraint §5.3; findings §F (`js/candidates.js:18`) | `candidate` | 1 | + +### 2.13 Analytics, reporting and dashboard + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-ANL-01 | Eight headline KPIs: Open Jobs, Total Candidates, Interviews Today, Offers Accepted, Time to Hire, Time to Fill, Cost per Hire, Closed Jobs. | FR-1 | `analytics` | 2 | +| REQ-ANL-02 | Hiring-trend and pipeline visualisations on the dashboard. | FR-1 | `analytics` | 2 | +| REQ-ANL-03 | Hiring funnel, time-to-hire versus time-to-fill, department performance, and a saved report library. | FR-17 | `analytics` | 3 | +| REQ-ANL-04 | Analytics set: hiring trend, applications received, source breakdown, offer acceptance, pipeline distribution, applications by department, recruiter performance. | FR-18 | `analytics` | 2 | +| REQ-ANL-05 | Natural-language report and analytics generation. | AI-9, FR-17, FR-18 | `assistant`, `analytics` | 3 | +| REQ-ANL-06 | Leadership has a single view across all Utopia brands and departments. | BO-6 | `analytics` | 2 | +| REQ-ANL-07 | Analytics results are scoped to the viewer's role — a recruiter sees own, leadership sees aggregate. | BRD §4, FR-21 | `analytics`, `identity` | 2 | +| REQ-ANL-08 | Time to hire is measurable against the current 27-day baseline. | BO-2 | `analytics` | 2 | +| REQ-ANL-09 | Source and channel performance is comparable across the eleven inbound channels. | FR-8, FR-18, BO-4 | `analytics` | 3 | + +### 2.14 Tasks, worklist and notifications + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-WRK-01 | Recruiter actions are assignable and trackable, with open-item counts surfaced in navigation. | FR-10 | `worklist` | 2 | +| REQ-WRK-02 | AI next-best-action suggestions appear as tasks, visibly marked as AI-originated. | FR-10, AI-12, BRD §7.1 | `worklist` | 2 | +| REQ-WRK-03 | System and hiring-event notifications exist with unread counts. | FR-20 | `notifications` | 2 | + +### 2.15 Identity, access control and application security + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-SEC-01 | Every request is attributable to an authenticated user; there is no anonymous internal access. | findings §D (no auth of any kind) | `identity` | 0 | +| REQ-SEC-02 | RBAC is enforced server-side over a seeded catalogue of roles, permission-controlled modules and permission verbs. The catalogue is **configuration, not structure** — Phase 1 seeds 7 roles × 25 modules × 10 verbs (`05` §2.1/§2.2/§2.9); adding a role or module is an INSERT plus grants. The prototype's 8 roles / 13 modules / 8 permission types (`js/data.js:425-446`) are demo data derived from a `level` cutoff index (findings §D) and are **not** the requirement; BRD §4 is a 66-seat allocation, not a permission catalogue. | FR-21, BRD §3, §4 | `identity` | 1 | +| REQ-SEC-03 | There is exactly one authorization decision point, used by the UI, the API and the assistant alike. | Constraint (chatbot access control) | `identity` | 1 | +| REQ-SEC-04 | Interviewers can see only the candidates attached to their assigned interviews. | BRD §4 | `identity`, `interview` | 2 | +| REQ-SEC-05 | Match-score visibility per role is a configuration setting, not a hardcoded rule. | OQ-5 → OBD-05 | `identity`, `scoring` | 1 | +| REQ-SEC-06 | No data-derived value is rendered without output escaping, and a CSP without `unsafe-inline` for scripts is in force. | findings §E (34 unescaped `innerHTML` sites, `js/candidates.js:68,121`) | frontend | 0 | +| REQ-SEC-07 | Candidate-facing links are scoped, expiring, revocable tokens — never a bare entity identifier. | Constraint (data protection) | `identity` | 3 | +| REQ-SEC-08 | Security settings — SSO, 2FA, session timeout, password policy — are enforced, not display chrome. | findings §D (`js/settings.js:148-154`), FR-22 | `identity` | 1 | +| REQ-SEC-09 | The permission matrix governs behaviour; it is not a display widget. | findings §D (`js/rbac.js:78,111-112` — no `can()` exists) | `identity` | 1 | + +### 2.16 Data protection and retention + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-DAT-01 | Candidate data is processed only within Utopia-controlled infrastructure or by a processor under a data-processing agreement. | BRD §7.4, §3.3 | platform | 1 | +| REQ-DAT-02 | Candidate data must not be used to train third-party foundation models. | BRD §7.4 | `ai_orchestration` | 1 | +| REQ-DAT-03 | Retention and deletion honour candidate rights requests, including within derived embeddings and indexes. | BRD §7.4 | `files`, `candidate` | 2 | +| REQ-DAT-04 | Every column on a candidate-touching table carries a machine-readable PII classification. | BRD §7.4 (enforceability) | platform | 1 | +| REQ-DAT-05 | No special-category data (diversity, health, accommodation) is stored in Phase 1. | BRD §7.2 scope decision | all | 1 | +| REQ-DAT-06 | Erasure and permanent history coexist: identifying data is removable without tearing holes in history or reporting. | Constraint §5.5 + BRD §7.4 | platform | 2 | + +### 2.17 Current state, history and audit + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-HIS-01 | Current state and full history both exist, as separate stored things. | Constraint §5.5; findings §F (no history tables) | all domain | 1 | +| REQ-HIS-02 | Every history row carries actor, actor kind and reason. | Constraint §5.5 | all domain | 1 | +| REQ-HIS-03 | A single append-only audit log spans all modules and is queryable by actor and by candidate. | BRD §7.3, §11 | `audit` | 1 | +| REQ-HIS-04 | The application has no update or delete path into the audit log. | BRD §7.3 | `audit` | 1 | +| REQ-HIS-05 | Access events — profile viewed, export run, chatbot answer returned — are audited, not only data changes. | BRD §7.3, §7.4 | `audit` | 1 | +| REQ-HIS-06 | Requisition, requirement and scoring-config versions are immutable once published. | Constraint §5.3 | `requisition`, `scoring` | 1 | + +### 2.18 Outbound publishing + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-PUB-01 | Requisition versions publish to eight external platforms with per-platform connection state and cost banding. | FR-8, BRD §8.2 | `integrations_outbound` | 4 | +| REQ-PUB-02 | Publishing is an authorised action with a cost implication, restricted above recruiter level. | BRD §8.2 (cost bands), §4 | `integrations_outbound` | 4 | + +### 2.19 API contract + +| REQ | Requirement | Source | Module | Phase | +|---|---|---|---|---| +| REQ-API-01 | The service is exposed over a documented, versioned HTTP JSON API. | BRD §8.3 | API layer | 1 | +| REQ-API-02 | Adopting a new model version requires no interface change. | BRD §8.3 | API layer | 1 | +| REQ-API-03 | The API degrades gracefully — AI absent rather than request failed. | BRD §8.3, NFR-7 | API layer | 1 | +| REQ-API-04 | Long-running operations (bulk ranking, batch parsing) are asynchronous with retrievable job status. | BRD §8.3 | API layer | 1 | +| REQ-API-05 | Rate limits and expected latency are published so the interface can set user expectations. | BRD §8.3 | API layer | 1 | + +### 2.20 Non-functional and experience requirements (must not regress) + +These are already met by the prototype and verified (findings §G). They are confirmed +requirements precisely because the migration must not lose them. + +| REQ | Requirement | Source | Phase | +|---|---|---|---| +| REQ-NFR-01 | WCAG 2.1 AA contrast across all views in both themes. | NFR-1; verified 23 routes × 2 themes (findings §G) | 0 onward | +| REQ-NFR-02 | Usable from 320px to ultrawide without horizontal overflow. | NFR-2 | 0 onward | +| REQ-NFR-03 | Minimum 44×44px touch targets. | NFR-3 | 0 onward | +| REQ-NFR-04 | Light and dark themes following OS preference until the user chooses. | NFR-4 (`js/app.js:64,193,198`) | 0 onward | +| REQ-NFR-05 | Utopia Brands palette and typeface hierarchy per the brand guideline. | NFR-5 | 0 onward | +| REQ-NFR-06 | Works on iOS, Android, macOS and Windows browsers, with safe-area handling. | NFR-6 | 0 onward | +| REQ-NFR-07 | Interactive AI responses land within a latency threshold that does not interrupt recruiter flow. | NFR-8; ceiling is OBD-03 | 1 | +| REQ-NFR-08 | Recruiters act on AI output from the screens where they already work. | BRD §2.3 | 1 | +| REQ-NFR-09 | The existing 23-route information architecture is preserved as the screen backlog. | findings §G (`js/app.js:7-16`) | 0 onward | +| REQ-NFR-10 | The design system in `css/styles.css` is retained as the design contract, not rebuilt. | findings §G; `_decisions.md` | 0 onward | +| REQ-NFR-11 | The dependency-free canvas chart engine `js/charts.js` is retained rather than replaced by a charting dependency. | findings §G (`js/charts.js:339`) | 1 onward | + +### 2.21 Money and time + +| REQ | Requirement | Source | Phase | +|---|---|---|---| +| REQ-MON-01 | Every monetary value carries an explicit ISO-4217 currency; an amount without a currency is not storable. | findings §F (`js/data.js:126`, `js/offers.js:129` — bare integers, no currency) | 1 | +| REQ-MON-02 | The original amount and currency are immutable; any conversion is stored alongside the rate it used. | Constraint §5.3 (pinning) | 3 | +| REQ-MON-03 | All instants are stored in UTC; calendar-only values are stored as dates. | findings §F (hardcoded "today", `js/data.js:237`) | 1 | + +--- + +## 3. Proposed requirements + +Not stated in assignment §3, but **required** to satisfy something that is. Each needs an +owner's acknowledgement, not a re-debate — if a `PROP-` item is rejected, the confirmed +requirement it supports becomes unsatisfiable and that must be stated explicitly. + +| PROP | Proposed requirement | Supports | Why it is proposed rather than confirmed | Owner | Phase | +|---|---|---|---|---|---| +| PROP-01 | Phase 0 escaping + CSP patch of the existing prototype, with a CI gate against new unescaped interpolation. | REQ-SEC-06 | §3 does not mention the prototype's XSS exposure; findings §E makes it P0 the moment real CV or mail data lands. 2–3 developer-days. | Talha Ahmed | 0 | +| PROP-02 | A recruiter-facing intake triage queue with explicit `needs_review`, `rejected_unusable` and `quarantined` outcomes. | REQ-INT-04, REQ-INT-09 | §3 requires failures be visible; it does not specify the surface. This is where OBD-06 lands operationally. | Talent Ops | 1 | +| PROP-03 | Candidate-facing access tokens (hashed, scoped, expiring, revocable) for status pages, upload links and interview confirmations. | REQ-SEC-07, REQ-CAN-09 | Emailed links leak by forwarding and archives; an unguessable id can never expire or be revoked. | Talha Ahmed | 3 | +| PROP-04 | A fairness-evaluation **gate**: no scoring configuration version becomes active without a passing evaluation reference. | REQ-GOV-04, REQ-GOV-05 | §3 requires evaluation before release; a gate is what makes that enforceable rather than procedural. | Legal + Talent Lead | 3 | +| PROP-05 | A machine-readable PII classification registry with a CI completeness check. | REQ-DAT-03, REQ-DAT-04 | Three jobs must read the classification (purge, subject-access export, non-production anonymisation); prose cannot be read by a job. | Ahmed Mujtaba | 1 | +| PROP-06 | Controlled vocabularies and templates administered through a back-office admin rather than a bespoke Settings UI in Phase 1. | REQ-JOB-08 | Removes FR-22 from the Phase 1 critical path without blocking anyone. | Talent Ops | 1 | +| PROP-07 | A reapplication cooling-off period with an audited override. | REQ-APP-05 | §3 requires reapplication support but sets no interval. A hard block invites recruiters to create duplicate candidates to evade it. | Talent Lead (OBD-08) | 1 | +| PROP-08 | Audit hash chaining plus a daily export of closed audit partitions to write-once storage. | REQ-HIS-03, REQ-HIS-04 | Grants and triggers prevent application tampering; only an off-box immutable copy provides an independent check. Stated as tamper *evidence*, not prevention. | Talha Ahmed | 2 | +| PROP-09 | An FX rate table plus a per-row pinned reporting currency for cross-jurisdiction compensation reporting. | REQ-MON-02, REQ-ANL-06 | Six posting jurisdictions and a single leadership view require conversion; converting at read time makes reports drift. | Finance + Talent Lead | 3 | +| PROP-10 | A non-identifying address list (agency mailboxes, `info@`, shared family addresses) excluded from the one-email-one-identity rule. | REQ-CAN-05 | Real agency and referral submissions will otherwise fail resolution and silently back up the review queue. | Talent Ops | 1 | +| PROP-11 | An unmerge confirmation screen that lists exactly which rows will remain with the survivor before the recruiter confirms. | REQ-DUP-05 | Rows created after a merge have no defensible pre-merge owner; showing the list converts an invisible surprise into an informed decision. | Ahmed Mujtaba | 2 | +| PROP-12 | Database-level prevention of interviewer double-booking. | REQ-ITV-04 | Application-level checks race under concurrent scheduling. | Talha Ahmed | 2 | +| PROP-13 | A score-explanation panel plus AI-provenance badges on every AI-derived value in the UI. | REQ-SCR-07, REQ-GOV-03 | §3 requires explainability and content labelling; neither exists as a UI surface today. | Ahmed Mujtaba | 1 | +| PROP-14 | A dedicated recruiting mailbox plus an Entra ID app registration with admin-consented mail scopes. | REQ-INT-02 | Inbound channel #1 is Outlook (BRD §8.1) and this dependency sits with corporate IT, outside the team's control. Start in Phase 0. | Corporate IT | 0 | +| PROP-15 | Retention purge implemented as pseudonymisation with skeleton-row retention, not row deletion. | REQ-DAT-06 | The only mechanism that lets permanent history and erasure coexist. | Legal | 2 | +| PROP-16 | Five end-to-end smoke journeys in CI plus module-facade test coverage. | REQ-GOV-11, all | There are no tests, no test runner and no CI anywhere today (findings §B). | Ahmed Mujtaba | 0 | +| PROP-17 | An intake-to-candidate resolution record with its own actor, timestamp, reason and evidence. | REQ-INT-01, REQ-INT-09 | §3 requires raw intake before candidate creation; the *decision* to promote is the reviewable artefact and needs to be a stored thing. | Talha Ahmed | 1 | +| PROP-18 | A stated per-capability availability model behind AI Studio, driven by real capability status. | REQ-GOV-10 | All fifteen capabilities are already visible in the UI, which creates the expectation that they are nearly done. | Talha Ahmed | 1 | +| PROP-19 | An `actor_unknown` data-quality signal wherever a history row was written without an attributable actor. | REQ-HIS-02 | Background jobs, imports and ad-hoc SQL fixes will bypass actor propagation; a visible gap is far better than a wrong attribution. | Talha Ahmed | 1 | +| PROP-20 | A parse-confidence threshold below which a field is left empty and flagged for review, per field. | REQ-INT-07 | BRD §11 asks for population "without recruiter re-keying"; real mixed-quality PDFs will not reach that unqualified standard, so the review step must be designed in rather than discovered. | Talent Ops | 1 | + +--- + +## 4. Deferred requirements + +Confirmed or accepted in principle, deliberately **not** in the phase in hand. Each carries +the phase it is expected in and the condition that must hold before it starts. + +| DEF | Deferred item | Target phase | Entry condition | Consequence of deferring | +|---|---|---|---|---| +| DEF-01 | Per-requisition custom pipeline configuration (beyond the seven default stages). | 3 | A second job family demonstrably needs different stages. | Phase 1–2 uses one default pipeline; FR-6 still satisfied. | +| DEF-02 | Assessments module (FR-13, REQ-ASM-01/02). | 3 | Interviews and scorecards are live. | Assessment data stays outside the platform until Phase 3. | +| DEF-03 | Offers with approval chain (FR-14, REQ-OFR-*). | 3 | Requisition approval chain proven in Phase 1. | Offers continue outside the platform; a real gap for Talent Ops, stated. | +| DEF-04 | Outbound publishing to eight platforms (FR-8, REQ-PUB-*). | 4 | Job-board credentials and cost approval exist (OBD-13). | Requisitions are posted manually until then. | +| DEF-05 | Full tool-using assistant (AI-10, REQ-AIC-10 full). | 4 | RBAC enforced and audited; PROP-03 and REQ-GOV-09 verified. | Phase 2 assistant is read-only — see §6 row 15. | +| DEF-06 | Talent pool re-surfacing and rematch (FR-5, REQ-CAN-10). | 3 | Candidate/application split live and scoring stable. | Rejected candidates are not systematically re-surfaced until Phase 3. | +| DEF-07 | Outbound email delivery **pipeline** — templates UI, retry with backoff, bounce and complaint handling, digests, per-user preferences (FR-20 email, AI-7). | **2 (full). A minimal send slice is Phase 1, not deferred** — see the note below this table. | Notification templates approved; sender domain configured. | Phase 1 sends only the transactional replies the intake failure paths need; internal notifications are in-app rows until Phase 2. | +| DEF-08 | Saved report library (FR-17). | 3 | Dashboard KPIs stable and read models materialised. | Phase 2 ships fixed KPIs, not ad-hoc reports. | +| DEF-09 | Bespoke Settings UI (FR-22). | 4 | Admin back-office proves insufficient. | Covered in Phase 1 by PROP-06 and `identity`. | +| DEF-10 | Help / knowledge base (FR-23). | 4 | — | Lowest value; static docs suffice. | +| DEF-11 | Referral, agency, campus and walk-in intake forms (4 of 11 channels). | 4 | Form ownership and field sets agreed (OBD-11). | Those channels arrive via Outlook or manual upload in the meantime. | +| DEF-12 | Job-board inbound ingestion — LinkedIn, Indeed, Rozee, Mustakbil (4 of 11 channels). | 3 | Per-board API entitlement or a stable email format (OBD-13, and §6 row 2). | Board applications arrive through the Outlook channel. | +| DEF-13 | AI capabilities AI-4 through AI-15 (REQ-AIC-04..15). | 2–4 by BRD priority | AI-1/2/3 live and evaluated. | AI Studio must show honest availability (PROP-18) or the team is judged against the mockup. | +| DEF-14 | pgvector semantic retrieval and hybrid search. | 2 | Phase 1 FTS + trigram search measured and found insufficient for a named query class. | Phase 1 search is lexical and fuzzy, not semantic. | +| DEF-15 | Row-level security for the AI query path. | 2 | The application authorization layer is live and tested. | Phase 1 candidate PII protection rests entirely on the new application layer — a stated risk. | +| DEF-16 | A separately isolated untrusted-parsing worker queue. | 2 | — | Phase 1 mitigations (timeouts, memory caps, restricted OS user, no outbound network) are weaker than a sandbox. Stated risk. | +| DEF-17 | Candidate-facing self-service portal. | Out of scope this phase | Product decision (OQ-7 → OBD-07). | The RBAC role exists with zero provisioned seats (BRD §4). | +| DEF-18 | Special-category / diversity data capture. | Not planned | Separate lawful basis, aggregate-only reads and distinct access control agreed with Legal. | Fairness evaluation must run on proxies or externally supplied cohorts (OBD-02). | +| DEF-19 | PWA installability and offline shell. | 4 | A data-protection position on caching candidate PII on personal devices. | Responsive web already meets NFR-2/3/6. | +| DEF-20 | Read replica dedicated to search. | On trigger | p95 search latency exceeds 500 ms after index and query tuning. | Not expected at the assumed volume (ASM-03). | +| DEF-21 | Hiring-manager and calendar modules as standalone stores. | Never as modules | — | Managers are users with roles and assignments; calendar is a view over interviews. Deliberate consolidation, not an omission. | + +**DEF-07 — the outbound-mail split, ruled once.** Four documents previously phased outbound +email four different ways (this table at 2–3, OBD-21 at Phase 3, `03` §5 / §33 migration 018 and +`07` §5.1 at Phase 2, `04` §9.1 row 5 arguing for Phase 1). The binding split, recorded here and +mirrored in `03` §22 / §33, `04` §9.1 row 5, `07` §4.1 / §4.2 / §5.1 and `08` §2.14 / §7 finding 10: + +| Phase | What lands | Why it cannot sit on the other side of the line | +|---|---|---| +| **1 — minimal slice** (~4–6 dev-days, `07` T-16b) | One `app.outbound_message` row per send; `Mail.Send` through the **same** `MailProvider` port the inbound Graph adapter already uses; the send idempotency guard; NDR/bounce **classification** on the inbound side; one seeded transactional template ("send an unprotected copy of your CV"). Plus the in-app `app.notification` row `07` §4.2 already promised. | Phase 1 owns inbound email and CV parsing. Without a send path, **every parse failure is a dead end a recruiter resolves in Outlook by hand, outside the audit trail** — and an NDR arriving with no `outbound_message` row to attach to cannot be classified at all. This is a correctness hole in Phase 1, not a missing Phase 2 feature. | +| **2 — full pipeline** (`07` T-29, A-31, A-36) | Template authoring UI and versioning workflow, retry with backoff, complaint handling, digest sends, per-user `notification_preference`, the in-app notification centre. | None of it is needed to make a Phase 1 failure path actionable, and all of it needs sender-domain configuration and template approval, which are other people's work items. | + +The distinction that makes this coherent: Phase 1 sends **transactional candidate-facing replies +the intake pipeline itself generates**. Phase 1 does **not** email internal users — that is +OBD-21's subject and it stays in-app until Phase 2. + +--- + +## 5. One-month expectation — stated plainly + +One month with two developers delivers **Phase 0 plus the first end-to-end thread of +Phase 1**: one channel ingesting real mail, a CV parsed into a candidate, one application +created against a versioned requisition, one score with visible components, on one hardened +screen. It does not deliver a platform, and any plan that says otherwise is wrong. + +| Phase | Scope | Range | Confidence | +|---|---|---|---| +| 0 | Prototype XSS/CSP hardening; repo, CI, container, Postgres, migration skeleton; `identity` + `audit` + `config`; ADRs; frontend shell scaffold | 2–3 weeks | High | +| 1 | Vertical slice: intake → parsing → candidate → versioned requisition → application → assignment → scoring v1 with explanations; three inbound channels; enforced RBAC; five screens | 10–14 weeks | Medium | +| 2 | Pipeline board; interviews + scorecards; duplicate review and reversible merge UI; dashboard KPIs; notifications; worklist; read-only assistant | 7–10 weeks | Medium-low | +| 3 | Assessments; offers with approvals; report library; fairness-evaluation gate; talent pool; job-board inbound | 7–10 weeks | Low | +| 4 | Outbound publishing; full tool-using assistant; remaining P2 AI capabilities; Settings and Help | 5–8 weeks | Low | + +Confidence degrades after Phase 2 because Phase 3 depends on unresolved business decisions — +OBD-01 (model hosting), OBD-02 (historic outcome data) and OBD-04 (jurisdictions). + +--- + +## 6. Verdict on every unconfirmed idea (assignment §4) + +Verdicts use exactly one of: **Recommended now** / **Recommended later** / **Not +recommended** / **Dependent on existing stack** / **Dependent on business confirmation**. + +| # | Idea | Verdict | Reason | Condition that changes the verdict | +|---|---|---|---|---| +| 1 | Mandatory public screening form before CV submission | **Dependent on business confirmation** | Changes the intake mix and the candidate experience, and knock-out questions are a regulated screening decision in several of the six posting jurisdictions. The career portal already exists as channel #2 (BRD §8.1); making a structured form *mandatory* is a policy choice, not an engineering one. Recommended shape if approved: optional per requisition, structured answers stored on the application, never used as an automatic reject. | Talent Lead confirms it may be mandatory per requisition **and** Legal approves the question set as non-discriminatory. Then: Phase 2, small. | +| 2 | Direct LinkedIn API integration | **Dependent on business confirmation** | There is no general-purpose LinkedIn ATS ingestion API outside its Talent Solutions partner programme; access requires a commercial entitlement Utopia may or may not hold, and scraping is prohibited by LinkedIn's terms. This is a contract question before it is a build question. Interim path costs nothing: LinkedIn application notifications arrive as email and are ingested through the Outlook channel (REQ-INT-02). | Utopia produces a Recruiter System Connect / Talent Hub entitlement and API credentials. Then: DEF-12, Phase 3. | +| 3 | Automatic HRMS sync | **Dependent on existing stack** | HRIS is explicitly out of scope this phase (BRD §3.2) and no HRMS is named anywhere in the assignment or the repository. A bidirectional sync also creates a second source of truth for a person, which is the failure mode already rejected for the `managers` entity. | An HRMS is named, has a documented API, and Talent Ops confirms direction. Recommended shape: **one-way export of hired candidates only**, Phase 4. Bidirectional sync stays not recommended. | +| 4 | Native mobile app (iOS/Android) | **Not recommended** | 66 named seats, of which 24 are interviewers who consume only assigned-interview data (BRD §4). The responsive web app already meets 320px, 44px touch targets and safe-area handling, verified (NFR-2/3/6, findings §G). Two app stores, two release trains and a third codebase for two developers is indefensible. | Interviewer scorecard completion measurably fails on mobile web, **or** push notification delivery becomes a hard requirement that web push cannot meet. Even then, evaluate DEF-19 first. | +| 5 | Progressive Web App (installability, offline shell) | **Recommended later** | Cheap once the React shell exists — a manifest, an app-shell service worker and an install prompt. Not now for one substantive reason: caching candidate PII on personal devices needs a data-protection position under BRD §7.4, and there is no Phase 1 offline data story worth having. | Nothing blocks it technically. Phase 4 (DEF-19), after Legal accepts a cache policy that excludes candidate PII. | +| 6 | Vue / React / another frontend framework | **Recommended now** — React 18 + Vite + TypeScript, progressive migration | Decided in `_decisions.md`: the CSS is the valuable verified asset (1269 lines, 93 design tokens across 159 custom-property declarations and 470 `var(--…)` references (measured, `01` §12), dual themes, WCAG AA across 23 routes × 2 themes) and is preserved verbatim; the *rendering layer* is the liability — 34 unescaped `innerHTML` sites (findings §E), ~115 form-control sites across 15 files, 22 ordered `