Documentation
Below are all 14 findings recorded in this dimension during the audit, sorted by severity then launch priority. Each card carries the full anatomy: severity / priority / effort, code location, evidence, technical issue, business impact, plain-language explanation, fix steps, related dimensions, and references.
Findings — Documentation
<repo-root>:n/aDirectory listing of repo root (ls -la _clients/SONI-remix-new/): no README.md, README.markdown, Readme.md, or README.txt at any level of the tree. Glob '_clients/SONI-remix-new/**/README*' returned zero results. The single .md file in the entire tree is .lovable/plan.md, which is a Hungarian-language feature plan for Longevity Score v3 (the LLM-driven Score-weights migration), not project documentation.The repository has no README in any form. A new engineer joining the team has nowhere to learn what the product is, what stack it uses, how to install dependencies, how to run it locally, what env vars are required, how to deploy, or where to find further documentation. Every onboarding starts as a reverse-engineering exercise against 86,000 lines of TypeScript across 455 files plus 89 SQL migrations.
Documentation is the single highest-leverage onboarding artefact: its absence multiplies the cost of every future hire, contractor handover, and audit. For a sole-founder project this is also a bus-factor risk -- if the original developer is unavailable, the project is effectively undocumented and another engineer would need 2-5 days of code archaeology before producing useful output. For a regulated-domain product (health-adjacent, AI Act candidate per DOM-001 / DOM-005 / DOM-008) the absence of a top-level project description also makes regulator / counsel review impossible without a verbal walkthrough.
The project has no front-door document. Anyone new -- a contractor, a co-founder's developer, a future auditor -- arrives at the repository and finds no explanation of what the app is, how to run it, or where things live. They have to read the code itself to learn the basics. A short README is roughly half a day's work and removes this whole class of friction.
- Create README.md at repo root with sections: (a) one-paragraph product description (what SONI is, who it's for), (b) Tech stack one-liner (TanStack Start on Cloudflare Workers, Supabase, Lovable AI Gateway), (c) Prerequisites (Bun version, Node fallback, Wrangler), (d) Local setup (clone, bun install, copy .env.example to .env, fill in values, bun dev), (e) Scripts table (dev / build / lint / format), (f) Project layout (src/routes, src/server, src/components, supabase/migrations), (g) Deployment (link to Lovable platform docs + Wrangler), (h) Pointer to docs/ directory and CONTRIBUTING.md.
- Keep it under 200 lines -- a long README that no one updates is worse than a short one that engineers actually maintain.
- Pair with a .env.example (see OPS-002).
S — under ½ day
<repo-root>:n/aNo ARCHITECTURE.md, no docs/architecture.md, no /docs directory of any kind. Glob _clients/SONI-remix-new/**/{ARCHITECTURE,architecture}* returned zero results. The architecture must be inferred from: wrangler.jsonc (Cloudflare Worker entry), supabase/config.toml (Supabase project id), 38+ server files referencing process.env.LOVABLE_API_KEY (Lovable AI Gateway), src/integrations/supabase/auth-middleware.ts (server-side auth gate), public/sw.js (push), src/routes/api.coach-chat.ts and api.voice-coach-chat.ts (SSE), supabase/migrations/*.sql (42 tables across 89 timestamped migrations). Total surface to reverse-engineer: ~10 distinct moving parts with no diagram or written description tying them together.The system has many cooperating pieces -- a TanStack Start Worker on Cloudflare, a Supabase backend (Auth + Postgres + Storage with 7 buckets), the Lovable AI Gateway with two distinct model families (openai/gpt-5 for text, google/gemini-3-pro-image-preview for images), a service-worker push pipeline with web-push VAPID, a server-function RPC layer, SSE streaming endpoints for coach + voice coach, and a pg_cron-driven hooks family -- yet there is no document that names these components, draws their connections, or names the invariants between them (e.g. which surfaces are allowed to use the service-role client, which auth path attaches the Bearer token, which env vars apply to which side). Cross-dimension findings already document many of these moving parts piecemeal; what is missing is the single coherent picture.
Without an architecture overview, every conversation about the system starts at first principles. Audits (security, scalability, AI integration, domain compliance) all had to reconstruct the topology from source before they could even ask their first real question. For regulatory exposure tied to AI Act Article 11/12 (technical documentation requirement) and GDPR Article 30 (records of processing activities), an architecture document is the literal artefact the regulator expects to see; its absence forces ad-hoc reconstruction under time pressure if an inquiry lands.
There is no map of the system. The application connects a website-hosting platform (Cloudflare), a database (Supabase), an AI provider (Lovable), and a push-notification service -- but nowhere in the project does someone draw or describe how these fit together. A regulator, a new developer, or a security auditor cannot understand the system without first reading thousands of lines of code. A single-page architecture document with a diagram closes this gap in roughly a day.
- Create docs/architecture.md.
- Open with a Mermaid (or ASCII) diagram showing: Browser/PWA -> Cloudflare Worker (TanStack Start SSR + server functions + SSE routes) -> Supabase (Auth, Postgres, Storage) and Lovable AI Gateway (openai/gpt-5, google/gemini-3-pro-image-preview) and web-push/VAPID + Service Worker.
- Section per component: purpose, entrypoint file, key env vars, scaling assumptions, failure mode.
- Section on data flow: auth (cookie -> Bearer token -> auth-middleware -> Supabase claims), coach turn (user message -> context loaders -> SSE prompt -> Lovable Gateway -> persisted to coach_messages), avatar bank (seedAvatarBank -> generateNextBatch -> Storage).
- Section on invariants: service-role client is import-restricted to *.server.ts and api.* routes; RLS is the primary authorization gate (app-level checks are defense-in-depth); all AI calls are server-side.
- Cross-link to ADRs (DOC-.
- as decisions get recorded.
M — 1–3 days
<repo-root>:n/aNo docs/decisions/, no docs/adr/, no /RFC, no design-docs directory of any kind anywhere in the tree. Glob _clients/SONI-remix-new/**/{adr,ADR,rfc,RFC,decisions}/** returned zero results. Yet the project has made several non-obvious decisions that need to be defensible to a future engineer, auditor, or counsel: (a) chose Lovable AI Gateway as a single AI provider, with 38+ files hard-coding the gateway URL (already raised in AI-005), (b) chose Cloudflare Workers + TanStack Start (a relatively novel combination), (c) chose to drop the bloodwork_uploads / biomarkers / vital_logs / supplement_stacks tables (migration 20260505161305) -- the visible artefact of a wellness-not-medical pivot, but with no decision document explaining why or what the regulatory framing is, (d) chose Lovable @lovable.dev/cloud-auth-js OAuth bridge instead of using Supabase Auth native OAuth -- a security-relevant choice (cross-ref SEC-013), (e) chose to ship six locales (de, en, es, fr, hu, it) without an explicit market-coverage rationale, (f) chose to call the surface wellness coach / longevity coach rather than health (per the .lovable/plan.md disclaimer Eletmod-pontszam, nem orvosi diagnozis -- Lifestyle score, not medical diagnosis) -- this is a regulatory-positioning decision per DOM-001 (EU MDR Rule 11) but it is documented only in a feature-plan markdown file inside a tool directory, not as a project-level decision record.Several of the most consequential choices are not written down anywhere a future engineer or auditor would think to look. The wellness-vs-medical framing in particular is a regulatory shield -- if a regulator ever asks why did you delete the bloodwork tables and re-label as wellness, the only available answer today is because the developer remembers deciding that. That is not an audit-grade answer. Similar issues apply to the AI-provider choice (AI Act technical documentation expects to see this), the auth-provider choice (security audit needs the rationale to assess the OAuth-bridge attack surface), and the locale selection (a contractor adding a new locale has no rule for whether to include it).
Decision records are how a project survives turnover. Without them, every significant architectural question gets reopened on every team change, and regulatory disclosures become best-effort reconstructions. The wellness-vs-medical record in particular is high-leverage: DOM-001 already flags MDR Rule 11 exposure, and the supporting evidence (we explicitly avoided diagnostic intent purpose) has no written home today. Recording the decision now, while the original developer is still in the room, costs about a day; reconstructing it under a regulator inquiry costs orders of magnitude more.
The project has made several decisions that a future regulator or technical reviewer will ask about -- why this AI provider, why drop the bloodwork tables, why wellness not medical, why these six languages. None of these decisions are written down anywhere. The fix is a small folder of short decision memos (one page each, 10-15 of them total) that capture the why behind each non-obvious choice. This is one of the cheapest pre-launch investments with the highest payoff in audit-readiness and team-resilience.
- Create docs/decisions/ with a README.md explaining the ADR format (Michael Nygard template: Context, Decision, Status, Consequences) and an index.
- Backfill ADRs for the consequential decisions already made (each 1-2 pages): ADR-0001 Wellness scope, not medical device (the Codex / Longevity Score framing, the bloodwork-tables drop, the EU MDR Rule 11 positioning, links to .lovable/plan.md and DOM-001), ADR-0002 Lovable AI Gateway as sole AI provider (provider lock-in trade-off, fallback plan or explicit acceptance, cross-ref AI-005), ADR-0003 Cloudflare Workers + TanStack Start runtime (why nodejs_compat, cold-start posture), ADR-0004 Supabase Auth + Lovable cloud-auth-js OAuth bridge (with security trade-offs per SEC-013), ADR-0005 Six-locale initial coverage (market rationale, addition policy), ADR-0006 Coach memory model (4 coach_* tables, purpose split, retention rules, cross-ref DAT-001 / DAT-003), ADR-0007 Service-role key usage boundary (which modules may import client.server.ts, cross-ref SEC-002 / SEC-003), ADR-0008 AI-generated content labeling posture (cross-ref DOM-005 / AI-004).
- Adopt a rule: any PR that introduces new vendor, new auth surface, new regulated-data table, or new AI prompt model adds or updates an ADR.
M — 1–3 days
<repo-root>:n/aNo .env.example, no docs/env.md, no env section in any README (because there is no README). Per stack-profile section 3, the actually-required environment variables are: SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, SUPABASE_SERVICE_ROLE_KEY, LOVABLE_API_KEY, VAPID_SUBJECT, VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VITE_SUPABASE_URL, VITE_SUPABASE_PUBLISHABLE_KEY, VITE_SUPABASE_PROJECT_ID. None of these are listed in a single contributor-facing place. Stack-profile evidence: process.env.LOVABLE_API_KEY referenced from 38+ files; .env present at repo root (647 bytes, 5 lines); no .env.example file exists.OPS-002 already flags the absence of .env.example. The documentation angle is distinct: even if a future engineer creates the .env.example, the meaning of each variable -- where it comes from (Supabase project settings? Lovable account? web-push self-generation?), which side it runs on (server-only vs Vite-bundled), and what happens at runtime if it is missing or wrong -- is still nowhere captured. The VAPID keys in particular have a non-trivial generation step (web-push generate-vapid-keys) that a new engineer would not know without being told.
Every new contributor (including auditors) loses 1-2 hours grepping the source to compile the env list and ask the operator for values. For the bring-your-own-provider keys (Lovable, Supabase), the operator-side documentation gap also matters: if the operator rotates a key, they have no checklist of where it needs to land. This is a fix_in_first_sprint priority that we have promoted to must_fix_before_launch because it stacks with OPS-002, OPS-004, and SEC-001 (.env committed) -- together they form the deployment-secrets blind spot.
The app needs about ten secret keys to run, but there is no list anywhere of what they are, where to get them, which ones are server-only versus public, or what to do if one of them changes. A short docs/env.md fixes this and also serves as the checklist for rotating keys during incident response.
- Create docs/env.md (or an Env section in README).
- Table with columns: name, scope (server-only / Vite-bundled / both), source (Supabase project settings, Lovable account, generate via web-push generate-vapid-keys, etc.), required (yes/no), example value (always masked / eyJ... style), what breaks if missing.
- Include a Generating VAPID keys subsection with the exact bun x web-push generate-vapid-keys command.
- Include a Rotation checklist subsection: which env vars exist in Cloudflare Worker secrets, which in Supabase dashboard, which in Lovable account, plus the steps to roll each cleanly.
- Pair with the .env.example fix in OPS-002.
S — under ½ day
<repo-root>:n/aNo LICENSE, LICENSE.md, LICENCE, LICENCE.md, COPYING, or COPYING.md file anywhere in the tree. Glob _clients/SONI-remix-new/**/{LICENSE,LICENCE,COPYING}* returns zero. package.json contains private: true but no license field. The repository is private on GitHub (per audit-config note, source_repo URL is github.com/RekaWeb3Design/remix-of-so-ni-78.git, private repository), but the project depends on many open-source packages whose licenses (MIT, Apache-2.0, ISC, BSD) have their own attribution requirements, and any code shared with a contractor or auditor without an in-repo license statement leaves the license posture ambiguous.Even for a private, proprietary product, the in-repo license matters in two cases: (a) a contractor or contributor who looks at the code needs to know it is proprietary and how they may or may not use it -- the default of no license is the most restrictive but also the most ambiguous, (b) the project bundles many open-source dependencies whose licenses require attribution; without an in-repo NOTICE / LICENSE.third-party file, the team has no audit trail of dependency-license compliance.
For pre-launch B2C this is mostly latent risk; it materializes the first time the project is shared with anyone outside the founding team (contractor evaluating, partner integration, B2B prospect doing diligence, audit firm). At that point the absence of a clear license is a blocker. The dependency-attribution side also becomes a real issue at scale -- shipping a product whose 60+ npm dependencies have unattributed MIT/BSD/Apache licenses is a known risk surface that B2B procurement asks about.
The project has no license file. For a private project that is not immediately a problem, but as soon as a contractor, auditor, or partner sees the code, they need to know it is proprietary and how they can or can not use it. The fix is a one-line proprietary license statement -- under five minutes of work.
- Add LICENSE file: either a proprietary All rights reserved -- See company X for licensing terms notice (recommended for the current phase), or a known closed-source template.
- Set license to UNLICENSED (or SEE LICENSE IN LICENSE) in package.json.
- Optionally generate a third-party attribution file: bun pm ls --all plus a tool like license-checker to produce LICENSE.third-party.md.
- Add a Copyright header rule to CONTRIBUTING.md (DOC-.
- -- typically // Copyright (c) 2026 <company>. All rights reserved. on every new file.
S — under ½ day
<repo-root>:n/aLEG-001 (no Privacy Policy in app), LEG-002 (no Terms of Service), LEG-010 (no Imprint/Impressum) already flag the absence of these documents from the application. The documentation-side gap is distinct: even if these documents were drafted externally (e.g. by counsel), they would need to live somewhere versioned -- per locale, since the app supports six locales (de, en, es, fr, hu, it) -- so that material changes are diffable and the effective date is auditable. There is no docs/legal/ folder, no public/legal/, no privacy.md / terms.md / imprint.md anywhere in the tree. For a six-locale product, that means 18 missing localized policy artefacts (3 docs x 6 locales).User-facing legal documents are themselves an audit artefact under GDPR (Article 13/14 information to data subjects -- the privacy policy must be available and material changes must be timestamped) and under consumer-protection law (HU/DE Impressum, EU distance-selling Terms). Storing them only as in-platform CMS pages (or only as drafts in counsel drive, or only on the marketing site outside the repo) means the development team has no source-of-truth, no diff history, and no localization parity. For a regulated-data product (per DOM-001 / DOM-002 / DOM-003 health-adjacent special-category data), this gap compounds: the auditor wants to see version-controlled policies.
When a regulator or counsel asks what version of the privacy policy was effective when user X gave consent, the team currently has no answer beyond what is in production today. Once any of these documents exist (cross-ref LEG-001 / LEG-002 / LEG-010 fixes), versioning them in the repo per locale is the cheapest way to maintain an evidence trail. Doing this first in the repo and then publishing from the repo is also a way to avoid the six locale versions silently drifted failure mode.
Once the privacy policy, terms of service, and imprint are written (which the legal-compliance audit already flagged as missing), the next question is where they live. The recommendation is to version them in the repo per language, so any change is dated and reviewed -- not just typed into a CMS where it can be silently edited. This is the same pattern good companies use for product copy too.
- Once LEG-001 / LEG-002 / LEG-010 are addressed by counsel, store the drafts in docs/legal/<locale>/privacy.md, docs/legal/<locale>/terms.md, docs/legal/<locale>/imprint.md (or impressum.md for de/hu).
- Render them in-app from those files (or from a CMS that pulls from these as source).
- Each file carries a YAML front-matter: effective_date, version, language, last_reviewed_by.
- Adopt a rule: any change to a docs/legal/ file requires an entry in CHANGELOG.md (DOC-.
- under a Legal section.
- For consent records, store the effective_date alongside the user consent timestamp so future investigations can resolve which version did they accept.
M — 1–3 days
supabase/migrations/:n/aGrep across supabase/migrations/ for COMMENT ON (TABLE|COLUMN) returns 12 matches across only 6 of 89 migration files. The database has 42 application tables. No docs/schema.md or docs/data-model.md exists. The reader of types.ts learns this table exists with these columns but not this table is the daily user check-in that the morning coach reads and writes, or this table is one-row-per-user-per-day vs append-only event log.A new engineer cannot tell from the migrations alone (a) which table is the spine of the user model (probably profiles), (b) which tables are user-facing log streams (meals, workout_logs, habit_logs), (c) which tables are derived/cached state (bio_twin_active_state, body_progress_state) that get rebuilt from upstream events, (d) which tables are coach-internal scratch space (coach_memory_threads, coach_intake_threads, coach_facts, coaching_moments -- four overlapping coach-state tables whose distinctions are not documented), and (e) which tables are temporal series vs key-value cache. The relationships between cycle_logs and cycle_settings, between coach_messages and coach_conversations and coach_diaries, between bio_twin_avatar_bank and bio_twin_active_state -- all of these have to be reverse-engineered from server-side code.
Schema understanding is the single biggest onboarding-time sink in a database-heavy product. Without a domain-model doc, every new engineer has to spend 1-3 days mapping table purposes from migrations + server-side usage before they can safely change anything. Worse, the absence shows up directly in the data-integrity audit: DAT-006 (RESET_TABLES references three already-dropped tables) is exactly the kind of drift that lives undetected when no one has a single overview of which tables exist for what. For GDPR Article 30 (records of processing) and Article 9 special-category handling (per DOM-002 / DOM-003), a schema-purpose document is also a literal compliance artefact -- the regulator wants to see we process cycle_logs.flow_intensity for purpose X under lawful basis Y.
The database has 42 tables but nothing explains what each one is for, how they connect, or which ones depend on which. A future engineer would have to spend a couple of days reading code to figure out, for example, the difference between the four tables that store coach memory. A two-to-three-page schema overview document, plus comments on the trickier tables, removes most of this guesswork.
- Add COMMENT ON TABLE for each of the 42 tables in a single new migration -- one sentence each.
- Create docs/schema.md grouped by domain: User core, Daily logging, Coach surface, Body and biometrics, Bio Twin, Cycle, Rewards and streaks, Safety, Notifications. For each table: purpose, write-pattern (append-only / upsert / single-row-per-user / one-per-day), key joins, retention policy if any.
- Include a single ER-style diagram (Mermaid erDiagram) for the most-joined cluster (coach_* family).
- Cross-link from README.
M — 1–3 days
src/routes/api.coach-chat.ts, src/routes/api.voice-coach-chat.ts:1-60api.coach-chat.ts begins with a 2-line comment (Server route: streaming AI Coach chat with full user context. Uses a server route not createServerFn so we can return a raw SSE stream.). api.voice-coach-chat.ts has a similarly terse header. Neither file documents: the JSON shape of the request body, the SSE event types emitted, the auth model, the rate-limit posture (none -- already raised in SEC-005), or the error response contract. No OpenAPI / Swagger / JSON Schema for any endpoint exists in the repo. The same applies to the three public hooks endpoints (src/routes/api/public/hooks/bio-twin-snapshots.ts, body-plateau-detect.ts, src/routes/hooks/weekly-reports.ts) which are cron-callable HTTP endpoints whose auth contract is already partially broken (per SEC-002 / SEC-003) and whose request shape is undocumented.The coach-chat surface is the product main AI-driven user interaction and the most reverse-engineering-resistant part of the system (1100+ lines of orchestration in api.coach-chat.ts alone). A future engineer maintaining the SSE stream contract, a mobile client builder consuming it, or a security auditor evaluating prompt-injection paths (cross-ref AI-002) all need a written description of what goes in, what comes out, and what the failure modes are. Without it, integration changes are guess-and-check.
Undocumented streaming contracts are a high-friction surface for anyone building against them -- a future mobile app, a partner integration, a QA harness, or an automated test suite cannot be built without first reverse-engineering the wire format. For the public/hooks/* endpoints, the documentation gap also compounds the auth issue: SEC-002 / SEC-003 flag the cron-endpoint auth as broken; the absence of an endpoint-contract document means the fix has no specification to land into.
The two main AI endpoints -- text coach and voice coach -- and the scheduled-job endpoints have no written description of what they expect, what they return, or how they fail. Anyone building a mobile app, a test harness, or a partner integration would have to read the implementation. A short API document per endpoint, plus JSDoc on the entry function, covers this in a few hours per endpoint.
- Add a top-of-file JSDoc block per route handler (api.coach-chat.ts, api.voice-coach-chat.ts, all three hook routes) documenting: HTTP method(s), path, auth requirement, request JSON schema (or zod schema -- pairs with COD-007 / SEC-010 server-side validation work), response shape per event type (SSE event_name + payload), error event taxonomy, idempotency posture, and rate-limit.
- Create docs/api.md with a one-page contract for each endpoint.
- For the public cron hooks (bio-twin-snapshots, body-plateau-detect, weekly-reports), explicitly document the expected auth model (after SEC-002 / SEC-003 fixes) and the expected caller (pg_cron + URL).
- Consider generating an OpenAPI spec from zod schemas once SEC-010 / COD-007 add zod-based validation -- the schemas become the source of truth for both runtime and docs.
M — 1–3 days
src/:repo-wideGrep for @param|@returns|@throws|@example|@deprecated across src/: 3 total occurrences across only 2 files (src/lib/training-target.ts: 2 hits; src/lib/workout-scoring.ts: 1 hit). The codebase has approximately 86,000 lines of TS/TSX across 455 files and 102 server modules. Block-comment headers (/**) appear 367 times across 167 files -- positive signal for module-level documentation in islands (e.g. src/server/_shared/coach-brain.ts has a rich module header, src/lib/longevity-formula.ts has a thorough source-of-truth comment, src/lib/evidence-based-targets.ts has 31 block comments) -- but parameter-level / return-value documentation on exported functions is essentially absent. The Bio Twin family (bio-twin-bank-generator.ts, bio-twin-avatar.ts, bio-twin-snapshot.ts) and the coach pipeline (coach-context.ts, coach-quality-gate.ts, coach-log-pipeline.ts) carry helpful module headers but the individual exported functions inside them are not annotated.TypeScript types document the shape of inputs and outputs; JSDoc documents the meaning, the side effects, the invariants, and the failure modes. For a project where 102 server modules export hundreds of helpers that orchestrate AI calls, database mutations, and Storage uploads, the lack of meaning-level documentation is the difference between a 1-hour and a 1-day handover per module. The good news is that the existing module-header pattern (longevity-formula.ts, coach-brain.ts, bio-twin-bank-generator.ts) shows the team can write excellent docs when they choose to; the gap is consistency and per-function granularity on the exported surface.
Quantified: a future engineer changing any of the coach-pipeline helpers (coach-context.ts, coach-quality-gate.ts, coach-memory.ts, coach-log-pipeline.ts, safety-check.ts, medical-safety.ts, mental-health-risk.ts, shame-free-rule.ts, emergency-signals.ts) -- the safety-relevant core of the product -- has to read implementation rather than signatures. This is the slow-bleeding side of bus-factor: not someone leaves and nobody knows what the project does (DOC-001 / DOC-002 territory), but someone leaves and every individual function takes longer to safely modify.
The good news: where the project does have inline comments, they are often excellent -- the longevity-score formula and the coach orchestrator are well-documented. The gap is that this discipline is applied to maybe 20 percent of the codebase. The other 80 percent has TypeScript types but no description of what each function does, what it changes, or how it fails. A pragmatic policy (any exported function in src/server/_shared gets a 3-line JSDoc) closes this over a sprint or two.
- Adopt a JSDoc-on-exported-functions policy in CONTRIBUTING.md (cross-ref DOC-009): every function exported from src/server/_shared/, src/server/, and src/lib/ gets at minimum: one-sentence purpose, @param descriptions for non-obvious arguments, @returns describing semantic meaning (not just type), @throws / never throws -- returns null on failure note, and any side-effect note (DB writes, Storage writes, AI calls).
- Prioritise the safety-critical modules first: coach-quality-gate.ts, safety-check.ts, medical-safety.ts, mental-health-risk.ts, shame-free-rule.ts, emergency-signals.ts.
- Adopt the existing longevity-formula.ts pattern as the team documentation style guide -- it shows the right level of evidence-citation + change here AND mirror sites guidance.
- Enable an eslint-plugin-jsdoc rule for require-jsdoc on exports (warning, not error, while backfilling).
L — 1–2 weeks
<repo-root>:n/aNo .github/ directory of any kind. No CONTRIBUTING.md anywhere. No CODEOWNERS file. No PULL_REQUEST_TEMPLATE.md. No commit-message convention enforced (sample of recent commits from git log --oneline -20: Lovable update, Work in progress, Changes (six times), Reverted to commit 9dd1b93..., Javitottam a coach hivast (Hungarian: I fixed the coach call), Csavarolta az assistant nyitanyt (Hungarian: Tightened the assistant intro), Korlatoztam a coach chatet (Hungarian: I limited the coach chat), Vegtisztitott ures uzeneteket (Hungarian: Cleaned up empty messages)). Commit messages are a mix of English platform-generated and Hungarian developer-written, mostly imperative one-liners without a why. No semantic-commit or conventional-commit format is in use.For a single-developer project this is low-impact; the moment a second contributor (contractor, co-founder developer, audit follow-up engineer) appears, every PR becomes a re-explanation of conventions: which branch to base off, what naming style to use, how to write a commit, what review the PR needs. The mixed-language commit history also makes git blame and git log less useful for non-Hungarian-speaking future maintainers (or vice versa).
The cost is paid in onboarding friction and missed opportunities to enforce light-touch quality discipline. A PR template with a checklist (typecheck pass, lint pass, env vars unchanged or .env.example updated, schema change includes ADR, new vendor includes ADR) would catch several of the issues the audit found before they shipped (e.g. tables dropped without an ADR per DOC-005, env vars added without docs per DOC-003, dead shadcn primitives left in tree per COD-006).
There is no contributor guide. A new developer joining would not know which branch to work from, what conventions to follow, or what a good commit message looks like. Adding a one-page CONTRIBUTING.md plus a short PR template costs an afternoon and pays back every time someone new opens a pull request.
- Create CONTRIBUTING.md: branch strategy (trunk-based + feature branches, naming pattern), commit-message convention (recommend Conventional Commits: feat: / fix: / chore: / docs: / refactor:, optionally scoped), PR review expectations (self-review checklist, who can approve), local-quality checklist (bun run lint, bun run format, manual smoke), language policy (English commits + English code comments for shareable surface; Hungarian fine in private notes if any).
- Create .github/PULL_REQUEST_TEMPLATE.md with checkboxes: typecheck passes / lint passes / no new env vars without docs/env.md update / no new vendor without ADR / no new table without COMMENT ON / safety-rail modules touched? acceptance criteria documented.
- Create CODEOWNERS naming the operator as default reviewer (single name acceptable for sole-founder phase).
- Optionally add commitlint + husky for enforcement once team size is more than one.
S — under ½ day
<repo-root>:n/aThe repo has several Lovable-platform-specific characteristics that a future engineer (or migration team) will trip over without documentation: (a) wrangler.jsonc sets compatibility_flags: [nodejs_compat] -- evidence stack-profile section 3 -- but no doc explains which dependencies require it (the web-push library, Buffer usage in server modules) or what would break if removed, (b) supabase/config.toml pins project_id = oyajjhkigkffvudjgybp -- pinning the audit and any future contributor to a single live project, (c) two lockfiles co-exist (bun.lockb 374 KB + package-lock.json 393 KB) per stack-profile section 2 -- with no packageManager field in package.json and no doc explaining which one wins, (d) several integration files carry auto-generated by Lovable, do not modify headers (cross-ref DOC-008) but the relationship to the Lovable platform remix-sync mechanism is undocumented, (e) auth-attacher.ts header comment says it must be registered as a global functionMiddleware in src/start.ts -- but src/start.ts does not exist in the tree, per stack-profile section 11. No docs/platform-notes.md or docs/lovable.md captures any of this.When the team eventually wants to migrate off Lovable (or off Cloudflare Workers, or onto a different package manager), or when a contractor tries to spin up a parallel environment, every one of these idiosyncrasies will surface as a debugging session. The two-lockfiles gap is particularly nasty -- dependency-resolution drift between Bun and npm is a known source of works on my machine incidents.
Each undocumented gotcha is a 1-2 hour debugging session for the next engineer to encounter it. For a project that already has vendor lock-in concerns (AI-005, single-AI-provider; the Lovable hosting model implied across the integration files), surfacing these explicitly is the first step toward making the lock-in either a deliberate trade-off (documented in an ADR) or a fixable migration target.
The project has several quirks that come from being built on the Lovable platform: a special Worker flag, a hard-coded Supabase project, two competing package-manager lockfiles, and a missing src/start.ts file that the code comments expect to exist. None of this is documented. A short platform-notes document captures each one and either confirms it is intentional or flags it for cleanup.
- Create docs/platform-notes.md with one short section per gotcha: Why nodejs_compat (which deps need it -- web-push, Node Buffer usage in server modules -- and the consequence of removing it), Supabase project-id pinning (where to change for a new environment, link to supabase/config.toml), Lockfile situation (which one is authoritative for this project -- recommend deleting one and pinning packageManager in package.json), Lovable-generated files (cross-link to DOC-008), Missing src/start.ts (decide: should auth-attacher.ts be registered explicitly, or is the framework auto-discovering it? document the resolution).
- Adopt a rule: each new platform-specific decision adds a section here or an ADR.
S — under ½ day
<repo-root>:n/aNo CHANGELOG.md exists at any level of the tree. git tag -l returns an empty list -- no releases tagged. Service-worker version is hard-coded (SW_VERSION = 2026-05-07-skip-to-app per stack-profile and OPS-015) and is the only release-identifier-like string in the repo. The commit history (cf. DOC-009) is mostly one-line messages with no grouping or release-cut signal.For a B2C product with users on cached PWAs and a service worker that ships push notifications, the absence of any release-versioning is a triple gap: (a) the team has no way to say this user is on version X when triaging incidents, (b) push-notification update behavior is fully manual (OPS-015 already raised), (c) a customer or B2B prospect asking what changed in the last quarter has no document to point at. For privacy-policy and ToS versioning (already absent per LEG-001 / LEG-002), the lack of a changelog also means there is no audit trail of when material privacy-affecting changes shipped.
Mostly polish today, but compounding: when the product reaches enough scale that incident triage matters or B2B sales conversations start, the missing versioning becomes visible immediately and costs more to retrofit than to introduce.
There is no changelog and there are no version tags in git. Users on a PWA with a service worker have no version identifier; the team has no way to say this bug affects users on builds before X. A simple monthly CHANGELOG.md plus tagging each deploy with a date-based version covers this.
- Add CHANGELOG.md following Keep-a-Changelog format (Added / Changed / Fixed / Removed / Security / Deprecated sections per release).
- Start tagging deploys -- semantic version (0.1.0 etc.) or CalVer (2026.05.0).
- Include the deploy tag in the service-worker version string (replace the manual SW_VERSION = 2026-05-07-skip-to-app with a build-time injected commit-sha or tag, addressing OPS-015 at the same time).
- Surface the version in a hidden /version or /health endpoint payload (also addresses OPS-009).
S — under ½ day
src/integrations/supabase/client.ts, client.server.ts, auth-middleware.ts, auth-attacher.ts; src/integrations/lovable/index.ts; src/routeTree.gen.ts; src/integrations/supabase/types.ts:file headersPer stack-profile Section 9: Many integration files (client.ts, client.server.ts, auth-middleware.ts, auth-attacher.ts, lovable/index.ts) begin with This file is automatically generated. Do not edit it directly. or This file is auto-generated by Lovable. Do not modify it. -- indicating tool-managed scaffolding. Plus src/routeTree.gen.ts (25,742 bytes, regenerated by @tanstack/router-plugin) and src/integrations/supabase/types.ts (Supabase CLI output). No docs/generated-files.md exists explaining: (a) which generator owns which file, (b) how to regenerate after a schema change, (c) what to do if a generated file gets accidentally hand-edited and committed, (d) why these files are committed at all rather than gitignored and rebuilt.Generator-managed source files are a common source of merge conflicts and I edited it and now nothing works incidents. The do-not-edit headers are necessary but not sufficient -- a new engineer needs to know what tooling to invoke to regenerate them. For types.ts in particular, regeneration is a regular operation (every migration that adds a table needs it re-run) and the command (supabase gen types typescript --project-id oyajjhkigkffvudjgybp ...) is not documented anywhere in-repo.
Low impact day-to-day -- the system works as long as nobody hand-edits a generated file -- but the documentation gap shows up exactly when something breaks (schema change makes types.ts stale; route addition does not refresh routeTree.gen.ts). Fixing it pre-emptively is cheap; debugging a stale-generator incident under deploy pressure is not.
Several files in the project are generated automatically by tooling and should not be edited by hand. They say so in their headers. What is missing is the instruction sheet for what to run when they need to be regenerated -- for example, after adding a new database table. A short markdown file covers this in under an hour.
- Add docs/generated-files.md listing: (a) src/integrations/supabase/types.ts -- regenerate with supabase gen types typescript --project-id $VITE_SUPABASE_PROJECT_ID > src/integrations/supabase/types.ts after any migration, (b) src/routeTree.gen.ts -- regenerated by Vite via @tanstack/router-plugin on dev server start, do not edit, (c) Lovable-generated integration files (src/integrations/supabase/client.ts, client.server.ts, auth-middleware.ts, auth-attacher.ts, src/integrations/lovable/index.ts) -- regenerated by the Lovable platform on every remix sync, hand-edits will be overwritten, raise feature requests with Lovable for changes.
- Add a comment in package.json scripts pointing at this doc, or wire bun run gen:types to run the Supabase CLI.
S — under ½ day
<repo-root>:n/aNo docs/known-issues.md, no GAPS.md, no TODO.md, no STATUS.md. Inline TODO/FIXME/XXX/HACK markers across src/: only 2 total occurrences across 2 files (src/server/blueprint-initial.ts, src/hooks/useDashboardData.ts) -- so the team is not using inline TODOs as a substitute either. Yet the audit has uncovered approximately 95 findings across 8 dimensions, many of which are half-implemented feature / planned but absent / we know about this: dead shadcn primitives (COD-006), mock data on dashboard sparklines (COD-008), missing /health endpoint (OPS-009), no test script (OPS-014), no error tracking (OPS-005), no privacy policy (LEG-001), no DPIA (LEG-008), no AI request audit log (AI-006), etc. None of these are acknowledged anywhere in-repo as known gap, deliberately deferred.A project that documents its own gaps is dramatically easier to take over than one that does not. The audit findings will eventually be triaged into fix now, fix this quarter, accept and document. The third bucket needs a home; otherwise every successor team rediscovers the same gaps and reopens the same conversations. This is the lowest-stakes documentation finding in the set, but the highest-leverage maturity signal.
Mostly latent / cultural impact. The first material moment is when the audit feedback is acted on: do we fix this or accept it? Decisions to accept need to land somewhere durable. If they do not, they erode -- the next person assumes nobody knows, and re-raises the issue.
Mature projects keep a short list of we know about this and have deliberately not fixed it yet. SONI does not have one. As the audit findings get triaged, the ones that are deferred should land in a single visible document so they do not get re-litigated.
- Once the audit triage is done, create docs/known-gaps.md (or fold into README).
- For each accepted-but-deferred gap, capture: short description, audit-finding ID (e.g. COD-006 -- 36 unused shadcn primitives, accepting for now as part of design-system scaffold, will revisit in 2026 Q3 design refresh), date accepted, when it will be revisited, who owns the revisit.
- Adopt the rule: any audit finding marked can_defer or accepted lands here.
- Pair with CHANGELOG.md (DOC-.
- -- when a known gap is resolved, it moves to CHANGELOG.
S — under ½ day