A sanitized TypeScript code sample inspired by the architecture behind PractiPrep, a mobile learning app for IHK Fachwirt exam preparation.
This repository demonstrates how premium entitlement state and AI usage limits can be resolved in a mobile app without exposing production source code, API keys, database schemas, AI prompts, payment product IDs, or proprietary business logic.
PractiPrep combines mobile learning flows, subscription access, AI-assisted explanations, account state, and backend synchronization. One of the most important product problems is deciding whether a user should receive access to premium AI features at a specific moment.
This sample focuses on that decision boundary:
- Normalize entitlement signals from multiple sources.
- Resolve one trusted premium access state.
- Decide whether the AI assistant can be used right now.
- Return a clear decision that the UI can act on.
- Type-safe domain modeling in TypeScript
- Subscription and offer-code edge cases
- Defensive handling of stale or unreachable backend state
- Daily AI usage limits for premium users
- UI-ready access decisions with reason codes
- Focused unit tests for product-critical logic
This is not the PractiPrep production app. It intentionally excludes:
- Real React Native screens or app navigation
- Real RevenueCat, StoreKit, or App Store product identifiers
- Supabase URLs, schemas, policies, functions, or service keys
- AI prompts, moderation rules, or provider credentials
- Question databases, answers, explanations, or learning content
- Private business logic and production implementation details
const entitlement = resolveEntitlement(sourceState, now);
const decision = canUseAiAssistant({
entitlement,
dailyUsage,
now,
policy,
});The UI can then use the decision to either open the AI assistant, show a premium prompt, show a restore message, or explain that a daily limit has been reached.
The most relevant files to review are:
src/entitlement/resolveEntitlement.ts— normalizes purchase, restore, backend, and offer-code signals into one app-facing premium state.src/ai-usage/canUseAiAssistant.ts— turns entitlement and daily usage state into a UI-ready AI access decision.src/entitlement/resolveEntitlement.test.tsandsrc/ai-usage/canUseAiAssistant.test.ts— cover the edge cases that matter most for product behavior.
src/
├── entitlement/
│ ├── entitlement.types.ts
│ ├── resolveEntitlement.ts
│ └── resolveEntitlement.test.ts
├── ai-usage/
│ ├── aiUsage.types.ts
│ ├── canUseAiAssistant.ts
│ └── canUseAiAssistant.test.ts
├── shared/
│ └── time.ts
└── index.ts
npm install
npm run checkThe sample separates signals from decisions. Raw purchase, restore, offer, and backend states are treated as signals. The app-facing code receives a normalized entitlement object with a stable reason code.
That keeps screens simpler: UI components do not need to know whether access came from an active subscription, a recent purchase confirmation, an offer code, or a trusted cached state.
This repository is safe to publish because it contains only generic, sanitized TypeScript. It is intended as a readable engineering sample for portfolio and review purposes.
Created by Nico Ohm / NOQCode.