Shared source of truth

App and web should read the same content paths and membership fields.

This page documents the exact route pattern and entitlement-field family the TechPSC web bundle is now using. It is written to match the Android membership resolver, so support and future sync work do not drift into two different rule sets.

Content routesShared engine

Topic lane path

Browse flow: family → stream → topic → MCQ.

quiz.html?quiz=quizzes/subjects/...

The browser should only launch the quiz engine after the user reaches the exact topic page.

Mock routesDense sets

Mock lane path

Browse flow: family → stream → set grid → quiz.

quiz.html?quiz=quizzes/mock-test/...

The set grid should stay visible first so users can scan all attempts before opening one.

Membership fields

Field families mirrored from the Android resolver

The web package now uses the same fallback field names the app checks in `MembershipAccountResolver`.

StatusEntitlement

Premium state fields

premiumStatus, membershipStatus, subscriptionStatus

ExpiryValidity

Plan expiry fields

planExpiryAt, planExpiry, subscriptionExpiryAt

FlagsFast check

Premium boolean

premium still acts as a direct active flag when the plan type and expiry also support it.

Plan typeLabel

Plan identity fields

planType, membershipPlan, premiumPlan, subscriptionPlan, planId

Session verification

After entitlement is found, the Android app calls the Cloud Function claimPremiumSession to verify or switch the active device session. The web Account page now follows the same rule so session conflicts can be explained instead of silently looking like a downgrade to free.