API Development
Prerequisites
- Node.js ≤22.4.x (see
.nvmrcfor version) - Yarn 1.22.x (Classic)
- Docker & Docker Compose – for Postgres, Redis, and optional full-stack run
Quick Start
1. Install Dependencies
cd cred-api-commercial
nvm use
yarn install
2. Environment Setup
Recommended: Automated setup via Cursor AI
If you use Cursor IDE, ask the AI agent to set up your .env:
"Set up my .env for local development"
This runs the env-setup skill, which fetches all env vars from the Cloud Run dev service via gcloud and applies local overrides from .env.local-overrides (DB, Redis, NODE_ENV pointing to localhost). Requires gcloud auth login with your @credinvestments.com account.
Manual setup
Alternatively, create a .env file manually. Copy from .env.example and add the variables below. For secrets, see the 1Password Commercial API env item.
# Database (used when app connects to Docker Postgres)
DATABASE_URL=postgres://cred@db:5432/cred_commercial
PG_DATABASE_PORT=5432
# Redis (commercial_cache is the Docker Compose service name)
REDISCLOUD_URL=redis://commercial_cache:6379
API_REDIS_PORT=6379
# Application
NODE_ENV=local
PORT=8000
WEB_PORT=8000
WEB_DEBUG_PORT=9222
# GraphQL Router (if using with_federation profile)
GRAPHQL_ROUTER_PORT=4000
# Model API (points to dev – already set correctly in .env.example / 1Password)
CRED_MODEL_API_URL=https://model-api-dev.credplatform.com/graphql
# Auth (optional for local dev)
JWT_SECRET=your-local-dev-secret
OKTA_AUTH_CALLBACK_ENDPOINT=http://localhost:8000/okta/auth/callback
CRED_COMMERCIAL_WEB_LOGIN_PAGE=http://localhost:8002/signin
3. Start the API (Docker – recommended)
Start Postgres, Redis, and the Commercial API in containers:
docker compose up
Equivalent to yarn dev. The web container runs nodemon inside Docker, so the app restarts automatically when you edit src/ files.
With a clean rebuild:
docker compose up --build
# or
yarn dev:rebuild
The API runs at http://localhost:8000/graphql.
Verify it's running:
curl -s http://localhost:8000/graphql -H 'Content-Type: application/json' \
-d '{"query":"{ __typename }"}' | head -c 100
You should see {"data":{"__typename":"Query"}}.
.env changes require container recreation
If you change .env after containers are already running, use docker compose up -d (not docker compose restart) to pick up the new values.
4. Database Setup
To get the database working (fresh setup or reset), run:
When using full Docker – inside the web container:
docker compose run --rm web yarn reset
When running the app on the host – set DATABASE_URL=postgres://cred@localhost:5432/cred_commercial and run:
yarn reset
yarn reset does: build → drop cache → drop DB → migrate → seed.
For incremental migrations only (no wipe), use yarn prep-db instead.
5. Database Seeding
Seeds populate the local database with test data so the app is usable out of the box. They run automatically as part of yarn reset and yarn prep-db, or you can run them separately.
Running seeds:
# Full Docker (recommended)
docker compose run --rm web yarn seed
# App on host (DB + Redis in Docker)
DATABASE_URL=postgres://cred@localhost:5432/cred_commercial \
REDISCLOUD_URL=redis://localhost:6379 \
NODE_ENV=local \
yarn seed
NODE_ENV must be local
Several seeds only run when NODE_ENV is local or test. If you see "Skipping 004-user" in the output, your NODE_ENV is wrong. Set NODE_ENV=local in your .env or pass it inline.
What the seeds create:
| Seed | What it creates |
|---|---|
| 001-currencies | All currency codes (USD, EUR, etc.) |
| 002-languages | 35 languages |
| 003-feature | Feature definitions (credits, enrichment, waterfall, etc.) |
| 004-user | 3 test users, 2 companies, and initial credits |
| 005 / 006 | Waterfall enrichment configurations |
| 007-account | 10 test accounts (Acme Corp, Globex, etc.) |
| 008-contact | 12 test contacts linked to accounts |
| 009-opportunity | 8 test opportunities across pipeline stages |
| 010-collection | 10 custom lists (account, contact, opportunity) with items |
Test login credentials:
| Password | Role | Company | |
|---|---|---|---|
admin@credinvestments.com |
P@ssword01 |
Admin | CRED Investments |
test@credinvestments.com |
P@ssword01 |
User | Test Company |
test2@credinvestments.com |
P@ssword01 |
User | Test Company |
Running a single seed (on host):
DATABASE_URL=postgres://cred@localhost:5432/cred_commercial \
REDISCLOUD_URL=redis://localhost:6379 \
NODE_ENV=local \
node -e "require('./dist/data/seeds/007-account').seed().then(() => process.exit(0))"
Note
When running individual seeds on the host, you must yarn build first — seeds run from the compiled dist/ directory.
All seeds are idempotent — safe to run multiple times without duplicating data.
Run Modes
Full Docker (docker compose up)
- Postgres, Redis, and the web app run in Docker.
- The web container runs nodemon internally – edits to
src/trigger automatic restarts. - App listens on
http://localhost:8000. - Debug port:
9222(e.g.localhost:9222).
App on Host, DB + Redis in Docker
Useful for debugging or development without running the app in Docker:
-
Start only Postgres and Redis:
docker compose up -d db redis -
Update your
.envto point at localhost instead of Docker service names:DATABASE_URL=postgres://cred@localhost:5432/cred_commercial REDISCLOUD_URL=redis://localhost:6379 -
Build and run:
yarn build yarn migrate yarn seed yarn nodemon
The API will be at http://localhost:8000/graphql.
GraphQL Router (Federation)
Full Multi-Service Federation
For the full local federation stack (including filter-api, agent-ai, and MCP), see the Local Federation documentation. The ./fed CLI in cred-local-workspace manages all services with a single command.
Federation runs the full CRED platform locally: a local commercial-api behind an Apollo Router that composes a supergraph from 4 subgraphs.
Frontend (localhost:8002)
│
▼
Apollo Router (localhost:4000)
├── commercial-api (localhost:8000) ← LOCAL (Docker)
├── model-api-dev.credplatform.com ← REMOTE
├── filter-api-dev.credplatform.com ← REMOTE
└── agent-ai-dev.credplatform.com ← REMOTE
This is the default mixed local/remote mode. If you also need to change cred-model-api locally and have the router compose against it, use the full local model setup below.
Automated setup
If you use Cursor IDE, ask: "Set up local federation" — this runs the local-federation-setup skill which handles everything below automatically.
1. Prepare .env
Use the dev target of env-setup (not local), then comment out DATABASE_URL so Docker Compose uses its internal db hostname. Verify these are present:
# DATABASE_URL=... ← must be commented out
CRED_MODEL_API_URL=https://model-api-dev.credplatform.com/graphql
CRED_FILTER_API_URL=https://filter-api-dev.credplatform.com/graphql
CRED_AGENT_AI_URL=https://agent-ai-dev.credplatform.com/graphql
2. Start the backend
docker compose --profile with_federation up
First run takes several minutes (Docker build + TypeScript compilation). Wait for these log lines:
- Web container:
Server ready ... graphqlUrl: http://localhost:8000/graphql - Router:
GraphQL endpoint exposed at http://0.0.0.0:4000/graphql
3. Build, migrate, and seed the local DB (first run only)
docker compose exec web yarn prep-db
4. Start the frontend
In the cred-web-commercial repo:
bun install
bun run dev:local
This uses .env.local.local which points the frontend at the local gateway (localhost:4000). Frontend starts on http://localhost:8002.
5. Switching between local and remote dev
# Switch to remote dev
rm -rf apps/web-commercial/.next
bun run dev
# Switch back to local
rm -rf apps/web-commercial/.next
bun run dev:local
The cache clear is required — Next.js caches env vars in .next/.
6. Regenerating GraphQL types after schema changes
When you add or change fields in the backend:
cd cred-web-commercial
bash scripts/gql-local.sh --restart # after backend schema change (~40s)
bash scripts/gql-local.sh # just regenerate types, no restart (~10s)
Use --restart when you've changed the backend GraphQL schema. Skip it when you only changed frontend .gql query files.
| Service | URL |
|---|---|
| Frontend | http://localhost:8002 |
| Federation Gateway | http://localhost:4000/graphql |
| Commercial API | http://localhost:8000/graphql |
Full Local Model API (commercial + model local)
When you need schema changes from cred-model-api to flow through the local router into web/iOS codegen, start both APIs locally:
cd cred-api-commercial
bash start-local-model-federation.sh
What the helper does:
- Starts
cred-model-apilocally onhttp://localhost:3000/graphql - Verifies
personById(2)works against the local model API before continuing, so downstream search/index config issues fail early - Starts
cred-api-commercialwith Apollo Router onhttp://localhost:4000/graphql - Points commercial's
CRED_MODEL_API_URLat the local model API viahost.docker.internal - Reuses
JWT_SECRETandCRED_MODEL_API_TOKENfromcred-api-commercial/.envso commercial-to-model auth works locally - Uses a local-only router config that sends the model-api subgraph the static model API token while still forwarding the
x-user-*viewer headers, so users created only in the local commercial DB can still resolve model-backed fields - Detects an empty local commercial database or missing compiled artifacts and runs
yarn prep-dbso migrations, generated artifacts, and seed data are in sync
Prerequisites:
cred-api-commercial/.envmust exist and includeJWT_SECRETandCRED_MODEL_API_TOKENcred-model-api/.envmust exist and include the normal model-api local credentials- Docker Desktop must be running
- By default the helper looks for sibling clones of
cred-model-api,cred-web-commercial, andcred-ios-commercialnearcred-api-commercial. If your local workspace is laid out differently, copycred-api-commercial/.local-federation.env.exampleto.local-federation.envand setMODEL_DIR=...,WEB_DIR=..., and/orIOS_DIR=...
After the helper succeeds:
# Frontend codegen from the local router
cd ../cred-web-commercial
bash scripts/gql-local.sh --restart
# iOS codegen from the local router
cd ../../mobile/cred-ios-commercial
./cred graphql sync local
Optional Local Agent AI
If you also need the AI assistant stack locally, cred-agent-ai can run beside
the local Commercial API:
cd ../../api/cred-agent-ai
docker compose up -d
Recommended local-only env shape:
- keep shared MCP / LLM / third-party credentials from the dev service env
- point
COMMERCIAL_API_URLat the local Commercial API: http://host.docker.internal:8000- point
DATABASE_URLat the local Commercial Postgres: postgres://cred@host.docker.internal:5432/cred_commercial- run the local GraphQL MCP server if you want GraphQL-backed Agent AI tools to
work for local-only Commercial users:
cd ../../api/cred-mcp/graphql-mcp-server docker compose up -d --build - for that local MCP server, use an ignored
.envwith: APOLLO_MCP_ENDPOINT=http://host.docker.internal:4000/graphqlAPOLLO_GRAPH_REF=cred-supergraph-api@devAPOLLO_KEY=<valid graph service key>MCP_ALLOWED_HOST=host.docker.internal- then point Agent AI at it:
MCP_SERVER_URL=http://host.docker.internal:5000/mcp- enable the local-only auth fallback:
LOCAL_FEDERATION_MODE=true
Why the fallback exists:
- in normal hosted environments, Agent AI verifies the JWT and then resolves the user from its own database
- in local federation, a developer can create a user only in the local Commercial DB
- with
LOCAL_FEDERATION_MODE=true, Agent AI keeps the normal shared lookup first and only falls back to the local Commercialmequery when needed - that mode is only considered valid when Agent AI is also pointed at the local
commercial DB via
DATABASE_URL; otherwise the fallback stays disabled - for the older GraphQL assistant mutation path, local-only requests also stay on an in-process background path so the caller token can reach GraphQL-backed MCP tools without being written into BullMQ / Redis
For iOS DebugLocal, point the agent base/socket config at localhost:8080
instead of the remote agent-ai-dev host.
Scope note:
- the local GraphQL MCP server is enough for GraphQL-backed tools such as
currentUser - assistant/follow-up MCP tools remain outside this local GraphQL MCP path
Trino (BigQuery / analytics)
To include Trino:
docker compose --profile with_trino up
Model API
The Commercial API uses the CRED Model API for AI features.
- In the default local federation flow above, it connects to the dev Model API via
CRED_MODEL_API_URL. - If you need schema or resolver changes from
cred-model-apilocally, use the Full Local Model API flow above instead.
Cursor AI Skills
If you use Cursor IDE, the repo includes AI-powered skills that automate common workflows. Mention the skill name in chat and the agent will follow the instructions automatically.
| Skill | What to ask | What it does |
|---|---|---|
| env-setup | "Set up my .env for local" | Fetches env vars from Cloud Run dev, applies local overrides, writes .env |
| local-federation-setup | "Set up local federation" | Starts backend (Docker) + frontend (host) + Apollo Router with full federation |
| pg-database-access | "Connect to the dev database" | Opens a read-only connection to Local/Dev/Staging/Prod via Cloud SQL Proxy |
| db-migration | "Create a migration to add column X" | Generates a Knex migration file following repo conventions |
| testing | "Write tests for my use case" | Scaffolds unit/integration tests for use cases, repos, resolvers |
Skills live in .cursor/skills/ in the repo. Run ls .cursor/skills/ to see all available skills.
Useful Commands
| Command | Description |
|---|---|
docker compose up |
Start full stack (Postgres, Redis, API with hot reload) |
yarn dev |
Same as docker compose up |
yarn dev:rebuild |
Rebuild containers and start |
yarn nodemon |
Run app with hot reload (when app runs on host, not in Docker) |
yarn reset |
Reset DB: build, drop cache, drop db, migrate, seed |
yarn prep-db |
Build, migrate, seed (no drop – incremental) |
yarn migrate |
Run migrations |
yarn seed |
Run seeds |
yarn start:worker |
Background workers (Merge/Polytomic webhooks, etc.) |
yarn start:nylas-worker |
Nylas webhook workers |
Endpoints
| Service | URL |
|---|---|
| GraphQL API | http://localhost:8000/graphql |
| GraphQL Playground | http://localhost:8000/graphql |
| GraphQL Router | http://localhost:4000 (with with_federation) |
| Debug port | localhost:9222 |
| Prometheus metrics | http://localhost:8001/prometheus/metrics |
Troubleshooting
Database connection refused
- Ensure Postgres and Redis are running:
docker compose ps - With app on host:
DATABASE_URL=postgres://cred@localhost:5432/cred_commercial,REDISCLOUD_URL=redis://localhost:6379
Model API errors
- Ensure
CRED_MODEL_API_URLin.envpoints tohttps://model-api-dev.credplatform.com/graphql
Port conflicts
- Override ports in
.env:WEB_PORT,PG_DATABASE_PORT,API_REDIS_PORT
tsc -w crashes with exit code 134
- The TypeScript watcher inside the Docker
webcontainer can run out of memory and exit with code 134. This is harmless — the app server (nodemon) runs independently and will still start. You can safely ignore this.
Clean reset
yarn clean
docker compose down -v
docker compose up --build
# Then: docker compose run --rm web yarn reset