← Portal
Tech audit · Legal & Compliance 2026-05-19

Legal & Compliance

10 findings
3
Kritikus
3
Magas
4
Közepes
0
Alacsony

Below are all 10 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.

02

Findings — Legal & Compliance

Kritikus Launch előtt M LEG-001 · legal-compliance
No Privacy Policy exists anywhere in the application (no file, no route, no rendered page)
Kód-hely
Repo-wide (no single file)
Evidence
Repo-wide globs for `privacy-policy*`, `privacy.*`, `*privacy*` (as a file or route name), `legal/*`, `gdpr*`, `impressum*` return no results. No `/privacy`, `/privacy-policy`, `/legal`, or `/impressum` route file exists under `src/routes/` (route inventory verified against stack-profile section 8). The 105 source files that match the word 'privacy' on a grep all use it as in-app feature copy (e.g. `auth.tsx:265-267` shows `auth.legal` localized as 'By continuing you agree to our Terms and Privacy Policy.' but the text is rendered as a plain <p> with no Link/<a> to any actual policy document; see also `settings.tsx:574-583` 'Privacy Shield' which is a copy block about photo retention, not a policy). All 6 locales (en, de, es, fr, hu, it) carry the same dangling sentence (`en.json:252`, `de.json:200`, `fr.json:200`, `it.json:200`, `es.json:200`, `hu.json:231`).
A probléma

GDPR Article 13 requires that, at the moment personal data is collected from the data subject, the controller provides identity and contact details of the controller, purposes and legal basis for processing, recipients/categories of recipients, intention to transfer to third countries, retention periods, and the user's rights (access, rectification, erasure, restriction, portability, objection, complaint to a supervisory authority). The app collects extensive personal data on signup (email, password, display_name, preferred_language) and then on use (biometrics, body_measurements, body photos, cycle_logs, coach conversations with mental-health-adjacent content, meal photos with potential face content) and gives the user no document explaining any of this. The localized sentence claims a 'Privacy Policy' exists, which makes the absence a representation issue on top of a compliance issue: the app affirmatively tells users a policy exists that does not exist.

Üzleti hatás

Cannot launch in the EU. A DPA (data protection authority) complaint or audit would find this on day one; fines under GDPR Article 83 reach up to 4% of global annual turnover or EUR 20 million, whichever is higher. For a B2C app handling biometric/health-adjacent data, this is the single most common reason for a launch-block by counsel review. Additionally, the false claim 'By continuing you agree to our Terms and Privacy Policy' shown to every user on signup is itself a consumer-protection issue (misleading commercial practice under EU Directive 2005/29/EC), independent of the GDPR exposure. App-store reviewers (Apple, Google) reject apps without a privacy policy URL: if this is ever submitted as a PWA-wrapper or native shell, the listing will be blocked.

Magyarázat

Your app currently has no privacy policy of any kind, but tells every new user 'By continuing you agree to our Terms and Privacy Policy' promising a document that does not exist. In the EU this single issue blocks launch: every regulator and every lawyer reviewing the product will stop here. You need a real privacy policy, linked from the signup screen, before going live.

