# Service Integration Guide

## Purpose & Audience

This document describes how existing and new Coda services integrate with the platform service for authorization, entitlements, and graceful degradation. It is intended for engineers adding permission checks to services. For the platform service architecture itself, see [architecture](../architecture/platform.md). For the API reference, see [API reference](../api/platform.md).

---

## Integration Overview

Every API request in the system calls the platform service to resolve permissions before proceeding. Services communicate with the platform service via ConnectRPC over the internal VPC.

```
                    ConnectRPC (internal VPC, port 8082)

 apps/server ──────────────────┐
 (Express)                     |
                               v
 apps/search ─────────────┐   [Platform Service (Fargate)]
 (ConnectRPC)             |    |                          |
                          v    |  AccessService           |
 future services ────────────> |  TenantService           |
                               |  AuditService            |
                               |  RoleService             |
                               |                          |
                               └──────────────────────────┘
```

**Service discovery:** Services locate the platform service via environment variable:

```
PLATFORM_SERVICE_URL=http://platform.internal:8082
```

**Client package:** Import `@coda/admin-api` for permission checks.

---

## Main Server (`apps/server`)

### Middleware Chain

The middleware chain gains 4 new middleware functions:

```
Current:
  requestContext -> requestLogger -> requireAuth -> enrichRequestContext -> apiRateLimit -> snowflakeIdentity

New:
  requestContext -> requestLogger -> requireAuth -> resolveTenant -> resolveSession -> enrichRequestContext -> requirePermission -> rateLimitByPlan -> snowflakeIdentity
```

| New Middleware            | Responsibility                                                                         |
| ------------------------- | -------------------------------------------------------------------------------------- |
| `resolveTenant`           | Calls `AccessService.ResolveTenant` RPC. Attaches tenant + tenantUser to `res.locals`. |
| `resolveSession`          | Calls session tracking. Checks IP allowlist, consent via platform service.             |
| `requirePermission(perm)` | Calls `AccessService.Check` RPC. Returns 403 with structured error on denial.          |
| `rateLimitByPlan`         | Reads rate limits from platform service (cached). Replaces flat `apiRateLimit`.        |

### Tool Execution

In `apps/server/src/ai/tools/registry/execution.ts`, `executeToolWithHandlers` calls `AccessService.Check` before running each tool. Tool definitions gain a `permission` field:

```typescript
// Example: tool requires tools.snowflake.query permission
{ name: 'snowflake_query', permission: 'tools.snowflake.query', ... }
```

The `search_tools` meta-tool filters available tools by user permissions.

### Model Selection

In `apps/server/src/routes/stream-handler.ts`, model resolution calls `AccessService.Check` for `models.{slug}.use`. The `GET /api/v1/models` endpoint filters by user permissions.

### Client-Side Integration

New `GET /api/v1/me/permissions` endpoint calls `AccessService.GetEffective` and returns the user's effective permission set to the React client. A new `PermissionContext` provides `can(permission)` for UI gating.

Client-side checks are **UX only**. The server always enforces.

---

## Search Service (`apps/search`)

The search service has **no direct dependency** on the platform service at the RPC level. Instead:

- Replace `createAdminAuth(allowedEmails)` with a ConnectRPC interceptor that calls `AccessService.Check` for `admin.search.*` permissions
- Remove the email allowlist entirely (`SEARCH_ADMIN_EMAILS` env var deleted after cutover)

---

## Onboarding a New Service

Any new service integrates by importing `@coda/admin-api` and following these steps:

1. **Define permissions:** Add new module + permissions in seed data (`packages/admin-api` or `apps/platform` seed scripts)
2. **Seed existing tenants:** Run seed migration for existing tenants (migration script or admin RPC)
3. **Add middleware:** Create ConnectRPC clients, add `ResolveTenant` + `Check` middleware
4. **Write invariant tests:** One test per security-critical permission check
5. **Update runbooks:** Document new permissions and operational procedures

### Per-Request Pattern

```
1. ResolveTenant   (once per request, in middleware)
2. Check           (route-level or action-level permission checks)
3. GetEffective    (for UI preloading — one call, returns all permissions)
```

---

## Graceful Degradation

### What Happens When the Platform Service Is Down

The platform service is a critical dependency. If it is unreachable:

- **Aurora down:** Fail-closed (deny-all) per design principle 1. Redis cache serves hot-path reads for up to 30 seconds. After cache expiry, all permission checks deny. Users see: "Service temporarily unavailable."
- **Redis down:** Permission cache falls through to DB. Rate limits fail-closed (429). Credit deductions use atomic DB writes. Audit buffer falls back to application logs. Users see slightly elevated latency (5ms to 50ms).

### Upstream Dependency Degradation

Each external dependency has an explicit degradation strategy:

| Dependency          | Strategy                                                                                                       | User Impact                                           |
| ------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| **AWS Bedrock**     | Graceful degradation. Structured error returned. Chat input disabled. No credits consumed for failed requests. | Banner: "AI is temporarily unavailable."              |
| **Snowflake**       | Tool-level disable via circuit breaker. Other tools remain functional.                                         | Tool chip shows "Snowflake offline."                  |
| **GraphQL Gateway** | Same as Snowflake -- tool-level disable with circuit breaker.                                                  | Similar UX.                                           |
| **Grass/Auth0**     | Session continuity. Existing sessions continue (JWT validation is local). New logins fail.                     | Existing users unaffected. New users see login error. |
| **S3**              | Feature-level disable. File uploads/downloads fail. Audit archival pauses.                                     | "File uploads temporarily unavailable."               |
| **Notion API**      | Tool-level disable via circuit breaker.                                                                        | "Notion integration temporarily unavailable."         |

### SLA Composition

The critical path for core functionality:

```
User -> Auth (Grass/Auth0) -> Permission Check (Aurora + Redis) -> AI (Bedrock) -> Response
```

Composite availability = 99.99% x 99.99% x 99.9% = **~99.88%** (~63 minutes downtime/month)

| Tier         | Published SLA       | Covers                           |
| ------------ | ------------------- | -------------------------------- |
| Starter      | None (best-effort)  | --                               |
| Professional | 99.5% monthly       | Core functionality (auth + chat) |
| Business     | 99.9% monthly       | Core functionality + data tools  |
| Enterprise   | Custom (negotiated) | Core + tools + response time SLA |

### Circuit Breaker Pattern

All upstream dependencies use the circuit breaker pattern from `@coda/async`. Circuit breaker state is **per-dependency, per-tenant** (not global). See [Platform Architecture](../architecture/platform.md) for state diagrams, thresholds, and configuration.

---

## Event-Driven Communication

Domains communicate via an in-process event bus. See [Platform Architecture](../architecture/platform.md#event-bus) for event types, transport categories, and migration plans.

---

## Tenant-Facing Status

**Status page:** Public status page showing per-component status (Authentication, AI Chat, Data Tools, File Management, Search, Integrations).

**Admin dashboard:** Tenant admin dashboard includes a "System Health" widget showing current dependency status (green/yellow/red), estimated recovery time, and affected features.

**Webhooks:** Tenants with webhooks receive `system.degraded` and `system.recovered` events with affected components and estimated impact.
