Skip to main content

Local mock environment

The CRM service depends on three external systems at runtime:

  1. Identity service — issues OAuth tokens and resolves /api/user / /api/policies for the VerifyOAuthToken + CheckPermission middleware.
  2. RabbitMQIdentityEventConsumer consumes 5 event types.
  3. Postgrestenant_crm schema, unaccent extension.

For routine UI / store / page work you don't want to spin up identity

  • RabbitMQ. This page documents the two support modes that let the SPA + backend run with stubs.

The vast majority of frontend changes need a working /api/crm/* endpoint that answers as if the request were authenticated. We ship a .env.test-style flag that lets the backend bypass real token validation and inject a fixed principal.

# tenant/tenant-backend-crm/.env
APP_ENV=local
CRM_FAKE_AUTH=true
CRM_FAKE_AUTH_USER_ID=01HFAKEUSER000000000000001
CRM_FAKE_AUTH_TENANT_ID=01HFAKETENANT00000000000001
CRM_FAKE_AUTH_IS_ADMIN=true

When CRM_FAKE_AUTH=true:

  • VerifyOAuthToken short-circuits and stuffs auth_user with the fake id / tenant_id / is_admin=true.
  • CheckPermission short-circuits on the is_admin flag (same path as production system-admin bypass).
  • No real identity call is made; IdentityService is NOT used.

Never enable CRM_FAKE_AUTH in staging or production. The middleware refuses to honor it when APP_ENV is not local. The artisan command crm:check-fake-auth-guard (run in CI) asserts the flag is false in any non-local config.

Mode B — Identity stub server

For end-to-end token-flow testing (login redirect, refresh token, policy update events) you DO need an identity-compatible endpoint. The bundled stub lives at:

tenant/tenant-backend-crm/dev/identity-stub.php

It's a 60-line PHP built-in-server script that serves:

RouteBehavior
GET /api/userReturns the fake principal payload
GET /api/policiesReturns one allow-all policy [{action: '*', effect: 'allow'}]
GET /.well-known/jwks.jsonReturns a static dev JWK pair
POST /oauth/tokenReturns a long-lived dev access_token

Run it:

cd tenant/tenant-backend-crm
php -S 127.0.0.1:8000 dev/identity-stub.php
# point IDENTITY_URL=http://127.0.0.1:8000 in your .env

Note: this stub does not implement RabbitMQ event publishing, so the CRM service won't see identity.policy.updated events. CheckPermission will rely on the 1-hour policy cache; restart the CRM service if you change policies in the stub.

Mode C — Skip the backend entirely (frontend MSW)

Not implemented yet. The SPA stores all go through axios; a future mock-service-worker integration would let the frontend dev server intercept /api/crm/* calls with fixtures. Tracking issue: see F2 in the audit doc.

Generated SDK refresh

After any backend OpenAPI change (route, request body, response shape), regenerate the typed SDK:

# 1) Export the OpenAPI spec from the backend
cd tenant/tenant-backend-crm
php artisan scramble:export --path=../tenant-frontend/openapi/crm.json

# 2) Re-run the @hey-api generator
cd ../tenant-frontend
npm run api:sync

# 3) Commit the changes
git add src/api/generated/crm/

CI runs npm run api:check on every PR — it asserts there's no uncommitted drift between the OpenAPI source and the generated client. If it fails, run steps 1-3 locally and commit.

What .env keys are read by which mode

ModeReadsReplaces
A (fake auth)CRM_FAKE_AUTH, CRM_FAKE_AUTH_*IDENTITY_URL, OAUTH_CLIENT_ID
B (identity stub)IDENTITY_URL=http://127.0.0.1:8000, OAUTH_CLIENT_ID=*— (real identity service)
C (MSW)The entire backend (not yet wired)