Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
229 lines
7.9 KiB
JSON
229 lines
7.9 KiB
JSON
{
|
|
"agent": "02",
|
|
"title": "Plans/packages/permissions extension points",
|
|
"sibling_docs_status": "docs/plan-permissions/ empty at write time (no 01-* / 03-* yet)",
|
|
"recommended_approach": "Extend Entitlements + Plan/UpsertPlan + AssertCanStartProcessing-style gates; expose via CreditsOverview/me; admin billing UI; do not add a parallel packages/permissions system.",
|
|
"extension_points": [
|
|
{
|
|
"priority": 1,
|
|
"role": "capability_source_of_truth",
|
|
"path": "apps/api/internal/billing/entitlements.go",
|
|
"symbols": [
|
|
"Entitlements",
|
|
"ComputeEntitlements",
|
|
"EntitlementsForCompany",
|
|
"IsFreePlanName",
|
|
"ProcessingTypeRequiresAI",
|
|
"ProcessingTypeRequiresEPREL"
|
|
],
|
|
"intent": "Add plan feature/section booleans here; keep pure ComputeEntitlements testable."
|
|
},
|
|
{
|
|
"priority": 1,
|
|
"role": "plan_catalog_and_meters",
|
|
"path": "apps/api/internal/billing/service.go",
|
|
"symbols": [
|
|
"Plan",
|
|
"CreditsOverview",
|
|
"defaultPublicPlans",
|
|
"IsPublicProductPlan",
|
|
"EnsureDefaultPlans",
|
|
"ListPlans",
|
|
"ListPublicPlans",
|
|
"UpsertPlan",
|
|
"AssignPlan",
|
|
"ProvisionFreePlan",
|
|
"AssertCanStartProcessing",
|
|
"ProcessingGateOpts",
|
|
"AIBrandApplyAllowed",
|
|
"ConsumeCredits",
|
|
"EnsureDefaultCosts",
|
|
"EnterpriseUnlimitedCredits"
|
|
],
|
|
"intent": "Extend Plan fields / defaults; SKU+AI gates; wallet assignment; public vs deal listing."
|
|
},
|
|
{
|
|
"priority": 1,
|
|
"role": "schema",
|
|
"path": "apps/api/sql/schema/001_platform.sql",
|
|
"symbols": ["plans", "company_plans", "credit_balances", "processing_costs", "billing_cycles"],
|
|
"intent": "Add feature/permission columns or JSON on plans; optionally wire unused custom_monthly_credits / custom_max_products."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "schema_stripe",
|
|
"path": "apps/api/sql/schema/016_stripe_billing.sql",
|
|
"symbols": ["company_plans.stripe_subscription_id", "company_plans.stripe_price_id"],
|
|
"intent": "Preserve Stripe linkage when altering company_plans."
|
|
},
|
|
{
|
|
"priority": 1,
|
|
"role": "admin_http",
|
|
"path": "apps/api/internal/httpapi/billing_handlers.go",
|
|
"symbols": [
|
|
"handleListPlans",
|
|
"handleListPublicPlans",
|
|
"handleUpsertPlan",
|
|
"handleAssignPlan",
|
|
"handleAddCredits",
|
|
"handleCreditsOverview"
|
|
],
|
|
"intent": "Accept/return new plan permission fields on admin upsert and credits overview."
|
|
},
|
|
{
|
|
"priority": 1,
|
|
"role": "route_mount",
|
|
"path": "apps/api/internal/httpapi/server.go",
|
|
"symbols": ["Router", "RequirePlatformAdmin"],
|
|
"intent": "Keep /api/admin/plans* under platform admin; tenant /api/billing/plans public ladder."
|
|
},
|
|
{
|
|
"priority": 1,
|
|
"role": "processing_enforcement",
|
|
"path": "apps/api/internal/processing/pipeline.go",
|
|
"symbols": ["StartJob", "processOne"],
|
|
"intent": "Primary AssertCanStartProcessing + step AllowAI policy; add section asserts near StartJob."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "http_402_mapping",
|
|
"path": "apps/api/internal/httpapi/processing_handlers.go",
|
|
"symbols": ["handleStartProcessingJob", "planGateCode"],
|
|
"intent": "Reuse 402 + code mapping for new plan_gate errors."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "v1_process",
|
|
"path": "apps/api/internal/httpapi/v1_process_handlers.go",
|
|
"symbols": ["handleV1StartProcess", "startV1Jobs"],
|
|
"intent": "Same gate errors as SPA processing."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "seo_gate",
|
|
"path": "apps/api/internal/seo/service.go",
|
|
"symbols": ["Report", "Apply"],
|
|
"intent": "Section toggle for SEO AI; already uses EntitlementsForCompany + ConsumeCredits."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "seo_http",
|
|
"path": "apps/api/internal/httpapi/seo_handlers.go",
|
|
"symbols": [],
|
|
"intent": "Map billing insufficient / upgrade errors for SEO routes."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "campaigns_gate",
|
|
"path": "apps/api/internal/campaigns/generate_send.go",
|
|
"symbols": ["Generate"],
|
|
"intent": "Section toggle for campaign AI; already checks CanUseAI / IsFreePlan."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "brand_gate",
|
|
"path": "apps/api/internal/httpapi/brand_handlers.go",
|
|
"symbols": ["brandResponse", "AIBrandApplyAllowed"],
|
|
"intent": "Pattern for soft feature flag exposed to UI (ai_apply_allowed)."
|
|
},
|
|
{
|
|
"priority": 1,
|
|
"role": "admin_ui",
|
|
"path": "apps/web/src/routes/admin/billing/+page.svelte",
|
|
"symbols": ["createPlan", "assignPlan", "reload", "customPlanCount", "maxProductsLabel"],
|
|
"intent": "Add edit + permission toggles; send full Plan including id/max_products."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "admin_nav",
|
|
"path": "apps/web/src/lib/components/AdminNav.svelte",
|
|
"symbols": [],
|
|
"intent": "Entry to /admin/billing already present."
|
|
},
|
|
{
|
|
"priority": 1,
|
|
"role": "tenant_display_and_client_gates",
|
|
"path": "apps/web/src/lib/billing-display.ts",
|
|
"symbols": [
|
|
"canUseAIFromCredits",
|
|
"isFreePlan",
|
|
"isEnterprisePlan",
|
|
"isSelfServeCheckoutPlan",
|
|
"formatSkuCap",
|
|
"withUpgradeHint"
|
|
],
|
|
"intent": "Mirror new entitlement flags for UX gating/hints."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "tenant_types",
|
|
"path": "apps/web/src/lib/types.ts",
|
|
"symbols": [],
|
|
"intent": "Extend credits/plan TypeScript shapes."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "tenant_nav",
|
|
"path": "apps/web/src/lib/components/Nav.svelte",
|
|
"symbols": [],
|
|
"intent": "Optional hide/disable tabs from me.credits entitlements."
|
|
},
|
|
{
|
|
"priority": 2,
|
|
"role": "me_embedding",
|
|
"path": "apps/api/internal/httpapi/auth_handlers.go",
|
|
"symbols": ["handleMe"],
|
|
"intent": "Already embeds CreditsOverview; new flags flow to SPA automatically if added to struct."
|
|
},
|
|
{
|
|
"priority": 3,
|
|
"role": "seed_demo",
|
|
"path": "apps/api/cmd/seed-demo/main.go",
|
|
"symbols": ["EnsureDefaultPlans", "AssignPlan"],
|
|
"intent": "Keep Free=0 / Enterprise demo invariants when changing defaults."
|
|
},
|
|
{
|
|
"priority": 3,
|
|
"role": "migrator",
|
|
"path": "apps/api/cmd/migrator/main.go",
|
|
"symbols": ["loadPlans", "loadCompanyPlans"],
|
|
"intent": "Map new plan columns from MySQL if present."
|
|
},
|
|
{
|
|
"priority": 3,
|
|
"role": "missing_plans_repair",
|
|
"path": "apps/api/internal/billing/missing_plans.go",
|
|
"symbols": ["AssignPlanIfMissing", "PlanIDByName", "HasActivePlan"],
|
|
"intent": "Assignment helpers for tenants without active plans."
|
|
},
|
|
{
|
|
"priority": 3,
|
|
"role": "stripe_assign",
|
|
"path": "apps/api/internal/billing/stripe.go",
|
|
"symbols": ["applyPlanPurchase", "downgradeToFree", "CreateCheckoutSession"],
|
|
"intent": "Checkout must remain public-ladder-only; custom deals stay admin-assign."
|
|
},
|
|
{
|
|
"priority": 3,
|
|
"role": "tests",
|
|
"path": "apps/api/internal/billing/gate_test.go",
|
|
"symbols": [
|
|
"TestComputeEntitlements",
|
|
"TestDefaultPublicPlansEnterpriseUnlimited",
|
|
"TestDefaultPublicPlansFreeZeroCredits"
|
|
],
|
|
"intent": "Extend entitlement/default-plan tests for new flags."
|
|
}
|
|
],
|
|
"do_not_duplicate": [
|
|
"Separate packages table parallel to plans",
|
|
"Frontend-only permission checks without EntitlementsForCompany",
|
|
"New Free/paid heuristics outside IsFreePlanName / ComputeEntitlements",
|
|
"Second SKU limit path ignoring plans.max_products / AssertCanStartProcessing"
|
|
],
|
|
"unused_schema_to_consider": [
|
|
"company_plans.custom_monthly_credits",
|
|
"company_plans.custom_max_products"
|
|
]
|
|
}
|