Skip to Content
Architecture

Architecture & conventions

This page explains Magic Core’s overall structure and cross-service conventions — how the services divide work, which way dependencies are allowed to point, and what global steps every request passes through. For each service’s internals see Platform API and Agent Service.

Monorepo layout

Magic-Core/ ├── apps/ │ ├── gateway/ (3110) single public edge: streaming reverse proxy, edge Clerk auth + identity injection, rate limit, health-aware routing (zero DB) │ ├── platform-api/ (3111) main BFF: resumes, users, collaboration, notifications, stats, analytics, webhooks, auth, billing/subscription, admin pool console │ ├── agent-service/ (3112) AI service: chat / translation / interview / PDF parse / agent runs (DeepAgents engine) │ ├── relay/ (3113) OpenAI-compatible relay over the CLIProxyAPI account pool: /v1 chat, rate limit, wallet/credit billing, channel failover + circuit breaker │ ├── keeper/ (3114) account-pool worker: usage ingest → keeper_usage_events, auth-file/api-key mirror, hourly/daily aggregation, model-price sync, quota probing │ └── docs/ this documentation site (Nextra) └── packages/ ├── db/ @magic/db Prisma schema + PrismaService (single DB entry point) ├── shared/ @magic/shared cross-cutting infra (its barrel eager-requires @magic/db) ├── util/ @magic/util zero-dependency primitives (hash, errorMessage, guards, num/json/record/time) ├── openai-compat/ @magic/openai-compat OpenAI-compatible protocol helpers (relay + agent-service) ├── cliproxy/ @magic/cliproxy CLIProxyAPI contract types + management transport (keeper + platform-api) └── testing/ @magic/testing test helpers (devDependency only)

Dependency direction (hard rules)

gateway ──────┐ platform-api ─┤ agent-service ┼─→ @magic/shared ─→ @magic/db relay ────────┤ keeper ───────┘ @magic/util zero-dep leaf — importable anywhere, depends on nothing @magic/openai-compat imported by relay + agent-service @magic/cliproxy imported by keeper + platform-api @magic/testing referenced only by each app's tests (devDependency)
  • Apps never import each other: they interact only through HTTP contracts, never shared code.
  • @magic/shared depends on no app, and on no domain package other than @magic/db. Its barrel eager-requires @magic/db, so importing anything from @magic/shared pulls Prisma in — reach for @magic/util when you only need a dependency-free primitive (this is why the DB-less gateway can stay lean).
  • DB access goes only through @magic/db: business code injects PrismaService rather than new PrismaClient().

Violating the dependency direction is something code review must block.

The shared packages

PackageWhat goes inWhat doesn’t
@magic/dbPrismaService, PrismaModule, schema.prisma + migrationsbusiness logic, domain rules
@magic/sharedauth guard, health checks, Redis, DynamicConfigService, interceptors / middleware / logging, the response envelopeanything only one app uses (keep it app-local)
@magic/utilzero-dependency primitives: sha256/hashToken, errorMessage, isRecord/asRecord, num/json/record/time helpersanything with a runtime dependency — keep it dep-free
@magic/openai-compatOpenAI-compatible SSE parse, usage/content extraction, chat/models URL build & normalizeprovider-specific business logic
@magic/cliproxyCLIProxyAPI management contract types + the cliproxyManagementRequest() transportapp-specific pool/usage logic
@magic/testingbuildTestApp, mock Prisma/Redis/Config, Testcontainers fixturesproduction code (always a devDependency)

Decide “does it belong in @magic/shared?” by: only if multiple apps use it or it’s a framework-level cross-cutting concern. Dependency-free primitives go in @magic/util instead, so consumers don’t drag Prisma in through the shared barrel.

Request lifecycle

The Nest data-plane apps (platform-api / agent-service / relay / keeper) share one global pipeline, assembled from @magic/shared in each main.ts. (The gateway is an Express edge with its own middleware chain, not this pipeline.)

  1. Global prefix /api — every route lives under /api; Swagger UI is at /api/docs. relay additionally serves the OpenAI-compatible /v1.
  2. Validation: a global ValidationPipe({ transform: true, whitelist: true }) — DTOs declared with class-validator; unknown fields are stripped.
  3. Auth: ClerkAuthGuard accepts a Clerk session JWT or a Personal Access Token (mr_pat_…); @Public() bypasses it (webhooks, analytics ingest), @Roles() does RBAC (defaults to admin when absent). relay authenticates /v1 with mr_rk_ relay keys instead.
  4. Response envelope: successful responses are wrapped by the global TransformInterceptor into { code, data, message, timestamp } — controllers return raw data.
  5. Exceptions: domain exceptions extend DomainException; the global HttpExceptionFilter maps them to the right HTTP status (e.g. ConflictDomainException → 409).
  6. Observability: AccessLoggerMiddleware records access logs; x-request-id flows through the request context.

Webhook exception: /api/webhooks/* preserves the raw request body for svix signature verification — don’t move webhook routes off that prefix.

Data model (~52 tables, grouped by domain)

All models live in packages/db/prisma/schema.prisma and are accessed only through Prisma:

  • Resume core: Resume (with a revision optimistic lock), ResumeVersion, Collaboration, Comment
  • Users / auth: User, PersonalAccessToken, SignInEvent, WebhookEvent (idempotency ledger), ClerkUserMirror / ClerkDailyActivity / ClerkMetricSnapshot
  • Billing / subscription: Plan, Subscription, Order, PaymentEvent, CreditWallet, CreditTransaction, BillingOperation, UsageLedger
  • AI quota: AiQuotaCounter, AiQuotaReservation
  • Reconciliation: ReconciliationRun, ReconciliationAction
  • Relay (account-pool front): RelayApiKey, RelayChannel
  • Keeper (account-pool worker): KeeperCpaApiKey, KeeperUsageIdentity, KeeperUsageInbox, KeeperUsageEvent, KeeperUsageOverviewHourlyStat / …DailyStat, KeeperUsageHealthStat, ModelPriceSetting, AggregationCheckpoint
  • Config: AppConfig
  • Notifications / feedback: Notification, Feedback
  • Analytics: AnalyticsEvent / AnalyticsEventV2 / …Daily, AnalyticsError / AnalyticsErrorGroup / …Daily, AnalyticsFunnel, AnalyticsPerf / …Daily, SourcemapAsset
  • Observability / ops: AccessLog, IpRule
  • Agent run trace: AgentRunAgentStepAgentEvent

All apps share one Postgres, but only platform-api runs migrations at boot (prisma migrate deploy); the other apps deliberately do not, to avoid concurrent migration races on the shared database.

Last updated on