Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesLegalLegal — QA Plan

Legal — QA Plan

1. Document fetch

#ScenarioExpected
1.1GET /legal/documents with no localeReturns latest per type in he
1.2GET /legal/documents?locale=enReturns latest English version of each type
1.3Two terms_of_use rows with same published_atDeterministic tiebreak by id ASC
1.4Locale missing for a type (e.g. no ru cookie_policy)That type omitted from response
#ScenarioExpected
2.1New owner accepts platform Terms during signupOne legal_consents row inserted with context='owner_onboarding', IP + UA captured
2.2User accepts the same set againNo new rows — recordConsent filters already-consented document IDs
2.3TOS bumped to v2; user re-accepts via reconsent flowNew row for v2 inserted with context='reconsent'; v1 row remains
2.4Request behind proxy with X-Forwarded-For: 1.2.3.4ip_address='1.2.3.4'
2.5Request with no user agentuser_agent NULL in DB
2.6Consent recorded with organizationId setRow carries the org id; external acknowledgement uses it as required scope, other types as audit context
#ScenarioExpected
3.1Active member has accepted no documentsAccess gated on privacy, fitness acknowledgement and member terms, never owner platform Terms
3.2Active owner has not accepted current platform TermsGated only on terms_of_use; privacy, health acknowledgement and member terms are absent
3.3Active admin or coach has no staff-specific termsAccess allowed; member and owner documents are not presented
3.4User accepted every server-required current version in the active organizationAccess allowed
3.5Concurrent acceptances on two devicesNon-unique ledger index permits duplicate evidence if both pass the existence check; no unique-constraint failure

4. Web UI

#ScenarioExpected
4.1Acceptance form in HebrewRTL layout, links open marketing-site Hebrew page
4.2Click marketing link with no internetGraceful — link target unreachable but form still submittable
4.3Check all boxes, click AcceptAPI call sends correct types array; on success, dialog dismisses
4.4Uncheck a required boxSubmit button disabled / form invalid
4.5Embedded mode (standalone=false)No API call from the form. Parent receives onAcceptedChange(true/false) on every tick/untick and onAccepted when all boxes are ticked

5. Permissions

#ScenarioExpected
5.1Unauthenticated GET /legal/documents200 — public route
5.2Unauthenticated POST /legal/consents401
5.3Authenticated user fetches their own status200
5.4User cannot fetch another user’s statusNo such endpoint exists — status is always self

6. Edge cases

#ScenarioExpected
6.1recordConsent with empty types arrayIsArray + IsEnum each: true rejects — 400
6.2recordConsent with unknown type400 from DTO validator
6.3recordConsent with malformed UUID organizationId400
6.4DB connection drops mid-insertCaught error; partial rows for some types possible (atomicity is per-statement only — not wrapped in a transaction)

7. Smoke

  • New owner can complete signup with the acceptance step.
  • Member onboarding picks up context='member_onboarding'.
  • Status endpoint returns requiresReconsent=true after a doc bump.
  • Banner appears in Hebrew RTL with correct copy.
#ScenarioExpected
8.1Existing active member has current privacy + fitness acceptance but no current member termsExisting /accept-terms requests member terms only; no compliance form, privacy/fitness re-sign or synthetic consent
8.2Native payment provider, no plan payment-link URLRequired join array includes privacy, fitness acknowledgement and member_terms; no staff Terms in the member-join contract
8.3Server-resolved plan payment-link URL or active external providerSeparate external acknowledgement is required alongside member terms and the base bundle
8.4Bypass UI and omit a required boolean on invitation request or authenticated direct acceptServer rejects before membership/invitation mutation; analytics consent never substitutes for legal acceptance
8.5Payment configuration changes after public resolveSubmit recomputes payment requirements and rejects incomplete newly required acceptance
8.6Accept each new document in he, en, and ruEvidence references the current exact localized version, with context/IP/UA/time and organization; Hebrew links have no /he prefix
8.7External acknowledgement exists for organization A; join organization BA’s evidence does not satisfy B; same-organization current evidence is deduplicated
8.8New required member/external document version is publishedOld consent remains evidence, but does not satisfy current required status
8.9Switch organization at /users/me and consent-status, including stale explicit selectionRequired types and returned organizationId follow valid explicit org then membership role priority; stale/omitted selection falls back; active-member backstop never includes external acknowledgement
8.10Open /accept-terms as a member who is staff elsewhereRequirements follow the selected organization only: member documents appear in the member org and no member documents appear in the staff org
8.11Review launch prerequisitesIsraeli counsel approves member terms and external-payment acknowledgement before launch; document publication never inserts acceptance on behalf of members
8.12Pending-only member joins with active external providerDistinct external acknowledgement checkbox is required before activation; returned status preserves target organization scope
8.13Staff creates or invites a member without required consentCreation/invitation succeeds without validating or recording member consent; the member accepts through /accept-terms at first login and pending invitations activate only after required consent
8.14Read Fitness & Health AcknowledgementDisplay title is updated; fitness_waiver type/slug stay unchanged; mandatory statutory rights are not waived
8.15Member join requires privacy, fitness acknowledgement and member termsAll three documents are linked under one required legal checkbox; no separate fitness or member-terms checkbox appears
8.16Analytics/session replay on first onboarding renderSeparate optional checkbox is unchecked; required legal submit can proceed without it
8.17Inspect mobile PostHog replay config after opt-inText inputs, images and sandboxed views are globally masked; log and network telemetry capture are false
8.18Open a plan-less join link while signed outIdentity fields, required legal agreement, optional analytics, and Join submit are one step; no later confirmation screen appears
8.19Submit English/Russian join consent with a required catalog row missingInvitation ticket is not returned and no subset of the requested legal types is recorded