This project was kickstarted with FullProduct.dev's universal app starterkit:
- Zod schemas as single source of truth: Use
schema()from@green-stack/schemas. APIs, types, db models and docs derive from these to stay in sync. - Workspace-defined routes: Define routes in
features/*/routes/. Runnpm run link:routesto re-export to Expo/Next. - Universal UI: Use
View,Text,Imagefrom@app/uiwith Nativewind compatibleclassNameinstead of HTML primitives. - Expo + Next.js: Most UI must work on web (Next.js) and mobile (Expo). Routing, images, and some APIs use React Portability Patterns (shared types +
*.next/*.expoimplementations injected at app roots)—not only.web.ts/.ios.tssplits. See React Portability Patterns. - Feature-first colocation: Routes, resolvers, schemas, screens live together in
features/*/orpackages/*/workspaces instead of being split by frontend/backend. - Portable workspaces and dependencies: Expo/native packages used only by a
features/*/orpackages/*/workspace belong in that workspace’spackage.json, not onapps/expo. Usenpm run add:dependenciesto install SDK-compatible versions viaexpo install, the script will then move the resolved versions to the target workspace (see.cursor/rules/workspace-expo-dependencies.mdc).
- Project structure
- Routing
- React Portability Patterns
- Data resolvers & APIs
- Data fetching
- Schemas & single sources of truth
- Universal styling
- Form management
- Generators
- Workspace drivers
- Env vars + App config
- Automatic docgen
When updating or recreating files:
- always maintain the same code style and tab spacing of the existing files
- Preserve all existing comments in any file you edit. Do not delete or shorten them unless you are deleting or rewriting the exact lines they refer to—then update those comments to match the new behavior.
- Treat inline and block comments as part of the API of the file: moving code should move comments with it; refactors must re-home comments, not drop them for brevity.
- Try to never use
anyunless absolutely necessary. Attempt to use generics instead or inference instead. - If we need a type and can extract a type from a Zod schema, we should. Check our single sources of truth docs for more info about that.
- Use section dividers like
/* --- Section name ------------------------------------------------------------- */padded to ~100 characters (match surrounding files). - Prefer this order when it fits: constants → types → implementation (add other sections such as styles or exports as needed).
Wherever possible, think of a plan and good feeback loop for the code you'll be writing.
Make the plan extremely concise. Sacrifice grammar for the sake of concision.
At the end of each plan, give me a list of unresolved questions to answer, if any.
A good feedback loop could be a test suite to run red green iterations with, or look at some of our scripts to run to help test everything still works as expected.
To see whether all apps are still working as expected, run the relevant commands to check:
npm run testruns all bun tests in@green-stack/core.npm run typecheckrunstypecheckin every workspace that defines it (via Turbo, parallel + cached).npm run typecheck:webandtypecheck:mobilescope to one app.npm run build:webruns the Next.js production build for@app/next(apps/next).npm run build:mobilerunsexpo exportfor@app/expo(apps/expo).npm run buildruns the full Turbobuildpipeline for the monorepo.
- bun is required for
npm run test(the test runner is bun). Install viacurl -fsSL https://bun.sh/install | bashif missing, then ensure~/.bun/binis onPATH.
npm run dev:webstarts the Next.js app with Turbo; it first runsbuild:schema(which also triggerscollect:resolvers,collect:schemas,collect:drivers,collect:models).- Expo / mobile: Cloud agents usually run Linux VMs without macOS/iOS Simulator or a typical local Android emulator. Do not assume you can open a simulator here; rely on
dev:web+ tests/builds where possible and call out manual Expo verification for the user when changes are platform-sensitive. - The DB layer has a built-in mock memory DB fallback if no
DB_URL/MONGODB_URIis set, so the app runs without an external database. - Clerk auth and Stripe require real secrets to function; without them the app still starts but auth/payment flows will fail.
npm run dev:webusesnext dev --webpack(webpack mode, not Turbopack).- The dev server first-compiles pages on demand; initial page loads may be slow.