feat(03-01): DB migrations, models, encryption service, and test scaffolds
- Add stripe and cryptography to shared pyproject.toml - Add recharts, @stripe/stripe-js, stripe to portal package.json (submodule) - Add billing fields to Tenant model (stripe_customer_id, subscription_status, agent_quota, trial_ends_at) - Add budget_limit_usd to Agent model - Create TenantLlmKey and StripeEvent models in billing.py (AuditBase and Base respectively) - Create KeyEncryptionService (MultiFernet encrypt/decrypt/rotate) in crypto.py - Create compute_budget_status helper in usage.py (threshold logic: ok/warning/exceeded) - Add platform_encryption_key, stripe_, slack_oauth settings to config.py - Create Alembic migration 005 with all schema changes, RLS, grants, and composite index - All 12 tests passing (key encryption roundtrip, rotation, budget thresholds)
This commit is contained in:
@@ -129,6 +129,58 @@ class Settings(BaseSettings):
|
||||
orchestrator_url: str = Field(default="http://localhost:8003")
|
||||
llm_pool_url: str = Field(default="http://localhost:8004")
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Encryption
|
||||
# -------------------------------------------------------------------------
|
||||
platform_encryption_key: str = Field(
|
||||
default="",
|
||||
description="Fernet key for BYO API key encryption (base64-encoded 32-byte key)",
|
||||
)
|
||||
platform_encryption_key_previous: str = Field(
|
||||
default="",
|
||||
description="Previous Fernet key retained for decryption during rotation window",
|
||||
)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Stripe
|
||||
# -------------------------------------------------------------------------
|
||||
stripe_secret_key: str = Field(
|
||||
default="",
|
||||
description="Stripe secret API key (sk_live_... or sk_test_...)",
|
||||
)
|
||||
stripe_webhook_secret: str = Field(
|
||||
default="",
|
||||
description="Stripe webhook endpoint signing secret (whsec_...)",
|
||||
)
|
||||
stripe_per_agent_price_id: str = Field(
|
||||
default="",
|
||||
description="Stripe Price ID for the per-agent monthly subscription plan",
|
||||
)
|
||||
portal_url: str = Field(
|
||||
default="http://localhost:3000",
|
||||
description="Portal base URL used in Stripe checkout success/cancel redirects",
|
||||
)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Slack OAuth
|
||||
# -------------------------------------------------------------------------
|
||||
slack_client_id: str = Field(
|
||||
default="",
|
||||
description="Slack OAuth app client ID",
|
||||
)
|
||||
slack_client_secret: str = Field(
|
||||
default="",
|
||||
description="Slack OAuth app client secret",
|
||||
)
|
||||
slack_oauth_redirect_uri: str = Field(
|
||||
default="http://localhost:3000/api/slack/callback",
|
||||
description="Slack OAuth redirect URI (must match Slack app config)",
|
||||
)
|
||||
oauth_state_secret: str = Field(
|
||||
default="",
|
||||
description="HMAC secret for signing OAuth state parameters (CSRF protection)",
|
||||
)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Application
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user