Enterprise Readiness Assessment¶
1. Executive summary¶
Verdict: The newest UI in the Someli platform, and the strongest signal of forward direction (Vite + React + TS + shadcn/ui + Tailwind, vs the Nuxt 2 / Vue 2 legacy of the customer and designer FEs). Codebase is small, modern, dependency-clean — a fundamentally healthy starting position. Weaknesses are uniformly maturity-level (no tests, no CI, no observability, no documented deploy story) rather than design-level. The biggest concrete risks are token-in-localStorage with no real revocation (inherited from the backend's auth design), and a third-party Lovable.dev script in production HTML without integrity verification.
Top 3 strengths: 1. Modern dependency tree, all current versions, no squatters — a notable contrast to the backends 2. shadcn/ui + Radix UI gives accessibility, keyboard handling, focus traps for free in most primitives 3. TypeScript — first FE in the platform with type-safety; sets a pattern future work can adopt
Top 5 risks:
1. Token in localStorage + no token expiry + no real revocation = long-lived credential exposure on any XSS
2. Third-party script (cdn.gpteng.co/gptengineer.js) in production HTML without SRI
3. No tests, no CI gating type errors → regressions ship freely
4. Role IDs configured via env vars → drift risk with backend
5. No observability, no error tracker → production bugs go unseen until users complain
Top 5 recommendations:
1. This week: remove/secure the Lovable.dev script; add noindex meta + robots.txt; strip console.log from production builds; fix hardcoded Apptype to use ENV.APP_TYPE
2. Phase 0: add CI (lint + tsc + build); add Sentry + web-vitals; add 401-handler in api.ts; add multi-tab storage listener
3. Phase 0: commit a Dockerfile or deploy workflow (currently absent)
4. Phase 1: add eslint-plugin-jsx-a11y; "skip to content" link; focus-on-route-change; document WCAG target
5. Phase 1: migrate token to httpOnly cookie (coordinated BE change in Someli-admin-api)
2. Methodology & scope¶
Audited via find, cat, grep, wc against the cloned someli-gh/admin_console_R/ directory. No build run (so projected bundle sizes are estimates from dependencies). No tests run (none exist).
3. Maturity assessment (CMMI 1–5)¶
| Pillar | Current | 12-mo target | Why |
|---|---|---|---|
| Architecture & Modularity | 3 | 4 | Clean Vite + React + TS layout; small component tree; healthy code style |
| API Contract & Versioning | 1 | 2 | No typed envelopes, no OpenAPI bindings; named methods are typed loosely |
| Data Architecture | 2 | 3 | React Query mounted but lightly used; localStorage for auth (XSS risk) |
| Background Processing | n/a | n/a | n/a — FE |
| Security & Compliance | 1 | 3 | Token in localStorage; 3rd-party script without SRI; no CSP from repo; console.log of PII to prod |
| Observability | 1 | 3 | console-only; no Sentry / RUM / analytics |
| Reliability & Resilience | 2 | 3 | No error boundaries; no 401 handler; no multi-tab sync |
| Scalability | 3 | 3 | Small app; static bundle; not a concern at current scale |
| Testing & Quality Gates | 1 | 3 | Zero tests; no tsc --noEmit in CI; ESLint exists but no CI gate |
| CI/CD & Deployment | 1 | 3 | No CI workflow / Dockerfile / hosting config in repo |
| Infrastructure as Code | 1 | 2 | nothing |
| Cost Visibility & FinOps | 2 | 2 | Static hosting; negligible cost |
| Documentation & Knowledge Management | 2 | 3 | No in-repo README beyond Vite default; this audit covers the gap |
| Team Practices & Governance | 2 | 3 | No PR template, no code-owners; branch model implied not documented |
4. Findings¶
Cross-references: see security.md, api-consumption.md, authentication-client.md, observability.md.
| ID | Severity | Description | Phase |
|---|---|---|---|
| F-1 | MEDIUM | Token in localStorage; XSS = long-lived takeover | 1 (BE+FE coord) |
| F-2 | LOW | api.ts hardcodes Apptype = btoa("admin-console") instead of reading ENV.APP_TYPE |
0a |
| F-3 | MEDIUM | cdn.gpteng.co/gptengineer.js in production HTML without SRI |
0a |
| F-4 | MEDIUM | No CSP set from repo (depends on hosting layer) | 0 |
| F-5 | LOW | No SRI on the one external script | 0a |
| F-6 | LOW (dev) | HMR overlay disabled | 0 |
| F-7 | LOW | lovable-tagger dev-plugin loaded (intentionally dev-only) |
n/a |
| F-8 | LOW | Vite fs.deny minimal; verify |
n/a |
| F-9 | LOW | No DOMPurify (only matters if dangerouslySetInnerHTML is added) |
n/a |
| F-10 | LOW | user_email in localStorage |
0 |
| F-11 | MEDIUM | No 401 → logout in api.ts |
0 |
| F-12 | LOW | Two coexisting toast libs (sonner + shadcn) | 0a |
| F-13 | LOW | Three lockfiles in repo (npm + yarn + bun) | 0a |
| F-14 | LOW | console.log of PII in production builds |
0a |
| F-15 | LOW | Role IDs configured via env vars (drift risk with BE) | 1 |
| F-16 | n/a | No <meta noindex> or robots.txt |
0a |
5. Strategic decisions¶
-
This is the platform's future FE stack. Future internal UIs should follow Vite + React + TS + shadcn/ui rather than Nuxt 2 + Vue 2. Don't extend the Nuxt repos for new product surface.
-
shadcn/ui is the right choice for an internal tool — fast iteration, generated code is editable, Radix UI accessibility is solid. Don't replace.
-
Authentication needs work, but the changes are coordinated with
Someli-admin-api. Pursue the BE-side fixes (token expiry, DB-backed revocation, httpOnly cookie) first; the FE changes follow. -
CI/CD is the most-leveraged gap. One workflow file (~50 lines) closes the type-check / lint / build / deploy loop. Until then, every PR is hand-verified.
6. Roadmap¶
Phase 0a — This week¶
- Remove or secure
cdn.gpteng.coscript (F-3) - Fix hardcoded
Apptype(F-2) - Strip
console.login production via Viteesbuild.drop(F-14) - Add
<meta name="robots" content="noindex, nofollow">andpublic/robots.txt(F-16) - Pick one package manager; delete the other two lockfiles (F-13)
- Decide sonner vs shadcn toast; remove the other (F-12)
- Add SRI to any remaining external scripts (F-5)
Phase 0 — Stabilise (0-3 months)¶
- GitHub Actions CI:
npm ci→npm run lint→tsc --noEmit→npm run build(F-CI gap) - Add 401 → logout in
api.ts(F-11) - Add multi-tab storage listener for logout
- Add Sentry +
web-vitals - Add error boundary
- Tighten CSP at hosting layer (F-4)
- Commit
vite.config.tssource-map config + Sentry upload step - Add Dockerfile / nginx.conf or formal hosting config
- Document deploy runbook
Phase 1 — Foundation (3-9 months)¶
- Add
eslint-plugin-jsx-a11y; do a manual a11y pass - "Skip to content" link + focus-on-route-change
- Add Vitest + msw + first 20 unit tests (auth, api client, key pages)
- Add Playwright + 5 E2E happy-path specs
- Migrate token to httpOnly cookie (coord with
Someli-admin-api) - Pin role IDs as const enum (vs env vars) (F-15)
- Standardise React Query adoption (vs raw fetch + useState)
Phase 2 — Modular refactor (9-18 months)¶
- Route-based code splitting (if route count grows)
- Storybook (if component count grows past ~75)
- Bundle-size CI check
- Set WCAG target + audit against it
Phase 3 — Selective extraction (18+ months)¶
- Not currently relevant for an internal admin tool
7. Risk register¶
| ID | Risk | Likelihood | Impact | Phase |
|---|---|---|---|---|
| R-1 | XSS on admin.someli.ai → token theft → long-lived account compromise of admin staff |
Low | High | 0 / 1 |
| R-2 | Lovable.dev CDN compromise → arbitrary JS in admin staff browsers | Low | High | 0a |
| R-3 | Regression ships because no CI / no tests | High | Low/Medium | 0 |
| R-4 | Admin staff member is offboarded but their stolen token remains valid because revocation is in-memory | Medium | Medium | 1 (BE) |
| R-5 | Production search engine indexing of admin URLs (gives recon to attackers) | Low | Low | 0a |
| R-6 | Backend role ID change without FE env var update → role-gating bug | Low | Medium | 1 |
| R-7 | Three lockfile drift → different installs across team / CI / prod | Medium | Low | 0a |
8. Standards compliance¶
- WCAG 2.1 AA: shadcn/Radix gets us most of the way; needs jsx-a11y lint + skip link + focus management
- OWASP A02 / A05 / A06 / A07: see
security.md - Core Web Vitals: not measured; projected to be fine at current bundle size
9. Open questions¶
See verify-markers.md.