# Migration & Rollout Plan

## Purpose & Audience

This document describes the migration from the current Grass JWT + email-allowlist auth model to the platform service's 16-step permission pipeline. It is intended for engineers planning, executing, or monitoring the rollout. For the architecture of the permission system itself, see [platform architecture](../architecture/platform.md). For operational procedures during rollout, see the [platform runbooks](runbooks/).

---

## Phase Overview

The platform service ships in 3 phases with an explicit dependency order. Each phase can be planned independently.

| Phase       | Scope                                | Effort          | Dependencies                      |
| ----------- | ------------------------------------ | --------------- | --------------------------------- |
| **Phase 1** | Core authorization (launch-blocking) | ~8-10 eng-weeks | Grass-to-tenant JWT claim mapping |
| **Phase 2** | 4 parallel streams (post-launch)     | 3-5 weeks each  | Phase 1                           |
| **Phase 3** | Post-product-market-fit features     | 1-3 weeks each  | Phase 2                           |

---

## Phase 1: Core Authorization

**Tables (18):** Tenant, TenantUser, User (additions), Module, Permission, Role, RolePermission, RoleInheritance, RoleExclusion, UserRole, UserPermission, PolicyCondition, AuditLog, PermissionChangeLog, Session, StepUpChallenge, SuperAdmin, AuditEncryptionKey

**Services:** AccessService, RoleService, PolicyService, SessionService, basic TenantService, AuditService

**Deliverables:**

- Permission resolution pipeline (16 steps)
- Redis caching + invalidation
- Audit log async pipeline with crypto-shredding
- Middleware integration (`apps/server`, `apps/search`)
- Seed data (modules, permissions, default roles)
- Proto definitions for `@coda/admin-api` + `@coda/api-common`
- ConnectRPC server setup (`apps/platform`)
- Named invariant tests for all security-critical pipeline steps

**Blocking dependency:** Grass-to-tenant JWT claim mapping must be resolved before implementation begins.

---

## Phase 2: Parallel Streams

These 4 streams run in parallel after Phase 1 is stable.

| Stream                     | Tables                                                                                                              | Effort    | What It Delivers                                                    |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------- | --------- | ------------------------------------------------------------------- |
| **A: Plans + Credits**     | Plan, PlanFeature, TenantPlan, AddOn, TenantAddOn, PlanCreditCost, CreditLedger, CreditEntry                        | 4-5 weeks | Plan tiers, credit metering, add-on system                          |
| **B: Full Multi-Tenancy**  | Invitation, TenantDomainAllowlist, TenantBranding, TenantSetting, Department, UserGroup, UserGroupMember, ScimToken | 3-4 weeks | Invitations, SCIM, groups, branding, domain auto-join               |
| **C: Compliance**          | ConsentRecord, PrivacyRequest, ExternalReference, DataClassification, JurisdictionConfig (seed)                     | 3-4 weeks | Consent, privacy requests, data classification, external references |
| **D: Resource Management** | ResourceShare, ResourceQuota, ResourceUsage, RateLimit, ChatAttachment                                              | 3-4 weeks | Sharing, quotas, rate limits, attachments                           |

---

## Phase 3: Post-Product-Market-Fit

| Feature                | Tables                                                | Effort  |
| ---------------------- | ----------------------------------------------------- | ------- |
| Promotions + Referrals | Promotion, PromotionCode, PromotionRedemption         | 3 weeks |
| Service Accounts       | ServiceAccount, ServiceAccountKey, ServiceAccountRole | 2 weeks |
| Webhooks               | Webhook, WebhookDelivery                              | 2 weeks |
| Access Requests        | AccessRequest                                         | 1 week  |

---

## Migration Cutover Sequence

### Pre-Cutover (While Building Phase 1)

1. **Bootstrap tenant and seed data.** Create the internal Orchard tenant in the new DB with default roles, permissions, and modules. One-time migration script, not a runtime operation.

2. **Migrate existing users.** Script reads current Grass JWT claims for all active users and creates `User` + `TenantUser` rows. Role mapping: `administrator` -> `admin`, `engineering` -> `power_user`, default -> `contributor`. Runs once against the existing Auth0/Grass user list.

