# 10 — Backend enforcement + integration (agent 10/10) ## Status **Enforcement wired** for the highest-risk mutating surfaces. Focused resolve/default/custom/global tests added. Docs index: [README.md](./README.md). Claim gate: run `verify` / `finish_check` after tests in this session. --- ## What was enforced | Surface | Keys checked | Where | |---------|--------------|--------| | Processing `StartJob` | `FeatureKeysForProcessingType` (AI / EPREL / normalize / campaign AI) | `processing/pipeline.go` → `AssertProcessingFeatures` | | Campaign AI generate | `capability.campaign_ai`, `marketing.campaigns.generate_ai` | `campaigns/generate_send.go` | | Campaign live send | `capability.email_live_send`, `marketing.campaigns.send` | `campaigns/generate_send.go` (non–dry-run) | | SEO AI apply | `capability.seo_ai_rewrite`, `marketing.seo.ai_rewrite` | `seo/service.go` | | API key create | `settings.api_keys`, `capability.api_access` | `httpapi/apikey_handlers.go` | | Email blast send | `capability.email_live_send`, `integrations.email.blast` | `httpapi/email_handlers.go` | | Brand AI inject | `capability.brand_ai_apply`, `marketing.brand_ai_apply` | `AIBrandApplyAllowed` | HTTP: `writePlanGate` + `RequireFeature` middleware (`httpapi/plan_gate.go`). Processing / SEO / campaigns / v1 process map `ErrFeatureDisabled` → **402** with `code=plan_gate`, `error=feature_disabled`, optional `feature`. Helpers: `FeatureKeyFromError`, `AssertFeatures`, `FeatureKeysForProcessingType` in `billing/feature_enforcement.go`. --- ## Tests added `apps/api/internal/billing/feature_enforcement_test.go`: - Free defaults deny AI / API keys - Custom / Enterprise enable-all - Global section disable-all (marketing off) - Custom override false wins - Capability resolution Starter vs Growth BYOK - Feature key extraction + processing-type map Existing: `features_api_test.go`, `custom_package_features_test.go`, `plan_features_handlers_test.go`. --- ## Glue confirmed from siblings - Migration `026_plan_features.sql` - Routes mounted in `server.go` (capabilities, plan features, feature-gates, enable/disable-all) - `EnsureDefaultFeatureSeeds` called from `EnsureDefaultPlans` - CreditsOverview /auth/me embed effective features - Admin Permissions UI + dashboard gating docs present --- ## Remaining blockers 1. **Migrate required** — writes to `plans.features` / `platform_feature_gates` need `026` applied (`.\scripts\migrate.ps1`). Resolve falls back without column but admin PUT fails closed with a clear error. 2. **Not every route is AssertFeature'd** — list/read endpoints and many store/feed mutations are still UI-gated only. Extend using `RequireFeature` or `AssertFeature` when a section is product-critical. 3. **OpenAPI** — session fragment lives in `05-openapi-fragment.yaml`; public `/api/v1/openapi.yaml` intentionally unchanged. Optional: merge fragment into internal docs. 4. **Numeric marketing limits** (feed source count, export count, storage GB) remain documentation-only — not feature keys with counters. 5. **Agent 9 UI** — confirm live that nav hides after capabilities load; stub mode in admin UI should clear once APIs return 200. 6. **EPREL** — `capability.eprel` is ON for Free in the matrix; product docs historically disagreed with code (`CanUseEPREL` always true). Align product copy separately. --- ## Files touched (agent 10) | File | Intent | |------|--------| | `billing/feature_enforcement.go` | Assert helpers + processing key map | | `billing/feature_enforcement_test.go` | Defaults / custom / global / resolve tests | | `billing/service.go` | Brand AI feature check | | `processing/pipeline.go` | Assert before meter gate | | `campaigns/generate_send.go` | Generate AI + live send | | `seo/service.go` | SEO AI apply | | `httpapi/plan_gate.go` | 402 writer + `RequireFeature` | | `httpapi/processing_handlers.go` / `v1_process_handlers.go` | Feature 402 | | `httpapi/seo_handlers.go` / `campaigns_handlers.go` | Feature 402 | | `httpapi/apikey_handlers.go` / `email_handlers.go` | Create/send gates | | `docs/plan-permissions/README.md` | System index | | `docs/plan-permissions/10-enforcement.md` | This note |