Skip to content

API Development

Prerequisites

  • Node.js ≤22.4.x (see .nvmrc for 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

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:

Email 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:

  1. Start only Postgres and Redis:

    docker compose up -d db redis
    
  2. Update your .env to point at localhost instead of Docker service names:

    DATABASE_URL=postgres://cred@localhost:5432/cred_commercial
    REDISCLOUD_URL=redis://localhost:6379
    
  3. 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-api locally on http://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-commercial with Apollo Router on http://localhost:4000/graphql
  • Points commercial's CRED_MODEL_API_URL at the local model API via host.docker.internal
  • Reuses JWT_SECRET and CRED_MODEL_API_TOKEN from cred-api-commercial/.env so 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-db so migrations, generated artifacts, and seed data are in sync

Prerequisites:

  • cred-api-commercial/.env must exist and include JWT_SECRET and CRED_MODEL_API_TOKEN
  • cred-model-api/.env must 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, and cred-ios-commercial near cred-api-commercial. If your local workspace is laid out differently, copy cred-api-commercial/.local-federation.env.example to .local-federation.env and set MODEL_DIR=..., WEB_DIR=..., and/or IOS_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_URL at the local Commercial API:
  • http://host.docker.internal:8000
  • point DATABASE_URL at 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 .env with:
  • APOLLO_MCP_ENDPOINT=http://host.docker.internal:4000/graphql
  • APOLLO_GRAPH_REF=cred-supergraph-api@dev
  • APOLLO_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 Commercial me query 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-api locally, 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_URL in .env points to https://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 web container 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