3. **Shadow mode via feature flag.** Deploy `requirePermission` middleware in shadow mode behind a feature flag. In shadow mode:
   - The 16-step pipeline runs on every request
   - The result (GRANTED/DENIED) is logged but **not enforced**
   - The existing auth check (Grass JWT roles + email allowlist) continues to enforce
   - Comparison reveals **false denials** -- requests the new system would deny that the old system allows

4. **Resolve false denials.** Fix misconfigurations surfaced by shadow mode: missing role assignments, permissions not seeded, plan features not mapped. Run shadow mode for at minimum **1 week with zero false denials** before proceeding.

### Cutover

5. **Feature flag: enforce mode.** Flip the flag from shadow to enforce. The new middleware enforces; the old auth check is removed.

6. **Tenant-by-tenant rollout.** The feature flag is scoped per tenant:
   - Internal Orchard tenant first (1 week validation)
   - Beta external tenant (1 week validation)
   - All remaining tenants

7. **Remove old auth.** After 4 weeks of stable enforcement across all tenants with zero false denials: remove old auth middleware, remove the feature flag, delete `SEARCH_ADMIN_EMAILS` env var. Grass JWT roles are no longer consulted for authorization (still used for authentication).

---

## Kill Switch and Rollback

- **Kill switch:** If false denials spike after cutover, flip back to shadow mode in <30 seconds.
- **Rollback plan:** If the feature flag system itself fails, the middleware's default behavior is **fail-open to the old auth path** during the transition period (not fail-closed to the new system).
- **Old auth retention:** The old auth path must remain deployable (not deleted) for 2 weeks after cutover.

---

## Phase 1 Pipeline Stubs

The 16-step pipeline ships in Phase 1, but several steps depend on Phase 2 tables. These steps are **no-ops in Phase 1** controlled by individual feature flags:

| Step                          | Phase 2 Dependency                             | Phase 1 Behavior                                                                                                                                                                                | Feature Flag                     |
| ----------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
| Step 5 (consent + DPA)        | Phase 2C: `ConsentRecord`, `ExternalReference` | **Skip.** No consent enforcement. Log warning per-request.                                                                                                                                      | `PIPELINE_STEP_5_ENABLED=false`  |
| Step 6 (IP allowlist)         | Phase 2B: `TenantIpAllowlist`                  | **Skip.** No IP restriction.                                                                                                                                                                    | `PIPELINE_STEP_6_ENABLED=false`  |
| Step 12 (resource share)      | Phase 2D: `ResourceShare`                      | **Owner-only mode.** Only resource owner has access. Acceptable because Phase 1 does not ship dashboards/data sources. For chats: all chats are owner-only (matches current implicit behavior). | `PIPELINE_STEP_12_ENABLED=false` |
| Step 14 (data classification) | Phase 2C: `DataClassification`                 | **Skip.** No classification enforcement.                                                                                                                                                        | `PIPELINE_STEP_14_ENABLED=false` |
| Step 15 (step-up auth)        | Phase 2B: `StepUpChallenge`                    | **Skip.** No step-up requirements.                                                                                                                                                              | `PIPELINE_STEP_15_ENABLED=false` |

When the corresponding Phase 2 tables are deployed, flip the flag. Shadow mode can be used per-step as well.

---

## Success Metrics

### Phase 1 (Cutover)

| Metric                                | Target                                        |
| ------------------------------------- | --------------------------------------------- |
| False denial rate in shadow mode      | 0 for 1+ week before cutover                  |
| Permission check p99 latency (cached) | <5ms                                          |
| Permission check p99 latency (cold)   | <50ms                                         |
| Cache hit ratio                       | >90%                                          |
| Zero cross-tenant data leakage        | 0 events (any event triggers page + incident) |

### Phase 2 (Post-Launch)

| Metric                         | Target                                      |
| ------------------------------ | ------------------------------------------- |
| Credit metering accuracy       | 100% (every AI operation has a CreditEntry) |
| Rate limit false positive rate | <0.1%                                       |
| Quota enforcement accuracy     | 100% (no over-quota creates)                |
| Audit log completeness         | 99.99%                                      |

### Rollout Validation

Each rollout stage (internal -> beta -> all tenants) must validate:

1. Zero false denials for 1 week
2. Permission check latency within SLO targets
3. Audit log completeness
4. No increase in user-reported access issues
