HR-ATS-Portal/docs/architecture/_repo-findings.md

11 KiB
Raw Blame History

Repository Inspection Evidence — verified facts

Working note. Every claim below was verified by direct inspection on 2026-07-29. Authoring agents MUST use these facts and cite these file paths. Do not re-derive or contradict them. Do not invent files, frameworks, or config that is not listed.

A. What the repository actually is

A static, browser-only frontend prototype. There is no backend of any kind.

Complete file inventory of the prototype as inspected on 2026-07-29 (excluding .git/, .backup-prebrand/). Files added afterwards by this design package are listed separately below, so the prototype's own line counts stay comparable:

index.html                 287 lines
css/styles.css            1269 lines   (design system, brand-tokenised)
js/  (22 files, ~4,780 lines total — `wc -l js/*.js` = 4,779)
  data.js      512   charts.js  347   candidates.js 441   inbox.js   332
  app.js       275   jobs.js    252   aiassistant.js 218  interviews.js 209
  misc.js      207   import.js  176   jobboard.js   172   pipeline.js 166
  dashboard.js 170   ui.js      252   offers.js     139   assessments.js 126
  recruiterhub.js 121  rbac.js  117   analytics.js  114   reports.js 109
  settings.js  193   tasks.js   131
devserver.py                36 lines   (no-cache static server, added for preview only)
docs/TalentFlow-ATS-Business-Requirements-v1.0.docx
.gitignore                  42 lines
.claude/launch.json
.audit.js                              (dev-only QA helper, gitignored)

Added after inspection by this design package, and not part of the prototype or of any line count quoted anywhere in these documents:

docs/architecture/                     this package
tools/check_evidence_citations.py      documentation gate: verifies every `path:line`
                                       citation in docs/architecture against the source

B. ABSENT — verified by find / direct check

None of the following exist anywhere in the repository:

  • package.json, any lockfile, node_modules/
  • requirements.txt, pyproject.toml, Pipfile
  • composer.json, go.mod, Gemfile, pom.xml, build.gradle
  • Dockerfile, docker-compose.yml, Makefile
  • .env, .env.example (none present; .gitignore anticipates them)
  • Any migration directory or migration tool
  • Any ORM, query builder, or database driver
  • Any test file, test runner, or CI configuration (.github/ absent)
  • Any build tooling (tsconfig.json, vite.config.js, webpack.config.js)
  • Any API route, controller, service, or server-side code
  • Any meeting transcript or recruitment document (searched repo and ~/Documents to depth 2 — only the BRD .docx this project produced)

Consequence: there is no backend stack to preserve. Operating Rule 9 ("do not replace the existing stack") therefore constrains only the frontend and design system, not the backend, which is a greenfield choice.

C. Frontend architecture — verified

