✨ This workspace has been generated by Nx, a Smart, fast and extensible build system. ✨
Tickets live in Linear, not GitHub Issues. Every change starts from a Linear issue:
- Pick up an issue in Linear and move it to In Progress (opening a PR does this for you).
- Press Cmd/Ctrl + Shift + . on the issue to copy its branch name, then
git checkout -b nick/dev-12-checkin-form-schemawith what you copied. Keeping theDEV-…ID in the branch name is what links the PR back to the issue. - Open a PR against
main. Fill inCloses DEV-12in the template. - On merge, Linear moves the issue to Done automatically. Don't update statuses by hand.
If you skip the branch-name step, add Closes DEV-12 to the PR description instead — either one
links it. See Project Management for the full magic-word
list and the Linear MCP setup for Claude Code.
Clone this repo and run yarn at the root to install this project's dependencies.
You can optionally install nx globally with npm install -g nx - if you don't, you'll just need to prefix the commands below with npx (e.g. npx nx serve backend).
This project uses PostgreSQL. You'll need a running Postgres instance before starting the backend.
Option A — Docker (recommended for local dev):
docker run --name scaffolding-db \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=[DB NAME HERE] \
-p 5432:5432 \
-d postgres:15Option B — pgAdmin / existing Postgres install:
Create a new database (e.g. jumpstart) through pgAdmin or psql.
Configure connection strings:
Copy example.env to .env and fill in your credentials:
cp example.env .envNX_DB_HOST=localhost
NX_DB_PORT=5432
NX_DB_USERNAME=postgres
NX_DB_PASSWORD=postgres
NX_DB_DATABASE=[DB NAME HERE]Run migrations:
yarn migration:runTo generate a new migration after changing entities:
name=your_migration_name yarn migration:generateWindows users: The
name=...syntax above only works on Mac/Linux. On Windows, runset name=your_migration_name && yarn migration:generatein Command Prompt, or$env:name="your_migration_name"; yarn migration:generatein PowerShell.
To revert the most recent migration:
yarn migration:revertFriendshipWorks is a mobile-only app. This workspace has two projects: the NestJS backend and the React Native + Expo mobile app.
In two terminals:
nx serve backend # API on port 3000
nx serve mobile-frontend # Metro bundler + Expo Go QR code
Scan the QR code with Expo Go on your phone. See Running the mobile app (Expo) below for setup. Happy coding!
To run just the backend (port 3000):
nx serve backend
To run just the mobile app:
nx serve mobile-frontend
Run them in two separate terminals — the backend and the Metro bundler are both long-running.
Extra Expo flags are forwarded through, so nx serve mobile-frontend --clear starts with a cleared
bundler cache.
Expo is a toolchain built on top of React Native. Two parts of it matter here:
- Metro, the bundler. It compiles
apps/mobile-frontendinto a JavaScript bundle and serves it over your local network while you develop. - Expo Go, a free sandbox app from the App Store / Play Store. It downloads your bundle from Metro and runs it, so you can see all changes without compiling anything natively (No XCode needed!!).
Sign up at expo.dev/signup, then log in from the repo:
npx expo login
Since everyone hits builds eventually, create the account during setup rather than later.
Get it from the App Store or Play Store. Your phone and your computer must be on the same Wi-Fi network — Metro serves the bundle over the LAN.
The mobile app reads its own env file, separate from the backend's:
cp apps/mobile-frontend/example.env apps/mobile-frontend/.env
On a physical phone, localhost means the phone, so set EXPO_PUBLIC_API_BASE_URL to your
computer's LAN IP (e.g. http://192.168.1.42:3000). Find it with ipconfig getifaddr en0 on macOS
or hostname -I on Linux. The committed localhost:3000 default is only correct for simulators and
the web target.
Two terminals:
nx serve backend # terminal 1 — API on port 3000
nx serve mobile-frontend # terminal 2 — Metro + QR code
Metro prints a QR code in terminal 2.
- iOS: scan it with the built-in Camera app, then tap the notification.
- Android: open Expo Go and use Scan QR code.
The app downloads and launches in Expo Go. First load takes a few seconds while the bundle builds.
nx serve mobile-frontend already selects Expo Go, but if the QR route misbehaves you can press s
in the terminal to toggle between Expo Go and development-build mode. To use a simulator instead
(requires Xcode / Android Studio), press i or a.
Edit any file under apps/mobile-frontend/src/ and save. Fast Refresh pushes the change to your
phone in about a second, keeping component state where it can. No rebuild, no re-scan.
Useful keys in the Metro terminal:
| Key | Does |
|---|---|
r |
Full reload (use when Fast Refresh gets confused) |
j |
Open the debugger |
m |
Toggle the dev menu |
? |
List all commands |
Shake the phone (or long-press with three fingers) to open the in-app dev menu.
Editing .env is the exception to live reload. EXPO_PUBLIC_* values are inlined when Metro
transforms your code, and those transforms are cached — so a changed env value won't appear until
you restart with a cleared cache:
nx serve mobile-frontend --clear
nx lint mobile-frontend
nx test mobile-frontend
nx typecheck mobile-frontend
nx export mobile-frontend # local bundle validation (what CI runs)
nx run-ios mobile-frontend # needs Xcode
nx run-android mobile-frontend # needs Android Studio
Why
serve/startare defined explicitly inproject.json:@nx/expo's ownserve,startand web executorsfork()@expo/cli/build/bin/cli, a path@expo/cli@57no longer ships, so they fail withCannot find module. Both targets are therefore overridden to runexpo start --goas a plain command instead. The plugin-inferred targets above (export,run-ios,run-android) were already plain shell commands, so they were never affected. Once Nx reaches 23.1+ the overrides can likely be dropped, along with theconfig.projectRootworkaround inmetro.config.js.
nx build mobile-frontendis not a local build — it triggers a cloud EAS build, requiringnpx expo loginand an Expo account. For local validation usenx export mobile-frontend.
The backend can expose Swagger UI (built from an OpenAPI document via @nestjs/swagger) so you can browse and try HTTP routes without reading controller code first.
Turn it on: In .env at the repo root (copy from example.env), set SWAGGER_ENABLED=true. Restart the backend (nx serve backend), then open http://localhost:3000/api for the UI.
Turn it off: Unset SWAGGER_ENABLED or set it to false.
TL TODOS:
- In
apps/backend/src/main.ts, replace[YOUR_APP_NAME]and other[TL]strings, adjust.addTag()entries to match your controllers, - Add
@ApiBearerAuth()onto the controller or handler for specifically protected routes.addBearerAuth()only states that the application supports authentication via HTTP Bearer in the Authorization header, it doesn't mark specific routes as protected. Learn more
Decorators to know as you add routes!
(import from @nestjs/swagger):
@ApiProperty()/@ApiPropertyOptional(): on top of DTO fields@ApiTags('Name'): on top of controllers to tag them to specific tags/features@ApiHeader({name: '...', description: '...'}): on top of individual methods or controllers to define custom headers that are expected as part of the requests to those methods/controllers@ApiResponse({ status: '...', description: '...' }): to define a custom HTTP response.- Prebuilt helpers (fixed status in the spec):
@ApiOkResponse(200),@ApiCreatedResponse(201),@ApiNotFoundResponse(404), additional@Api*Responseshortcuts
- Prebuilt helpers (fixed status in the spec):
Run git submodule update --remote to pull the latest changes from the component library
When cloning the repo, make sure to add the --recurse-modules flag to also clone the component library submodule (e.g. git clone --recurse-submodules https://github.com/Code-4-Community/scaffolding.git for the scaffolding repo)
Note: the
shared/submodule is currently not used by any app. Its only consumer was the web frontend that has since been removed. It is kept for now in case the mobile app adopts the shared component library later; you can safely skip initializing it.