Skip to main content
Soundcheck is a monorepo spanning two client apps, an Encore.ts backend (api-events, including /mcp), an MCP SDK, an AI agent, and two cloud infrastructure planes. This page covers the whole-platform topology, the generated-client contract, the integration map, and the data-flow patterns. For api-events internals see api-events.

Platform topology

Clients authenticate with Clerk and call api-events (Encore.ts), the system of record on PostgreSQL. The service writes domain events transactionally, serves the public HTTP API and /mcp, and fans out notification delivery over GCP Pub/Sub. @soundcheck/mcp (mcp-ts/) is the catalog library; CheckAI drives the platform through those tools.

Two infrastructure planes

Both planes share one PostgreSQL database: api-events owns schema and migrations (api-events/src/db/schema.prisma, api-events/src/db/migrations/).

Environments


The generated-client contract

The web app never hand-writes API types. The chain is:
  1. api-events route contracts — Encore api() / api.raw() handlers and typed operation graphs in api-events/src/.
  2. npm run openapi:emit (in api-events/) renders OpenAPI 3.x from those contracts via scripts/openapi/emitOpenApi.ts. Path templates use Encore param names ({userId}, {organizationId}, {eventId}). swagger-typescript-api still derives method names such as v1UsersDetail; the path-param objects follow the Encore names ({ userId } not { id }). Query, header, body, and response shapes come from sibling openapiRoute() annotations. Encore’s typed api() cannot describe custom envelope shapes, which is why most handlers are api.raw. Named $ref schemas come from sibling openapiSchema() registrations.
  3. On PRs, api-events-deploy.yml openapi-parity emits and asserts path templates against Encore extract. On api-events/ pushes to dev/qa/main, docs-ci sync-openapi-spec re-emits and asserts path templates and $ref’d schema-catalog keys before auto-committing docs/openapi/soundcheck.json.
  4. web/scripts/generate-api-client.mjs reads docs/openapi/soundcheck.json and emits a typed TypeScript client via swagger-typescript-api. It runs automatically on the web app’s predev and prebuild scripts (skipping codegen when the output is newer than the spec).
Because the spec is emitted from the same TypeScript contracts that power the Encore HTTP API, backend and frontend types stay in lockstep. The e2e/ suite additionally enforces endpoint coverage — new API routes are expected to be exercised — so an unregistered or untested endpoint surfaces in CI rather than silently drifting. npm run openapi:parity in api-events/ compares the committed spec against live TS endpoint declarations extracted via AST (a self-check that emit and handlers have not drifted). Encore’s native OpenAPI export is not used — it cannot describe api.raw handlers.

Integration map

The API is the single boundary for third-party integration. External services either push in via signed webhooks or the API calls out through a dedicated service. Per project convention, third-party calls that would otherwise be made inline (HubSpot, Flex) are brokered through n8n, which posts results back to the API as webhooks.

Inbound webhooks

All webhook handlers live in api-events/src/webhooks/ and verify a provider signature or shared secret before doing any work.

Outbound integrations


Data-flow patterns

Direct Pub/Sub today; durable outbox as the target

The API currently mixes direct provider calls with direct Pub/Sub publication; it has no shared transactional outbox. Availability notification processors demonstrate independent channel/device fan-out with terminal inbox and notification audit records, while other consumers have different failure policies. An inbox alone does not make external effects exactly once. See api-events for the component map. The durable workflow contract selects among synchronous transactions, outbox delivery, database queues, reconciliation and resumable workflows. The feature assessment identifies current gaps and a sequenced end-state for durability and scalability.

UEF import & ingestion

The Universal Event Format (UEF) is the interchange shape for bringing external event data into the platform — file uploads and third-party imports are normalized to UEF, then reconciled against existing records. In-repo the import pipeline lives under api-events/src/systems/imports/; ingestion batches under api-events/src/systems/event-ingestions/. See api-events for the ingestion subsystem.

CI/CD

Workflows live in .github/workflows/ (e.g. api-events-deploy.yml, web-ci-cd.yml, docs-ci.yml, gcp-terraform-validate.yml).

Security model

  • Authentication — Clerk-issued JWTs from every client. Basic Auth is removed. See the API’s auth middleware.
  • Authorization — organization-scoped, role-based checks enforced in middleware and handlers; resource-level ownership checks in services.
  • Secrets — held in Azure Key Vault and surfaced to App Services as Key Vault references (not raw env vars).
  • Webhooks — every inbound webhook verifies a provider signature or HMAC shared secret before acting.
  • Fail-closed config — the API defaults ENVIRONMENT to production, so production validation applies unless development is explicitly opted into.