* chore: update Google Fonts to Bricolage Grotesque, IBM Plex Sans, JetBrains Mono Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: update Tailwind config to Slate & Ice theme colors and fonts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: update CSS variables and glass-card utilities for Slate & Ice theme - Replace all color variables with Slate & Ice palette - Add glass system vars (--glass-bg, --glass-blur, --shadow-float) - Replace legacy glass-card with new variable-driven glass classes - Add breatheGlow, bellWobble, slideDown, fadeInRight keyframes - Update font references to IBM Plex Sans and Bricolage Grotesque Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: recolor BrandLogo to cyan gradient, split BrandWordmark for gradient Flow text Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: update TopBar with glassmorphism backdrop and cyan accent styling Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: update Sidebar with glassmorphism backdrop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add ambient atmosphere gradient orbs behind app shell Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: update QuickStats and SessionsPanel with glass-card styling Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add WeeklyCalendar, QuickActions, OpenSessions, RecentActivity dashboard components Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: redesign dashboard layout with calendar, open sessions, and glass-card panels New layout: greeting → calendar+actions → sessions+stats → activity Replaces old QuickStats and SessionsPanel with new dashboard components Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: replace remaining purple hex references with ice-cyan accent Sweep of hardcoded purple hex values (#818cf8, #6366f1) replaced with new cyan accent (#06b6d4) in QuickActions, RecentActivity, QuickLaunch, and SVG brand assets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: update CLAUDE.md branding and design system for Slate & Ice Modern Updated Last Updated date, branding section (fonts, colors, glass utilities, atmosphere orbs), component styling rules, and Design System section to reflect the new ice-cyan glassmorphism theme. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add Slate & Ice Modern design doc and implementation plan Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: redesign login page with Slate & Ice Modern design system Apply glassmorphism styling, atmosphere orbs, branded wordmark, and consistent design tokens to match the updated app shell aesthetic. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: raise TopBar z-index so profile dropdown renders above main content Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add AI assistant with in-session copilot and standalone chat with RAG Implements three-phase AI assistant feature: - Phase 0: RAG infrastructure with pgvector embeddings, Voyage AI integration, tree chunking service, and semantic search over team's flow library - Phase 1: In-session copilot panel during flow navigation with contextual AI help, current step awareness, and suggested related flows - Phase 2: Standalone AI chat page with persistent conversation history, pin/delete, and configurable retention policies (account-level) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add account management, email verification, AI fixes, and user guides - Profile settings, account transfer, delete/leave account flows - Email verification with JWT tokens and Resend integration - AI assistant/copilot fixes: markdown rendering, shared RAG helpers, token tracking, input refocus, model_validate usage - User guides hub + detail pages with 13 topic guides - Sidebar and top bar navigation for guides Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: prevent stale chunk errors after deployments - Set Cache-Control no-cache on index.html in nginx so browsers always fetch fresh chunk references after a deploy - Auto-reload on chunk load failures (stale deploy detection) with loop prevention via sessionStorage - Show friendly "App Updated" message if auto-reload doesn't resolve it Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add email verification toggle to admin settings Adds platform-level toggle to enable/disable email verification. When disabled, the verification banner is hidden and the send endpoint returns 403. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
130 lines
4.5 KiB
Python
130 lines
4.5 KiB
Python
from pydantic_settings import BaseSettings
|
||
from pydantic import field_validator
|
||
from typing import Optional
|
||
|
||
|
||
_DEFAULT_SECRET_KEY = "your-secret-key-change-in-production-use-openssl-rand-hex-32"
|
||
|
||
|
||
class Settings(BaseSettings):
|
||
# Application
|
||
APP_NAME: str = "ResolutionFlow"
|
||
DEBUG: bool = False
|
||
API_V1_PREFIX: str = "/api/v1"
|
||
|
||
# Database - Railway provides DATABASE_URL, we convert it for asyncpg
|
||
DATABASE_URL: str = "postgresql+asyncpg://postgres:postgres@localhost:5432/patherly"
|
||
|
||
@field_validator("DATABASE_URL", mode="before")
|
||
@classmethod
|
||
def convert_database_url(cls, v: str) -> str:
|
||
"""Convert standard postgres URL to asyncpg format."""
|
||
if v.startswith("postgresql://"):
|
||
return v.replace("postgresql://", "postgresql+asyncpg://", 1)
|
||
return v
|
||
|
||
@property
|
||
def DATABASE_URL_SYNC(self) -> str:
|
||
"""Get sync URL by removing asyncpg prefix from DATABASE_URL."""
|
||
return self.DATABASE_URL.replace("postgresql+asyncpg://", "postgresql://", 1)
|
||
|
||
# JWT Settings
|
||
SECRET_KEY: str = _DEFAULT_SECRET_KEY
|
||
|
||
@field_validator("SECRET_KEY", mode="after")
|
||
@classmethod
|
||
def reject_default_secret_in_production(cls, v: str, info) -> str:
|
||
"""Fail loudly if the default secret key is used outside of DEBUG mode."""
|
||
debug = info.data.get("DEBUG", False)
|
||
if v == _DEFAULT_SECRET_KEY and not debug:
|
||
raise ValueError(
|
||
"SECRET_KEY must be set to a secure value in production. "
|
||
"Generate one with: openssl rand -hex 32"
|
||
)
|
||
return v
|
||
ALGORITHM: str = "HS256"
|
||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 5
|
||
REFRESH_TOKEN_EXPIRE_DAYS: int = 7
|
||
|
||
# Security
|
||
BCRYPT_ROUNDS: int = 12
|
||
|
||
# Registration
|
||
REQUIRE_INVITE_CODE: bool = True # Set to False to allow open registration
|
||
|
||
# Email (Resend)
|
||
RESEND_API_KEY: Optional[str] = None
|
||
FROM_EMAIL: str = "ResolutionFlow <invites@resolutionflow.com>"
|
||
FEEDBACK_EMAIL: Optional[str] = None
|
||
|
||
@property
|
||
def email_enabled(self) -> bool:
|
||
"""Check if email sending is configured."""
|
||
return self.RESEND_API_KEY is not None
|
||
|
||
# Stripe
|
||
STRIPE_SECRET_KEY: Optional[str] = None
|
||
STRIPE_PUBLISHABLE_KEY: Optional[str] = None
|
||
STRIPE_WEBHOOK_SECRET: Optional[str] = None
|
||
|
||
@property
|
||
def stripe_enabled(self) -> bool:
|
||
"""Check if Stripe is configured."""
|
||
return self.STRIPE_SECRET_KEY is not None and self.STRIPE_WEBHOOK_SECRET is not None
|
||
|
||
# AI Flow Builder
|
||
ANTHROPIC_API_KEY: Optional[str] = None
|
||
AI_MODEL: str = "claude-haiku-4-5-20251001"
|
||
AI_CONVERSATION_TTL_HOURS: int = 24
|
||
AI_MAX_CALLS_PER_FLOW: int = 10
|
||
AI_REQUEST_TIMEOUT_SECONDS: int = 45
|
||
# AI Provider selection
|
||
AI_PROVIDER: str = "gemini" # "gemini" or "anthropic"
|
||
GOOGLE_AI_API_KEY: Optional[str] = None
|
||
AI_MODEL_GEMINI: str = "gemini-2.5-flash"
|
||
AI_MODEL_ANTHROPIC: str = "claude-haiku-4-5-20251001"
|
||
|
||
# Embedding / RAG
|
||
VOYAGE_API_KEY: Optional[str] = None
|
||
EMBEDDING_MODEL: str = "voyage-3.5"
|
||
EMBEDDING_DIMENSIONS: int = 1024
|
||
|
||
@property
|
||
def ai_enabled(self) -> bool:
|
||
"""Check if any AI provider is configured."""
|
||
return self.ANTHROPIC_API_KEY is not None or self.GOOGLE_AI_API_KEY is not None
|
||
|
||
# Deployment – auto-seed test data on PR environments
|
||
SEED_ON_DEPLOY: bool = False
|
||
|
||
# CORS - set FRONTEND_URL in production (e.g., https://patherly.up.railway.app)
|
||
CORS_ORIGINS: list[str] = ["http://localhost:3000", "http://localhost:5173", "http://localhost:5174"]
|
||
FRONTEND_URL: Optional[str] = None
|
||
# Allow all Railway PR environments (set to True in Railway env vars)
|
||
ALLOW_RAILWAY_ORIGINS: bool = False
|
||
|
||
@property
|
||
def allowed_origins(self) -> list[str]:
|
||
"""Get all allowed CORS origins including FRONTEND_URL if set."""
|
||
origins = self.CORS_ORIGINS.copy()
|
||
if self.FRONTEND_URL and self.FRONTEND_URL not in origins:
|
||
origins.append(self.FRONTEND_URL)
|
||
return origins
|
||
|
||
def is_origin_allowed(self, origin: str) -> bool:
|
||
"""Check if an origin is allowed, including Railway wildcard pattern."""
|
||
if origin in self.allowed_origins:
|
||
return True
|
||
# Allow any *.up.railway.app origin for PR environments
|
||
if self.ALLOW_RAILWAY_ORIGINS and origin.endswith(".up.railway.app"):
|
||
return True
|
||
return False
|
||
|
||
class Config:
|
||
env_file = ".env"
|
||
case_sensitive = True
|
||
extra = "ignore" # Ignore extra env vars like DATABASE_URL_SYNC
|
||
|
||
|
||
settings = Settings()
|