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 user accepts TOS + privacy + waiver during signupThree legal_consents rows 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 for audit context
#ScenarioExpected
3.1New user has accepted no documentshasRequiredConsents=false; access gated on TOS + privacy + waiver
3.2User accepted TOS + privacy but not waiverStill gated
3.3User accepted all threeAccess allowed
3.4TOS bumped after user accepted v1getConsentStatus returns requiresReconsent=true for TOS; banner appears
3.5Concurrent acceptances on two devicesRace-safe: at worst two rows for the same doc — currently prevented by the existence check; verify no constraint blows up if the race wins both sides

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.5Wizard mode (standalone=false)Parent receives onAccepted callback after API success

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.