This guide is for engineers and internal integrators working on the Winnerr monorepo. It reflects the current repository behavior: the CRM web app, API app, provider webhooks, workflows, and MCP integration surfaces.
Winnerr’s public third-party REST API and official language SDKs are not documented as launched surfaces in this repository. Do not build against /v1 examples, package names, sandbox hosts, or developer-dashboard flows unless a supported integration contract has been provided separately.
Prerequisites
- Node.js 18 or newer.
- pnpm 8 or newer.
- Access to the required environment variables for the app, API, database, auth provider, and any provider integrations you are testing.
- PostgreSQL-compatible database access for local development.
Install dependencies
From the repository root:
Create local environment files for the apps you are running. At minimum, local app/API development expects these URL values to agree:
# apps/app/.env.local
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:3002
# apps/api/.env.local
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:3002
DATABASE_URL=postgresql://USER:PASSWORD@HOST:PORT/DATABASE
JWT_SECRET=replace-with-a-local-secret
Add provider-specific keys only for the features you are actively developing or testing, such as Twilio, Nylas, AI services, storage, observability, or MCP OAuth clients. Never commit real secrets.
Start local services
Use the root scripts for the common workflows:
# Start the CRM web app and API app
pnpm dev:local
# Start all configured apps in the monorepo
pnpm dev
# Start the documentation app from apps/docs
pnpm --dir apps/docs dev
Default local URLs:
| Surface | URL | Notes |
|---|
| CRM app | http://localhost:3000 | Authenticated product UI. |
| API app | http://localhost:3002 | Internal API routes, webhooks, workflows, and MCP endpoint. |
| Docs app | http://localhost:3004 | Mintlify documentation preview. |
Work with API routes
Most product API routes live in apps/api/app/api, and provider webhook routes live in apps/api/app/webhooks. API routes are not guaranteed to share a global response envelope, pagination model, or public /v1 path.
Before documenting or consuming a route:
- Confirm the file exists in
apps/api/app.
- Read the route handler for its auth expectations.
- Check nearby tests or OpenAPI artifacts when present.
- Verify request and response examples against the implementation.
- Keep route files thin: auth and request parsing in the route, shared behavior in packages.
Authentication patterns
Web app to API app
When the web app calls the separate API app, forward the session token as a bearer token:
const token = await session.getToken();
await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/people`, {
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
});
In apps/api routes, read that bearer token with getAuthFromRequest(request) and scope data access to the returned orgId.
import { getAuthFromRequest } from '@/lib/auth-helper';
export async function GET(request: Request) {
const { userId, orgId } = await getAuthFromRequest(request);
if (!(userId && orgId)) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
// Query data using organizationId: orgId
}
MCP OAuth
The OAuth endpoints in apps/api/app/oauth support MCP-style OAuth 2.1 with PKCE. They are not a replacement for a general public developer portal.
| Method | Path | Purpose |
|---|
GET | /oauth/authorize | Creates a short-lived authorization code after validating a known client, redirect URI, and PKCE challenge. |
POST | /oauth/token | Exchanges the authorization code and code verifier for a one-hour JWT access token. |
Verify your changes
Run the checks that match the area you changed:
# Docs link check
pnpm --dir apps/docs lint
# Docs runtime build placeholder used by this repo
pnpm --dir apps/docs build
# OpenAPI validation, if you touch the generated spec
pnpm --dir apps/docs exec mintlify openapi-check api-reference/openapi.json
# Full monorepo tests when changing product behavior
pnpm test
Troubleshooting
API requests return 401 locally
- Confirm
NEXT_PUBLIC_API_URL points at http://localhost:3002 in the web app.
- Confirm the frontend forwards
Authorization: Bearer <token>.
- Confirm the API route uses
getAuthFromRequest(request) instead of same-server auth() when it is called from apps/app.
Webhooks do not fire locally
- Confirm the provider webhook URL points to your reachable API app URL.
- Confirm provider signature validation is configured for the environment you are testing.
- Confirm the route returns the provider-specific response shape, such as TwiML for Twilio flows.
Docs link check fails
Run pnpm --dir apps/docs lint and fix links to pages that exist in apps/docs/mint.json or the docs filesystem. Use relative docs paths such as /communication/phone or /development rather than stale template links.