Replaces the hardcoded message limit with a model-driven paywall and removes registration before the first question: - Onboarding: the app opens directly into the chat. Dynamic conversation starters are served by GET /suggestions (services/api/suggestions.json), updatable with a deploy — no app release needed. Guests chat via POST /guest/chat, identified by an app-generated device id; sign-in moves to the paywall, where a purchase must attach to an account. - Free experience: the model runs in discovery mode — follow-up questions, pattern identification, visible understanding — building an analysis without delivering the full solution. - Intelligent paywall: the model returns structured output (reply + analysis_ready). Only when the problem is described, the information is sufficient and an action plan is ready does it write a calm transition and pause the conversation. Manufactured urgency, emotional pressure, fake readiness and mid-answer stops are explicitly forbidden. - Premium: on unlock the app resends the transcript and the backend immediately delivers the full analysis, strategies and exercises, then the dialogue continues without restriction. - The old FREE_MESSAGE_LIMIT becomes MESSAGE_CAP (default 200/30 days), kept purely as an abuse backstop — it is not the paywall. - WelcomeScreen removed; the app is now two views (Chat, Paywall). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0118DaxZR36RpnY524vRqx3z
5.7 KiB
NeuroSemantics AI
A minimalist mobile app for iOS and Android. The product is one thing only: an intelligent conversation partner with a specialized knowledge base in neurosemantics and NLP. No course portal, no CRM, no community.
Design language: calm, simple, clear. Off-white background, near-black text, one dark blue-green accent. No animations, no gradients.
System overview
apps/mobile Expo / React Native app (two views: Chat, Paywall)
services/api One Lambda backend (chat, usage, subscription verification)
infra AWS CDK stack (the entire cloud environment)
db/migrations SQL schema (two tables: users, usage)
A new developer should understand the whole system in under an hour. Every piece exists for a reason; if a feature does not make the core product better, it is not built.
Request flow
- The user lands directly in the chat — no registration before the first
question. Guests are identified by an app-generated device id
(
POST /guest/chat); dynamic conversation starters come fromGET /suggestions(both public routes). The suggestions live inservices/api/suggestions.jsonand can be updated with a deploy — no app release needed. - Requests go through API Gateway to the single Lambda; signed-in
users use
POST /chatwith a Cognito JWT (Apple / Google / email via the hosted UI). - The Lambda calls the OpenAI Responses API with the Markdown knowledge
base (
services/api/knowledge/) as system instructions. The model returns structured output: a reply plus ananalysis_readyflag. - Sign-in happens at the paywall, since a purchase must attach to an account. Usage counters live in PostgreSQL (Aurora Serverless v2).
The intelligent paywall
The paywall is not a hardcoded message count. Free conversations run in
discovery mode: the model asks relevant follow-up questions, names
patterns, shows understanding, and builds toward an analysis — without
delivering the full solution. When the problem is described, the information
is sufficient, and a concrete action plan is ready, the model signals
analysis_ready, writes a calm transition ("…I have a concrete strategy I
would recommend. Continue with Premium to see the analysis and the
recommended steps."), and the conversation pauses.
The instructions explicitly forbid manufactured urgency, emotional pressure, fake readiness, and stopping mid-answer — Premium should feel like the natural continuation of an already valuable dialogue.
On unlock, the app resends the transcript; premium mode then delivers the full analysis, recommended strategies and concrete exercises immediately, and the dialogue continues without restriction.
A generous MESSAGE_CAP (default 200 per 30 days) exists purely as an
abuse backstop for the free tier — it is not the paywall.
Conversations are never stored server-side; the client holds them in memory
and sends the running transcript with each request. The database stores the
absolute minimum: users (id, email, provider, subscription_status,
created_at) and usage (messages_used, last_reset). No profiling, no
training on user data. Error logging is anonymized (no message content).
Payments
Subscription logic is shared (services/api/src/subscription/); the payment
provider differs per platform behind one PaymentProvider interface:
- iOS — In-App Purchase; the backend verifies the app receipt with Apple.
- Android — Google Play Billing; the backend verifies the purchase token with the Play Developer API.
- Web (future) — a Stripe adapter slots into the same interface.
Plans: Monthly and Yearly. Nothing else.
Getting started
npm install # installs all workspaces
npm run lint
npm run typecheck
npm test
Mobile app
cd apps/mobile
npm start # Expo dev server
Fill in extra in app.json (API URL, Cognito domain and client id) from
the CDK stack outputs. In-app purchases require a development build
(expo run:ios / expo run:android), not Expo Go.
Backend + infrastructure
cd infra
npx cdk deploy
After the first deploy:
- Put values into the
neurosemantics/appsecret in Secrets Manager:OPENAI_API_KEY,APPLE_SHARED_SECRET,GOOGLE_SERVICE_ACCOUNT_JSON. - Run
db/migrations/001_init.sqlagainst the cluster (credentials are in the RDS-managed secret). - Optional: enable Apple/Google sign-in by passing CDK context
(
googleClientId,googleClientSecret,appleTeamId,appleKeyId,applePrivateKeySecretName). Email sign-in works out of the box.
CI/CD
GitHub Actions: ci.yml lints, type-checks and tests every PR;
deploy.yml deploys the CDK stack on every push to main (set the
AWS_DEPLOY_ROLE_ARN secret for OIDC). Store builds ship via EAS
(eas build) when you choose to release.
Security
- All traffic over HTTPS. Account routes require a Cognito JWT; the two
public routes (
/suggestions,/guest/chat) carry no account data and are bounded by the free-tier message cap. - Secrets live in AWS Secrets Manager only — no API keys in the client.
- The Lambda runs in private subnets; the database is not publicly reachable.
Product philosophy
Every free user should leave the app feeling that the system understood their situation, that a concrete analysis is ready, and that the next step is available in Premium — never that they were held back by an artificial interruption.
Every new feature must justify itself. The allowed AWS surface is API Gateway, Lambda, Cognito, S3, Secrets Manager and CloudWatch — and V1 does not even need S3. No Redis, no Kubernetes, no Kafka, no Elasticsearch, no queues, no microservices. One backend. Maximal simplicity.