Fact Evidence
Zero network calls. grep for fetch(, XMLHttpRequest, axios, $.ajax, WebSocket, EventSource across js/ and index.html returns nothing. The UI is fully self-contained. repo-wide grep
All data is generated in-browser at load by a seeded LCG PRNG (seed = 88123), so the dataset is stable across reloads but exists only in memory. Nothing persists. js/data.js:8-10
100 candidates, plus jobs/interviews/assessments/offers/inbox generated at load. js/data.js:110-131
Hardcoded "today" — new Date('2026-07-09') used as the current date in multiple places. js/data.js:237, js/candidates.js:18, js/jobboard.js:167
localStorage used only for the theme preference. No session or app state. js/app.js:64,193,198
Client-side hash router over location.hash; views are functions returning HTML strings plus an onMount hook. 23 routes. js/app.js:20-57 (Router.go, Router.render), ROUTES map js/app.js:7-16
Global namespaces on window: DB, UI, Charts, App, Router, Views, plus per-module globals. No modules, no bundler, 22 <script> tags in order. index.html:264-285

D. Authentication and authorization — verified ABSENT

Fact Evidence
No authentication whatsoever. No login screen, no token, no session. repo-wide grep
Security settings are inert UI chrome — 2FA, SSO, session timeout and password policy render as toggles/selects with no handlers and no persistence. js/settings.js:148-154
The RBAC permission matrix is a display widget only. Clicking a cell mutates an in-memory array; nothing reads the matrix to gate behaviour. There is no can(), hasPermission(), or equivalent anywhere. js/rbac.js:78, js/rbac.js:83-85, js/rbac.js:111-112
Roles/permissions are demo data: 8 roles, 13 modules, 8 permission types, matrix derived from a single level cutoff index. js/data.js:425-446 (rbacModules, permTypes, rbacRoles, buildMatrix)

E. SECURITY — P0 finding: systemic XSS exposure

Fact Evidence
No HTML escaping exists anywhere. grep for escapeHtml, sanitiz, DOMPurify returns nothing. repo-wide grep
34 innerHTML assignments across 14 files; every view builds HTML by template-string interpolation of data values. grep -c innerHTML js/*.js
Candidate-controlled fields are interpolated raw into markup — e.g. ${c.name}, ${c.currentTitle}, ${c.location}. js/candidates.js:68
Inline event handlers with interpolated values, e.g. onclick="Candidates.openProfile('${c.id}')". js/candidates.js:121

Why this is P0 and not theoretical: today the data is synthetic and generated locally, so nothing is exploitable. The moment real data flows in — and the two primary Phase 1 sources are CV files and inbound email, both attacker-supplied — every screen becomes a stored-XSS sink. A CV containing <img src=x onerror=...> in its name field would execute in a recruiter's session with full application privileges. This must be fixed before any real data is rendered, and it is a rendering-layer change, not a backend one.

F. Data-model gaps in the prototype (all confirm the prompt's principles)

Gap Evidence Implication
No candidate/application separation. One flat candidates array carries jobId, jobTitle, stage, aiScore, recruiter directly on the candidate. One candidate cannot hold two applications. js/data.js:117-127 Confirms prompt §5.2 — must be split.
ATS score is a random integer, aiScore: int(52,98). No components, no evidence, no model, no version. A separate client-side "relevance" blend also exists. js/data.js:123, js/candidates.js:18 Confirms prompt §5.6 — nothing reusable.
No raw intake layer. The inbox is a pre-resolved array already joined to candidate and job; there is no unresolved/failed state that cannot become a candidate. js/data.js:284-300 (processingStatuses, inbox) Confirms prompt §5.1.
No versioning of jobs or requirements. Jobs are mutable single records. js/data.js:85-108 Confirms prompt §5.3.
Recruiter assignment is a single scalar (recruiter, recruiterId) on the job/candidate. No history, no primary/supporting distinction. js/data.js:96, js/data.js:123 Confirms prompt §5.4.
No history tables. Current values only — no stage history, assignment history, or status history. js/data.js throughout Confirms prompt §5.5.
Money is a bare integer. salary: int(90,190)*1000. No currency field anywhere in the dataset; offer validation only checks > 0. js/data.js:126, js/offers.js:129 Needs decimal + ISO currency.
No timezone discipline. JS Date objects, toLocaleDateString for display, hardcoded "today". No UTC storage, no tz-aware scheduling. js/data.js:54,237 Interview scheduling will need real tz handling.
No requisition concept at all. No director role scoping. absent from js/data.js Phase 2 greenfield.

G. Genuinely reusable assets (retain)

Asset Why it is worth keeping Evidence
Design system — 1269 lines of tokenised CSS: dual light/dark themes, Utopia brand palette and type hierarchy, responsive 320px→ultrawide, WCAG 2.1 AA verified across 23 routes × 2 themes (8,459 text nodes, 0 failures), 44px touch targets, safe-area/dvh handling. Substantial, verified, brand-compliant work. Rebuilding it would be pure loss. css/styles.css
js/ui.js primitivesmodal, toast, dataTable (sort + paginate + render hooks), badge, avatar, avatarStack, scoreChip, pbar, fieldError, clearErrors, icon set. A coherent component vocabulary already matching the design system. js/ui.js:251 (export list)
js/charts.js — dependency-free canvas chart engine (line/area, bar, grouped bar, doughnut, horizontal bar, sparkline) reading colours from CSS custom properties so it re-themes automatically. Avoids adding a charting dependency; already theme-aware. js/charts.js:339
23-route information architecture — the module breakdown, navigation grouping and screen inventory are a validated UX artefact even though the data layer behind them is fake. Useful as the Phase 1+ screen backlog. js/app.js:7-16

H. Frontend liabilities (refactor)

Liability Evidence Note
String-template innerHTML rendering with no escaping — see §E. 34 sites P0 before real data.
No build step, no modules, 22 ordered <script> tags, everything on window. Complex forms (requisitions, offers, scorecards) in this pattern will not scale to 25 modules with two developers. index.html:264-285 Real tension: retain the CSS/UX, reconsider the rendering layer.
No client-side validation library; ad-hoc per-form checks. js/offers.js:129, js/ui.js:241-249
No tests of any kind. absent
.gitignore contains a Python section and .env rules but no Node section. This postdates devserver.py (added for local preview), so it is weak/ambiguous evidence of stack intent and must not be presented as a decision input. .gitignore Do not over-read this.

I. Team

  • Talha Ahmed — senior; ATS scanning, candidate matching, AI workflows, architecture, integrations.
  • Ahmed Mujtaba — junior; capable coder. Must get small, modular, varied, independently demonstrable work across frontend, backend APIs, validation, testing, AI UX, dashboards and workflow logic. Explicitly not only repetitive CRUD or data cleaning. Every task needs a Talha review checkpoint.

J. Hard constraints for all authors

  • Internal Utopia Brands system. Not multi-tenant SaaS.
  • One platform, one master data model, one relational database. No regional databases.
  • Do not invent repository contents. If something does not exist, say so and cite §B.
  • Do not print or copy secret values (none exist to leak — no .env present).
  • No transcript exists; the assignment prompt is the authoritative requirements source. State this explicitly rather than implying a transcript was read.