> ## Documentation Index
> Fetch the complete documentation index at: https://docs.soundchecklive.io/llms.txt
> Use this file to discover all available pages before exploring further.

# API Architecture

> Internal architecture of the Soundcheck api-events service

The Soundcheck API is an Encore.ts service (`api-events/`, port **4000**) that is the **system of record** for the platform. It serves the full public HTTP API, owns PostgreSQL DDL, publishes domain events directly to Pub/Sub, and delegates notification delivery to processors. For platform-wide topology, see [System Architecture](https://docs.soundchecklive.io/engineering/architecture.md).

## Layer overview

```
┌─────────────────────────────────────┐
│  endpoints/ + webhooks/ (Encore)    │  ← HTTP + webhook route declarations
├─────────────────────────────────────┤
│  middleware/                        │  ← auth, error capture, user context
├─────────────────────────────────────┤
│  systems/*/ + operations/           │  ← business logic per domain
├─────────────────────────────────────┤
│  db/ (Prisma)                       │  ← data access
├─────────────────────────────────────┤
│  PostgreSQL                         │
└─────────────────────────────────────┘
```

Encore `api(...)` declarations stay thin: validate auth, call an operation, return a DTO. Operations hold business logic and Prisma access. Pub/Sub follows the same split — `handlers/` wire topics to `processors/`.

***

## Directory structure

```
api-events/src/
├── encore.service.ts       # Bootstrap: middleware, migrate on boot
├── systems/                  # Domain modules (events, venues, ledger, …)
│   └── <domain>/
│       ├── *Operations.ts  # Routing-agnostic logic
│       └── endpoints/      # Encore api(...) declarations
├── operations/             # Shared / cross-domain HTTP logic
├── endpoints/              # cross-system endpoints
├── webhooks/               # Clerk, Stripe, Twilio, …
├── processors/             # Pub/Sub orchestrators + per-channel processors
├── handlers/               # new Subscription(...) wiring
├── events/ + topics/       # Pub/Sub event types and topic declarations
├── clients/                # Twilio, SendGrid, Expo, …
├── db/                     # Prisma client, schema, migrations, idempotency helpers
├── auth/                   # Clerk JWT verification
├── config/                 # Secrets + env-driven config
└── observability/          # Sentry, PostHog, analytics
```

Canonical DDL: `api-events/src/db/schema.prisma` + `api-events/src/db/migrations/`. Migrations apply on Encore boot and via `npm run db:migrate`.

***

## Authentication & authorization

Clerk session JWT is the only caller auth path. `ENABLE_BASIC_AUTH` is removed and fails closed if set. `/api/v1/admin/**` is parked and 404s.

**Provisioning.** Webhook and middleware paths ensure `User`, `Organization`, and membership rows exist before handlers run, closing the race where a request arrives before Clerk webhooks land.

**Organization authorization.** Access is organization-scoped and role-based. Handlers resolve org scope from the authenticated identity — never from untrusted URL or query params.

**Fail-closed config.** `ENVIRONMENT` must be set explicitly; production secret and CORS validation apply outside development.

***

## Subsystems

* **Pub/Sub notifications.** Operations currently publish directly; the business commit and publication are separate. A shared transactional outbox is the [target architecture](./async-durability-patterns). Pub/Sub processors render and deliver SMS, email, and push. See [api-events](https://docs.soundchecklive.io/engineering/backend/api-events.md) and the [feature assessment](./async-workflow-assessment).
* **Audit logging.** Sensitive mutations write to per-domain audit tables via dedicated operations.
* **Event-file ingestion (UEF).** Uploaded files and imports are extracted, analyzed, reviewed, and merged into events. Logic lives under `systems/event-ingestions/`.
* **HubSpot ↔ Flex pipeline (via n8n).** Deal-stage and quote sync runs through n8n webhooks back into api-events.
* **Admin org-config console.** Staff surfaces for seat/onboarding and entitlement grants under org-scoped admin routes.
* **Portal auth.** Client-portal contacts authenticate through Clerk but are scope-resolved server-side so staff and portal sessions cannot cross-read.

***

## Route registration

Every public path is declared as an Encore `api(...)` endpoint under `src/systems/*/endpoints/` or `src/webhooks/`. `api-events/routes.json` holds each route's domain override; unknown paths return Encore's native 404.

OpenAPI is emitted from Encore (`npm run openapi:emit`) and synced to `docs/openapi/soundcheck.json` for client codegen. The `e2e/` suite enforces endpoint coverage when `E2E_ENFORCE_COVERAGE=1`.

***

## Error handling

Errors return structured JSON with an HTTP status:

```json theme={null}
{
  "status": 400,
  "code": "INVALID_REQUEST",
  "message": "Event ID must be a valid UUID",
  "details": "received: 'invalid-id'"
}
```

| Code | HTTP Status | Use Case |
| - | - | - |
| `INVALID_REQUEST` | 400 | Malformed input or missing required fields |
| `VALIDATION_FAILED` | 400 | Validation logic failure |
| `NOT_FOUND` | 404 | Resource doesn't exist |
| `UNAUTHORIZED` | 401 | Missing or invalid authentication |
| `FORBIDDEN` | 403 | Authenticated but insufficient permissions |
| `CONFLICT` | 409 | Resource already exists |
| `DATABASE_ERROR` | 500 | Database operation failed |
| `SERVER_ERROR` | 500 | Unexpected server error |
| `EXTERNAL_SERVICE_ERROR` | 502/503 | External service unavailable |

***

## Best practices

* **Endpoints** — keep thin; delegate to operations; return appropriate status codes.
* **Operations** — own business logic and transactions; record required asynchronous intent durably according to the [workflow contract](./async-durability-patterns). A shared outbox remains future implementation work.
* **Migrations** — edit `api-events/src/db/schema.prisma` only; apply with `npm run db:migrate` or on boot.
* **Testing** — unit-test operations with mocked Prisma (`vi.mock`); integration tests against Postgres on `:5434`; e2e against `:4000`.

***

## Related docs

* [`api-events/README.md`](https://github.com/soundchecklive/soundcheck-mobile-app/blob/main/api-events/README.md) — canonical architecture and idempotency design.
* [api-events](https://docs.soundchecklive.io/engineering/backend/api-events.md) — notification fan-out and Pub/Sub processors.
* [API overview](https://docs.soundchecklive.io/engineering/backend/overview.md) — Encore.ts backend and local setup (Go removal complete).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.