Javaslat
  1. Engage a privacy lawyer (or use a vetted template generator like iubenda, Termly, or Cookiebot's policy module) to draft a GDPR-compliant privacy policy that names: (a) the legal-entity controller and their EU representative if applicable; (b) every category of personal data collected (auth, profile, biometric/body, cycle, coach conversations, photos, push tokens, language/region); (c) the legal basis per category (consent for special-category biometric data per Art. 9, contract for service delivery per Art. 6(1)(b), legitimate interest for security logs); (d) all subprocessors (Supabase, Cloudflare, Lovable, OpenAI, Google) and the data they receive; (e) international-transfer mechanism (SCCs) for each non-EU subprocessor; (f) retention periods (e.g. body photos auto-purge at 90 days per `settings.tsx:577-582`); (g) the user rights and how to exercise them (email contact plus in-app delete/export endpoints once those exist, see LEG-003); (h) cookie/local-storage usage.
  2. Create `src/routes/privacy.tsx` rendering the document (markdown-loaded, localized in all 6 supported languages).
  3. Replace the dangling text in `auth.tsx:265-267` with React Link to /privacy and Link to /terms tags around the relevant clauses, in every locale's `auth.legal` translation.
  4. Add a footer link on every page (or at minimum on /, /auth, /settings).
  5. Surface the privacy-policy URL in app-store listings and on any marketing site.
Becsült munka

M — 1–3 days

Kapcsolódó dimenziók
Cross-references LEG-002 (Terms of Service same gap), LEG-003 (subject rights referenced from policy), LEG-004 (subprocessor inventory must be listed in the policy), LEG-008 (domain-compliance flag for special-category biometric data). Overlaps with security finding SEC-009 (password policy) which the privacy policy should describe at a high level. Cross-refs SEC-001 for the wider 'GDPR posture' framing.
Kritikus Launch előtt M LEG-002 · legal-compliance
No Terms of Service / Terms of Use document exists; signup screen claims one exists
Kód-hely
Repo-wide (no single file)
Evidence
Repo-wide globs for `terms*`, `tos*`, `eula*`, `agreement*` return no files or routes. `src/routes/` has no /terms, /tos, /legal route (verified against stack-profile section 8 route inventory). The signup screen `src/routes/auth.tsx:265-267` renders <p>{t('auth.legal')}</p> where `auth.legal` is, e.g. in `en.json:252`, 'By continuing you agree to our Terms and Privacy Policy.' but the text is plain prose with no link target. The same sentence appears in all 6 locales (de, es, fr, hu, it, en).
A probléma

EU consumer law (Directive 2011/83/EU on consumer rights, Directive 93/13/EEC on unfair terms in consumer contracts, and national implementations) requires that, before a consumer is bound by a contract via electronic means, the key terms must be displayed in a clear, comprehensible manner and the consumer must give explicit consent to them. Showing the user a sentence that names 'Terms' without exposing the actual terms means the user cannot meaningfully consent and any clause the controller later tries to rely on (liability limitation, dispute resolution forum, subscription auto-renewal, content licensing for user-generated photos, AI-output disclaimers) is at risk of being unenforceable. The app also processes user-generated content (meal photos, body photos, coach conversations) that is fed into a third-party AI gateway (Lovable, OpenAI, Google) without a Terms document specifying the user's license grant for that processing, the controller has no contractual basis for the transfer.

Üzleti hatás

Cannot enforce any terms against users (no contract was formed). Any future dispute over abuse, payment, AI output liability, or content removal is fought without the protections a ToS would provide. Combined with LEG-001, this blocks EU launch and app-store submission. Specific exposure for this product: the coach has explicit safety-rail prompts around medical/mental-health risk (mental-health-risk.ts, medical-safety.ts, emergency-signals.ts per stack-profile section 6) without a ToS containing the standard 'this is not medical advice, not a substitute for professional care, in emergencies contact local emergency services' disclaimer, any harm a user attributes to coach output is litigated without that defense. (The product description in `__root.tsx:61` does include 'Not medical advice' in meta-description text, but a meta description is not legally operative.)

Magyarázat

Your app has no Terms of Service document, just a sentence on signup saying users 'agree to our Terms.' Legally, no agreement is formed when you do not show the user what they are agreeing to. This is a launch blocker, and for a product that gives AI-driven longevity coaching it is also a significant liability gap if a user ever claims harm from the coach's output.

Javaslat
  1. Draft a Terms of Service covering: (a) service description and limitations ('SO:NI is a wellness coach, not a medical/diagnostic service'); (b) eligibility (18+ recommended given the mental-health-adjacent coach surface; see LEG-008 children-data handoff); (c) account rules, prohibited uses, abuse policy; (d) AI-output disclaimer with explicit not-medical-advice language and emergency-services directive; (e) user content license grant covering the photos, meal data, coach messages being processed by AI subprocessors; (f) subscription/cancellation terms if/when monetisation lands; (g) liability cap, indemnity, dispute-resolution clause appropriate to the controller's home jurisdiction (likely HU/EU); (h) changes-to-terms procedure (e.g. 30-day notice via email plus in-app banner).
  2. Create `src/routes/terms.tsx` rendering the document, localized in all 6 supported languages.
  3. Convert the `auth.legal` sentence in all 6 locale files into a translation with two embedded link placeholders, and render via <Trans i18nKey='auth.legal' components={{ termsLink: <Link to='/terms' />, privacyLink: <Link to='/privacy' /> }} />.
  4. For signup specifically, consider a separate checkbox 'I have read and agree to the Terms and Privacy Policy' that must be ticked before the signup button enables, strongest evidence of consent.
  5. Add footer links on every page.
Becsült munka

M — 1–3 days

Kapcsolódó dimenziók
Cross-references LEG-001 (same fix vehicle, both documents drafted together), LEG-006 (consumer protection, pricing and cancellation clauses live in the ToS once billing is added).
Kritikus Launch előtt L LEG-003 · legal-compliance
No data-subject rights implementation: no account deletion, no data export, no consent withdrawal endpoint
Kód-hely
Repo-wide (no single file)
Evidence
Repo-wide grep for `auth.admin.deleteUser`, `deleteUser`, `account_deletion`, `delete-account`, `deleteAccount`, `data-export`, `exportData`, `download-my-data`, `gdpr-request`, `portability`, `subject-access` returns NO matches in any source or migration file. The settings page (`src/routes/settings.tsx:580-617`) does offer a 'Full reset' that clears daily data (meals, workouts, biometrics, streaks, badges, reports) but explicitly preserves 'onboarding, profile and preferences' (lines 599-602) the underlying user account, the auth.users row, the profiles row, and the coach conversation/diary history (per the table inventory in stack-profile section 4, including coach_diaries, coach_messages, coach_memory_threads, coach_intake_threads, bio_twin_snapshots, body_progress_state, cycle_logs, safety_events) all remain intact. There is also no UI affordance to withdraw consent for any single processing purpose (e.g. opt out of AI-coach memory while keeping nudges).
A probléma

GDPR Articles 15-22 grant every EU data subject the following rights, which the controller must be able to honour within one month (Article 12(3)): right of access (15), rectification (16), erasure / right to be forgotten (17), restriction of processing (18), notification (19), data portability (20), objection (21), and the right not to be subject to automated decision-making (22). The app implements none of them as a self-service flow. Practically: (a) a user cannot delete their account at all from inside the app; (b) a user cannot download their data in a machine-readable form; (c) a user cannot withdraw consent for AI-coach memory or for the coach to read their cycle/safety data, all of which are processed under what should be revocable consent for Article 9 special-category processing. Without these endpoints, the controller cannot honour an Article 17 erasure request without a manual, human-touched workflow and given the 42 tables that reference user_id, manual deletion is error-prone and likely to leave orphaned data.

Üzleti hatás

Cannot lawfully launch in the EU. Receiving even one user data-deletion request after launch forces the controller into a manual SQL-and-Storage-purge exercise across 42 tables and 7 Storage buckets per user, with no audit trail; missing any row is itself a GDPR violation. The right of access (Article 15) likewise: if a user emails 'please send me everything you hold on me,' the controller has 30 days to comply. With biometric plus cycle plus mental-health-adjacent coach-conversation data on file, that response would be a complex JSON export; a manual extract is not a sustainable answer at any user count. App-store submissions (Apple in particular, since iOS 14.5) explicitly require an in-app 'Delete Account' button: the app would be rejected on first review.

Magyarázat

EU privacy law gives every user three rights you have to honour: delete my account, download my data, and stop using my data for a specific purpose. Your app currently supports none of them. The 'Full reset' button in Settings clears daily entries but keeps the account, the coach memory and the body history, so it is not the GDPR 'delete my account' flow. Apple also rejects apps without an in-app delete-account button. Both legally and for app-store approval, this needs to be built before launch.

Javaslat
  1. Add an in-app 'Delete account' button in `src/routes/settings.tsx` (separate from 'Full reset', clearly labelled as irreversible). Implement a server function deleteUserAccount(userId) that: (a) deletes all rows referencing the user across the 42 tables in a single transaction (use supabase.auth.admin.deleteUser plus explicit cascades, or rely on ON DELETE CASCADE foreign keys if the migration history has them, verify against the data-integrity audit findings); (b) deletes all Storage objects under the user's folder in each of the 7 buckets; (c) finally deletes the auth.users row.
  2. Add a 'Download my data' button that produces a JSON ZIP archive of all rows where user_id = auth.uid() plus signed URLs to their Storage objects, valid for 7 days. Implement as a server function that streams the assembled archive.
  3. Add granular consent toggles in Settings for: AI coach memory retention; processing of cycle data; processing of body photos. Each toggle should both stop future processing AND offer a one-click 'delete past data for this category.'.
  4. For Article 22 (no automated decision-making with significant effects): document in the privacy policy that AI coach output is advisory only, no automated decision with legal/significant effect is made, and the user can always switch to non-AI mode.
  5. Log all subject-rights actions in a gdpr_actions audit table (timestamp, user_id, action, completed_at) for the controller's Article 30 records.
  6. Establish a dpo@<domain> or privacy@<domain> email mailbox referenced from the privacy policy as the escalation path for rights requests the in-app flow does not cover.
Becsült munka

L — 1–2 weeks

Kapcsolódó dimenziók
Cross-references LEG-001 (privacy policy must describe these rights and how to exercise them). Overlaps with data integrity (dimension 3, orphan-data risk across 42 tables during deletion) and with security (SEC-005, rate-limit the export endpoint to prevent abuse).
Magas Launch előtt M LEG-004 · legal-compliance
Subprocessor inventory not maintained: Lovable AI Gateway, OpenAI, Google (Gemini), Supabase, Cloudflare process personal data with no DPA-trail evidence
Kód-hely
Repo-wide (no single file)
Evidence
From stack-profile section 6, the app sends user content (coach messages, voice-coach audio, body photos, meal photos, biometry photos) to the Lovable AI Gateway at https://ai.gateway.lovable.dev/v1/chat/completions. The model strings called are `openai/gpt-5` and `google/gemini-3-pro-image-preview` implying onward processing by OpenAI and Google. The full subprocessor chain that processes personal data (inferred from stack-profile and code): (1) Supabase (Postgres + Auth + Storage, EU region not asserted anywhere in `supabase/config.toml`); (2) Cloudflare (Workers runtime, edge cache, R2: the og:image in `__root.tsx:68-69` is hosted on pub-bb2e103a32db4e198524a2e9ed8f35b4.r2.dev); (3) Lovable (AI gateway broker plus the cloud-auth OAuth bridge); (4) OpenAI (model inference); (5) Google (Gemini image model inference). No privacy policy exists (LEG-001), so no subprocessor list is published. No DPA-presence evidence is in-repo (DPAs are signed external to source code, but a Records-of-Processing register that names them is required under Art. 30 and is not present either).
A probléma

GDPR Article 28

(1) requires the controller to use only processors providing 'sufficient guarantees' and to have a written contract (DPA) with each. Article 28(2)-

(4) requires the controller to authorise sub-processors and disclose changes. Article 30 requires a Record of Processing Activities that lists each processor, the categories of personal data processed, and the safeguards in place. For a single-developer or small-team product, these obligations are commonly met by: (a) signing the standard DPA each vendor offers (Supabase, Cloudflare, OpenAI, Google all publish DPAs; Lovable's status is unknown and should be verified); (b) publishing the subprocessor list inside the privacy policy. Neither has visible evidence. The OpenAI and Google paths are particularly material because the data flowing through is special-category (biometric photos, cycle data, mental-health-adjacent coach text) and the providers are US-based, requiring Standard Contractual Clauses for the international transfer (Article 46). The og:image hosted on a Cloudflare R2 public URL (`__root.tsx:68`) also indicates Cloudflare R2 is in use for at least static assets, this is another subprocessor to enumerate.

Üzleti hatás

Two distinct exposures. First, contractual: without DPAs in place, every API call to OpenAI/Google/Lovable that ships personal data is an unlawful disclosure to a non-authorised third party, each user could in theory claim Article 82 compensation. Second, transfer-mechanism: without SCCs for the US-bound providers, the transfers are unlawful under Article 44 (post-Schrems II). Both are findable in any GDPR audit, both can be cured before launch by signing the vendors' standard DPAs and listing them in the privacy policy. The cost of the cure is low (sign 4-5 DPAs, none of which are negotiated for a product this size, vendors offer them as-is), but it must happen before launch.

Magyarázat

Every time a user sends a message or a photo to the coach, that data passes through Lovable, OpenAI, and Google. EU law requires you to have a signed 'data processing agreement' with each of these companies and to list them in your privacy policy. None of that paperwork is visible in the project right now. The good news: every one of these vendors offers a standard agreement you can sign in a few minutes; the bad news: you cannot launch in the EU until that paperwork is on file.

Javaslat
  1. Sign the Data Processing Agreement offered by each subprocessor: Supabase (https://supabase.com/legal/dpa), Cloudflare (https://www.cloudflare.com/cloudflare-customer-dpa/), OpenAI (https://openai.com/policies/data-processing-addendum), Google Cloud (https://cloud.google.com/terms/data-processing-addendum). For Lovable specifically, request a DPA from Lovable support, confirm whether they pass through to OpenAI/Google as sub-processors with their own DPA chain.
  2. Confirm each vendor's EU SCCs are in place for international transfers (the modular SCCs published by the European Commission in 2021, all four major vendors include them by default in their DPA).
  3. Create a Record of Processing Activities document (a simple spreadsheet is enough at this stage; vendors like iubenda offer templates) listing: data category, purpose, legal basis, retention, subprocessor, transfer mechanism.
  4. Publish the subprocessor list inside the privacy policy (LEG-.
  5. and commit to giving users 30 days' notice before adding a new subprocessor.
  6. Configure the Supabase project's region to an EU region if it is not already (the project id `oyajjhkigkffvudjgybp` reveals nothing about region; verify in the Supabase dashboard).
  7. For the Cloudflare Worker, confirm the deployment region restrictions if any.
Becsült munka

M — 1–3 days

Kapcsolódó dimenziók
Cross-references LEG-001 (subprocessor list belongs in the privacy policy), LEG-005 (international-transfer mechanism for each subprocessor). Overlaps with AI integration (dimension 9, provider lock-in audit will also surface these vendors).
Magas Launch előtt M LEG-005 · legal-compliance
International data transfers to US-based subprocessors (OpenAI, Google, Cloudflare) not addressed: no transfer mechanism named
Kód-hely
Repo-wide (no single file)
Evidence
Inferred from stack-profile section 6 (Lovable AI Gateway proxying `openai/gpt-5` and `google/gemini-3-pro-image-preview`) and section 3 (Cloudflare Workers runtime, Cloudflare R2 in use per `__root.tsx:68`). No privacy policy exists (LEG-001), so no Article 46 transfer-mechanism disclosure is published. No data-residency configuration is asserted in `supabase/config.toml`, `wrangler.jsonc`, or any in-repo configuration file. The Supabase project id `oyajjhkigkffvudjgybp` does not encode region; whether the Supabase project itself is EU-hosted or US-hosted cannot be determined from the repo alone.
A probléma

Post-Schrems II (CJEU C-311/18, July 2020) and after the invalidation of Privacy Shield, transfers of EU personal data to the US require either (a) reliance on the EU-US Data Privacy Framework (the adequacy decision adopted in July 2023, valid for vendors that are DPF-certified), or (b) signed Standard Contractual Clauses plus a documented Transfer Impact Assessment, or (c) one of the narrow derogations in Article 49. The app sends biometric photos (special category, Article 9), coach conversations (potentially mental-health-adjacent), and cycle data to OpenAI and Google via the Lovable gateway, all US-headquartered companies. For each vendor the controller must determine: (i) is the vendor DPF-certified, and is the data category covered? (ii) if not DPF-only, are SCCs in place via the vendor DPA? (iii) has the controller performed a Transfer Impact Assessment? None of this is documented in the repository.

Üzleti hatás

An EU data-protection authority that learns of US transfers of special-category data without a documented transfer mechanism can order suspension of the processing within days. For a coach product whose core feature IS the AI conversation, suspension of the AI subprocessor is an effective service shutdown. The fix is paperwork-only (verify DPF certification status of each vendor as of audit date, sign SCCs as a fallback, document the TIA) and can be completed in 1-2 weeks. The cost of not doing it is binary: a complaint to NAIH (Hungarian DPA), CNIL (French DPA), or any other EU DPA can result in an enforced processing-suspension order.

Magyarázat

Sending European users' data to American companies (OpenAI, Google) requires a specific legal mechanism, either a current EU adequacy decision for that company, or signed contracts called Standard Contractual Clauses. You need to verify, for each vendor, which mechanism applies and document it. This is a paperwork task, not a code change, but it is mandatory before launching to EU users.

Javaslat
  1. For each US-headquartered subprocessor (OpenAI, Google, Cloudflare, Lovable if US-based), check the EU-US Data Privacy Framework participants list (https://www.dataprivacyframework.gov/list) for current DPF certification and the specific data categories covered.
  2. For any vendor not DPF-certified for the relevant data category, ensure the signed DPA includes the European Commission's 2021 modular Standard Contractual Clauses (Module 2: controller-to-processor). All four vendors include them as standard.
  3. Perform a one-page Transfer Impact Assessment per vendor documenting: data categories, recipient country, surveillance-law exposure, supplementary measures (encryption in transit, encryption at rest, minimisation of data sent). For an AI gateway call, document specifically that the data sent is the prompt plus image (not the full DB), processed for inference only, and not retained by the vendor per their DPA.
  4. Publish the transfer mechanism in the privacy policy (LEG-001), for each subprocessor: 'Transfers occur under the EU-US DPF / Standard Contractual Clauses (2021).'.
  5. Verify the Supabase project region: if it is not already EU (e.g. eu-central-1, eu-west-1), migrate or document the controller's risk acceptance.
Becsült munka

M — 1–3 days

Kapcsolódó dimenziók
Cross-references LEG-001 (transfer mechanism must be in the privacy policy) and LEG-004 (DPA inventory).
Magas Launch előtt M LEG-008 · legal-compliance
DPIA required and not evidenced: large-scale special-category processing (biometrics, body photos, cycle, mental-health-adjacent coach data) plus AI profiling
Kód-hely
Repo-wide (no single file)
Evidence
From stack-profile section 4, the live database contains tables that hold special-category data under GDPR Article 9: biometrics, body_measurements, body_biometry_scans, bio_twin_snapshots, body_progress_state, cognitive_scores, cycle_logs, cycle_settings, physical_assessments, safety_events, coach_diaries, coach_messages, coach_memory_threads. Storage buckets body-biometry-photos, bio-twin-photos, body-progress-photos (per stack-profile section 4) hold biometric photos. From stack-profile section 6, AI coach calls produce profiling-style output (the coach's mental model of the user is composed from blueprint, body-trend, longevity-bridge, north-star, decision-style, glycemic-load contexts via 100+ server modules, this is systematic, extensive profiling under Article 22). Safety-rail prompts (mental-health-risk.ts, medical-safety.ts, emergency-signals.ts, safety-check.ts) acknowledge mental-health-adjacent content flows through the coach. No DPIA document exists in `_clients/SONI-remix-new/` (verified: no `dpia*`, `data-protection-impact*`, `privacy-impact*`, `risk-assessment*` files).
A probléma

GDPR Article 35 requires a Data Protection Impact Assessment when processing is 'likely to result in a high risk to the rights and freedoms of natural persons.' The EDPB and most national DPAs (NAIH, CNIL, ICO, Garante) publish lists of processing types that mandate a DPIA. The app triggers at least three of those criteria:

(1) Article 35(3)(b), large-scale processing of special-category data (biometrics, sex/cycle data which is health data under Article 9);

(2) Article 35(3)(a), systematic and extensive evaluation of personal aspects based on automated processing, which is what an AI longevity coach with persistent memory does;

(3) per the CNIL's published list (https://www.cnil.fr/fr/liste-traitements-AIPD-obligatoire), processing of health data is on the mandatory-DPIA list. Without a documented DPIA, the controller has not formally identified the risks, the mitigations, and the residual risk acceptance, and cannot demonstrate Article 35 compliance to a regulator. The DPIA is also the document that decides whether prior consultation with the supervisory authority under Article 36 is needed (it is, if residual risk remains high after mitigations).

Üzleti hatás

Launching without a DPIA on a special-category plus AI-profiling product is itself a GDPR violation (fines up to 2% of global turnover under Article 83(4)(a)). For a health-adjacent product the DPIA is also the controller's primary defence: it documents the risk model, the mitigations chosen (encryption, RLS, photo auto-purge at 90 days per `settings.tsx:577-582`, AI-output safety rails), and the conscious risk acceptance. Without it, in any post-launch incident (data breach, harm-from-coach-output, ATO with cycle-data leak), the controller has no Article 35 documentation to show that risks were considered and mitigated proportionally. The DPIA is also the natural place to document the AI-output limitations and the not-medical-advice posture, material that overlaps with the ToS (LEG-002) and with the eventual AI Act high-risk classification analysis (domain-compliance dimension).

Magyarázat

EU law requires a formal 'risk assessment' document before launching a product that processes health-adjacent data and uses AI to profile users, both of which your app does. The assessment lists what could go wrong, what you have done to prevent it, and what risk remains. It takes 1-2 days to draft from a template and protects you significantly if anything ever goes wrong post-launch.

Javaslat
  1. Use the CNIL PIA tool (free, https://www.cnil.fr/en/open-source-pia-software-helps-carry-out-data-protection-impact-assesment) or the ICO DPIA template to draft a DPIA covering: each data category (auth, profile, biometric photos, body measurements, cycle data, coach conversations, safety events), each processing purpose, each subprocessor, the legal basis (Article 9(2)(a) explicit consent for biometric and cycle data; Article 6(1)(b) contract for service delivery), the risks (re-identification, ATO with special-category exposure, AI-output harm, cross-border-transfer surveillance risk), the mitigations (encryption, RLS, auto-purge, safety rails, regional Supabase hosting), and the residual risk with the controller's sign-off.
  2. For the AI coach output specifically, document: model used, intended purpose (advisory only), tested failure modes (medical mis-recommendation, suicide-risk mishandling, false positive on safety events), human-in-the-loop expectation (none, explicit), risk-mitigation through safety-rail prompts.
  3. Review the DPIA quarterly and after any material change (new subprocessor, new processing purpose, new model).
  4. If the DPIA concludes residual risk is high (e.g. for the mental-health-adjacent coach surface), consult the supervisory authority (NAIH in HU) under Article 36 before launching that processing.
  5. Keep the DPIA internal but reference its existence and date of last review in the privacy policy (LEG-001).
Becsült munka

M — 1–3 days

Kapcsolódó dimenziók
Cross-references LEG-001 (DPIA existence referenced in policy), LEG-002 (ToS bears the operative not-medical-advice disclaimer that the DPIA assumes is in place), LEG-009 (Records of Processing, the two documents share most of their inventory). Major handoff to domain-compliance (dimension 10) for the Article 9 / EU AI Act analysis.
Közepes Launch előtt S LEG-009 · legal-compliance
Records of Processing Activities (Article 30) not evidenced: required for special-category health data regardless of company size
Kód-hely
Repo-wide (no single file)
Evidence
GDPR Article 30(5) waives the Records-of-Processing requirement for organisations with fewer than 250 employees ONLY if the processing is occasional AND does not include special categories of data under Article 9 (or criminal-conviction data under Article 10). The app processes biometric photos, cycle/health data, and mental-health-adjacent coach conversations on a regular, not occasional, basis (stack-profile section 4 confirms 42 application tables several of which are continuously written). Therefore the Article 30 exemption does not apply and a Record of Processing is mandatory regardless of organisation size. No such record exists in the repository (verified: no `processing-record*`, `ropa*`, `article-30*`, `records-of-processing*` file). The repository correctly does not commit a controller's internal records, but the absence of any reference, template, or process documentation indicates the record is likely not maintained elsewhere either.
A probléma

The Record of Processing Activities is the controller's internal inventory: for each processing activity, the purpose, the categories of data subjects and personal data, the categories of recipients (including subprocessors), the international-transfer mechanism, the retention period, and the technical/organisational security measures. It is the document a DPA asks for first in any audit. It overlaps significantly with the DPIA (LEG-008) and with the subprocessor inventory (LEG-004), the same source data, different presentations. Without it, the controller cannot answer basic regulator questions ('Show us your processing activities') and cannot internally check that all subprocessors have signed DPAs (LEG-004) or that all special-category processing has a DPIA (LEG-008).

Üzleti hatás

An Article 30 finding is usually not, by itself, a launch-blocker in the way the privacy policy gap is, but if a regulator opens an investigation for any other reason, the absence of a Record of Processing is an immediate aggravating factor in the fine calculation under Article 83(2). Operationally, the Record is also the source-of-truth document new team members read to understand 'what data does this system actually hold and why', without it, every onboarding takes longer and the controller's risk posture drifts over time.

Magyarázat

EU law requires a one-page internal inventory called 'Records of Processing', basically a list of what data you collect and why. For most small companies this is optional, but because your app processes health-related data, the exemption does not apply to you. It is a 1-day task using any template (the UK and French regulators publish free ones).

Javaslat
  1. Use the ICO controller template (https://ico.org.uk/for-organisations/uk-gdpr-guidance-and-resources/accountability-and-governance/documentation/) or the CNIL template as a starting point.
  2. Populate one row per processing activity: 'User account management', 'Biometric photo analysis for body composition', 'Coach conversation AI inference', 'Cycle tracking', 'Push notifications', 'Weekly report generation'. For each row record: legal basis (Article 6 plus Article 9 sub-paragraph if applicable), data categories, retention, subprocessors, transfer mechanism, security measures (encryption, RLS, auto-purge).
  3. Store the document outside the repository in the controller's compliance folder; reference its existence in the privacy policy.
  4. Review and update quarterly, and on every new feature that touches personal data.
  5. The Record, the DPIA (LEG-008), and the subprocessor list (LEG-.
  6. should all reconcile, keeping them in one shared workbook is easier than maintaining three documents that drift apart.
Becsült munka

S — under ½ day

Kapcsolódó dimenziók
Cross-references LEG-004 (subprocessor inventory is one column of the Record), LEG-008 (DPIA shares the same data inventory).
Közepes Első sprint S LEG-006 · legal-compliance
No cookie/storage consent banner: currently low-risk because no analytics, but the gap will become a violation when tracking is added
Kód-hely
Repo-wide (no single file)
Evidence
No cookie-consent library is installed (repo-wide grep for `cookieconsent`, `osano`, `onetrust`, `cookieyes`, `klaro`, `iubenda`, `cookiebot` returns 0 matches in `package.json` and `src/`). No analytics, tag manager, marketing pixel, or session-replay tool is installed either (repo-wide grep for `gtag`, `googletag`, `google-analytics`, `googletagmanager`, `facebook`, `fbq`, `posthog`, `mixpanel`, `segment`, `hotjar`, `clarity`, `meta-pixel`, `fathom`, `plausible`, `amplitude`, `matomo`, `piwik` returns no real hits, the single 'amplitude' hit in fr.json is body-training copy, and the 'analytics' hit in coach/CoachKnockCard.tsx:53 is a Hungarian inline comment not actual code). The browser-side storage currently in use: (a) localStorage for the Supabase auth session via `src/integrations/supabase/client.ts:22-27` (strictly necessary for the login functionality); (b) localStorage for the i18n language preference (`auth.tsx:33`, `settings.tsx:302`); (c) localStorage for the country auto-suggestion flag (`settings.tsx:146-150`); (d) sessionStorage for the Lovable preview token (`__root.tsx:92`); (e) a 'sidebar_state' cookie set by `src/components/ui/sidebar.tsx:21-22, 85-86` (UI-state, arguably strictly necessary). None of these is a tracking technology under the ePrivacy Directive, they all fall under the 'strictly necessary' exemption (Recital 66 / Art. 5(3) carve-out).
A probléma

Today the app does not place any cookie or storage that requires consent under the ePrivacy Directive Article 5(3): the localStorage uses are either authentication (exempt) or user preference (exempt). The 'sidebar_state' cookie is UI-state, also exempt. So as of audit date, the absence of a consent banner is technically compliant. However: (a) the privacy policy gap (LEG-001) means the controller is still required by GDPR Article 13 to disclose all uses of cookies/storage, even strictly-necessary ones, in the policy, which currently does not exist; (b) the moment any analytics, A/B test framework, marketing pixel, or session-replay tool is added (very common in early-launch optimisation), the absence of a consent mechanism becomes an immediate violation; (c) the Lovable platform itself may inject preview-mode telemetry or analytics into the deployed bundle that is not visible in this repo's source, this should be verified with Lovable. The DPC, CNIL, and Garante (Italian DPA) have all issued fines for non-strictly-necessary cookies fired pre-consent in the past 24 months.

Üzleti hatás

Today: no fine exposure for the consent-banner gap specifically (the absence of trackers makes it moot). Forward-looking: the first PR that adds Plausible, PostHog, GA4, Sentry-with-session-replay, Hotjar, or any similar tool will silently put the app out of compliance. Without a consent framework already in place, that PR will not include a consent gate, the team will have to retrofit one under pressure. A consent banner added late is also a UX-regression event (drops trial-signup conversion 5-15 percentage points typically), better to design it in from day one. For Lovable platform telemetry: if Lovable injects anything analytics-like into production builds (not just preview builds), that is currently uncovered.

Magyarázat

Right now your app does not use any cookies that require asking the user, so technically you do not need a 'Accept Cookies' banner today. But the moment someone adds any analytics tool (Google Analytics, Plausible, error monitoring with session replay, etc.) you immediately need one. It is much easier to put a simple consent mechanism in place now while the surface is small than to retrofit it later. Worth a 1-day investment.

Javaslat
  1. Confirm with Lovable whether the production build injects any first-party analytics or telemetry that is not visible in this repo's source; if it does, classify each one as strictly-necessary or not.
  2. Adopt a lightweight consent framework now, while the surface is empty. Options: (a) Klaro (open source, ~10 KB, EU-friendly), (b) Cookiebot/iubenda (managed, paid), (c) build a custom 3-button banner (Accept all / Reject non-essential / Settings) wired to a `consent` localStorage key consumed by any future analytics initialiser.
  3. Document the storage inventory inside the privacy policy: sb-<projectid>-auth-token (localStorage, strictly necessary), i18nextLng (localStorage, preference), country_autosuggested:<userid> (localStorage, preference), sidebar_state (cookie, UI-state), __lovable_token (sessionStorage, platform-preview).
  4. Adopt a convention: any third-party SDK added to the app (analytics, A/B, marketing) must be initialised inside an if (consent.analytics) gate, gated on the consent state, NEVER eagerly loaded on app boot.
Becsült munka

S — under ½ day

Kapcsolódó dimenziók
Cross-references LEG-001 (storage inventory belongs in the privacy policy). Forward-looking dependency: any future analytics rollout flips this to a critical finding.
Közepes Első sprint L LEG-007 · legal-compliance
EU Accessibility Act (WCAG 2.1 AA) gaps: clickable divs, alt-empty content images, no focus-visible discipline
Kód-hely
_clients/SONI-remix-new/src:n/a
Evidence
Heuristic sampling across `src/`: (a) `div ... onClick` pattern appears 30 times across 23 files (e.g. `src/components/biotwin/TwinTimeline.tsx`, `src/components/CoachChatSheet.tsx:2`, `src/components/CoachPage.tsx:2`, `src/routes/scan.tsx:1`, `src/components/intelligence/IntelCollapsibleSection.tsx:1`), these are not focusable, not keyboard-actionable, and not announced as interactive to screen readers without explicit role, tabIndex, and onKeyDown handling; (b) 34 <img tags across 23 files; sampled cases include `src/routes/academy.tsx:123-129, 179-186` where the academy lesson 'today's pick' thumbnail and topic thumbnails both have alt='' (treats meaningful content images as decorative, wrong: a screen-reader user gets no idea what the lesson is until they read the title); `src/components/CoachPage.tsx:1917` alt='' on the pending-image preview chip in chat (decorative is acceptable here); `src/components/coach/CoachAvatar.tsx:21-28` has alt={persona === 'maya' ? 'Maya' : 'Ryan'}, good. The single style entry `src/styles.css` (189 lines per stack-profile section 8) was not exhaustively read here but the Tailwind 4 default reset removes focus rings by default unless `focus-visible:` utilities are added. No `prefers-reduced-motion` opt-out is wired to the heavy framer-motion animations. Header (`src/routes/auth.tsx:101-107`) does have aria-label='Back' on the Link, that level of discipline is present in places but not enforced everywhere.
A probléma

The European Accessibility Act (Directive 2019/882) became enforceable on 28 June 2025. It applies to e-commerce, banking, transport ticketing, e-books, and 'consumer-facing services' provided in the EU market, a longevity-coach B2C app likely qualifies as a consumer service. The reference standard is EN 301 549, which incorporates WCAG 2.1 Level AA. Concrete gaps in this codebase that an audit would surface: (a) clickable <div> elements without role='button', tabIndex={0}, and a matching onKeyDown for Enter/Space, fails 2.1.1 Keyboard, 4.1.2 Name-Role-Value; (b) content images with alt='', fails 1.1.1 Non-text Content for the academy thumbnails specifically (decorative-only intent should be re-evaluated per image); (c) absence of a `prefers-reduced-motion` accommodation around framer-motion animations, fails 2.3.3 Animation from Interactions (AAA, not strictly AA-required but commonly bundled into compliance scopes); (d) no published accessibility statement, required by the EAA in itself, separate from the technical conformance. Note: this finding is heuristic, a full WCAG conformance audit is a multi-day manual project per page and is out of scope for static repo inspection.

Üzleti hatás

Since 28 June 2025, the EAA is enforceable across the EU; member states are starting to designate enforcement bodies and reporting routes. Penalties vary by member state but range from low-five-figure fines to product withdrawal orders. For a longevity-coach app, the user demographic likely includes age-50+ users who are more affected by accessibility shortcomings (lower vision acuity, reduced fine motor control, increased screen-reader use). Beyond compliance: a non-accessible app silently loses 15-20% of the addressable market (the share of EU adults with a recognised disability or significant access need). The fix scope here is moderate, converting clickable divs to buttons, fixing alt text, adding focus-visible utilities, measured in days, not weeks.

Magyarázat

The EU Accessibility Act became enforceable in June 2025 and applies to consumer-facing apps like yours. There are real but fixable gaps in the current build: some buttons are not keyboard-usable, some content photos do not describe themselves to screen-reader users, and the animation-heavy interface has no 'reduce motion' option. None of this is blocking on its own, but it should be fixed in the first few sprints and an accessibility statement should be published.

Javaslat
  1. Run an automated baseline (axe-core CLI, Lighthouse Accessibility, or @axe-core/playwright) to enumerate the actual WCAG 2.1 AA gaps and prioritise.
  2. Replace clickable divs with <button> (or <Link>) elements throughout, the 23-file list above is the starting hit-list. Where a <div> must stay, add role='button', tabIndex={0}, and onKeyDown handling Enter/Space.
  3. Audit every alt='' instance: if the image conveys content (academy thumbnails, biotwin avatars, body photos), provide descriptive alt text; if it is truly decorative (next-to-text icon), keep alt='' and ensure the adjacent text is the screen-reader source.
  4. In `styles.css`, ensure a high-contrast focus-visible:outline rule applies to all interactive elements.
  5. Wrap heavy framer-motion animations in a useReducedMotion() check (the library exports it) and skip-or-shorten when the user has prefers-reduced-motion: reduce.
  6. Audit colour contrast: the warm cream/hazelnut palette (var(--espresso) on var(--cream)) likely passes, but the muted-text (text-muted-foreground at 11px/10px in many places, see settings.tsx:.
  7. should be verified at 4.5:1 minimum contrast.
  8. Publish an accessibility statement at /accessibility (linked from the footer), the EAA requires a public statement of conformance, gaps, and the feedback mechanism for users to report issues.
  9. Add accessibility checks to CI (axe-core plus Playwright).
Becsült munka

L — 1–2 weeks

Kapcsolódó dimenziók
Cross-references LEG-001 (accessibility statement is a separate published document, like the privacy policy). Overlaps with code quality (dimension 7), clickable-div pattern is also a maintainability smell.
Közepes Első sprint S LEG-010 · legal-compliance
No Imprint / Impressum block on the site: likely required under HU and DE consumer-information rules
Kód-hely
Repo-wide (no single file)
Evidence
No imprint, impressum, or 'company information' page exists in the codebase (verified: globs for `impressum*`, `imprint*`, `about*`, `company*`, `legal/contact*` return no results; routes `src/routes/` enumerated in stack-profile section 8 contain no such page). No footer component containing legal-entity info exists (verified: globs for `Footer*` under `src/components/` return no matches). The supported app languages (de, hu, it, fr, es, en) include both Germany and Hungary, both of which mandate publication of the service provider's identity and contact details on every commercial website.
A probléma

The EU E-Commerce Directive 2000/31/EC Article 5 (transposed into national law as Telemediengesetz Section 5 in Germany, Ekertv. Section 4 in Hungary, etc.) requires that any commercial online service provider publish, in an easily accessible form, the provider's name, geographic address, electronic contact, registration number (where applicable), VAT number (where applicable), and supervising authority (where applicable). For Germany the requirement is enforced strictly, Impressumspflicht violations are routinely the subject of cease-and-desist letters (Abmahnung) from competitor law firms. For Hungary, the same information must be available before any contract is concluded (Ekertv. Section 4). The app's signup screen is effectively a contract-conclusion moment (the user agrees to the not-yet-existing Terms of Service per `auth.legal`), so the Impressum/Imprint must be linked from there at minimum. None of this exists.

Üzleti hatás

For German users, the immediate exposure is Abmahnung-style cease-and-desist letters from law firms specialising in finding Impressum gaps; typical settlement costs are EUR 500-2000 each plus a corrective Impressum. For Hungarian users, the consumer-protection authority can issue fines for missing Ekertv. Section 4 disclosures. Reputational impact: missing Impressum is an immediate red flag in any due-diligence review (B2B partners, investors). The fix is trivial (add a footer with name, address, email, VAT-ID, EU OS-platform link) but must be in place before German/Hungarian launch.

Magyarázat

German and Hungarian law require every commercial website to publish a small 'company info' block (legal entity name, address, contact email, VAT number) that users can reach from every page. Your app supports both German and Hungarian as launch languages, so this is in scope. The fix is a 1-hour task once you have the company details to fill in.

Javaslat
  1. Create `src/routes/impressum.tsx` (or `src/routes/imprint.tsx` with a localized title) rendering, in all 6 supported languages: legal entity name, geographic address, registration number (e.g. HU cegjegyzekszam), VAT number, email address, telephone number if applicable, name of the legally responsible person, supervising authority where applicable.
  2. Add a footer component (`src/components/Footer.tsx`) that renders on every page with links to /impressum, /privacy, /terms, /accessibility.
  3. For EU consumer-disputes, add the EU Online Dispute Resolution platform link (https://ec.europa.eu/consumers/odr), mandatory under Regulation (EU) 524/2013 when offering goods/services to consumers.
  4. If the controller is a Hungarian entity, include the NAIH (Nemzeti Adatvedelmi es Informacioszabadsag Hatosag) reference as the data-protection supervisory authority.
  5. For the German market specifically, follow the structure used by reputable German SaaS apps (the canonical layout is well-documented).
Becsült munka

S — under ½ day

Kapcsolódó dimenziók
Cross-references LEG-001, LEG-002 (footer links live in the same component as privacy/terms links).
AI Project Audit · Tech report · Legal & Compliance Charter v0.4 · 2026-05-19