Files
resolutionflow/backend/app/core/config.py
chihlasm 9462d8b15a feat: procedural editor redesign with collapsible sections and DnD (#84)
* docs: add procedural/maintenance editor redesign design

Collapsible sections, fixed-height layout, drag-to-reorder steps,
maintenance schedule section, and step list UX improvements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add procedural editor redesign implementation plan

7 tasks across 7 phases: collapsible sections, fixed-height layout,
step list improvements, drag-to-reorder, maintenance schedule section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: restructure procedural editor with collapsible sections and fixed-height layout

Convert scrolling document layout to fixed-height editor with accordion-mode
collapsible sections for Details and Intake Form. Step list now gets all
remaining height with independent scrolling. Add CollapsibleEditorSection
component with ARIA attributes (aria-expanded, aria-controls).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add step count with time estimate header and auto-scroll to new steps

Remove outer card wrapper from StepList (now rendered in scrolling container).
Header shows total estimated minutes when steps have time estimates. Auto-scrolls
to newly added steps using ref + scrollIntoView.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add drag-to-reorder steps with @dnd-kit

Wrap step list in DndContext + SortableContext. Each step/section header
gets a SortableStepWrapper with useSortable. Drag handles have accessible
labels and keyboard support. procedure_end stays non-draggable and always
last. Expanded steps are disabled for dragging. Array-index reorder only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add MaintenanceScheduleSection with schedule builder and summary

Schedule draft state is local UI only (not in store). Hydrates form from
existing schedule on load. Includes getScheduleSummary helper for collapsed
section display. Two-stage save: tree first, schedule second. Schedule
failure shows actionable error without rolling back tree save.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: wire maintenance schedule section into procedural editor

Add collapsible Schedule section for maintenance flows with accordion
integration. Schedule summary shows frequency, time, and target count
when collapsed. New maintenance flows default to schedule section expanded.
Two-stage save preserved: tree saved first, schedule managed independently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve lint issues in maintenance schedule and editor page

Move getScheduleSummary to scheduleUtils.ts to satisfy react-refresh
only-export-components rule. Add onScheduleLoaded to useEffect deps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add design and implementation revision documents

Revision docs correct original plans: schedule persistence via API
endpoints (not tree_structure), array-index reorder (no display_order),
store minimum-one-step invariant, accordion mode, ARIA requirements,
and two-stage save orchestration with failure handling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: auto-seed PR environments with SEED_ON_DEPLOY flag

Release command now runs migrations + seeds test users when
SEED_ON_DEPLOY=true. Tree seeding runs as a background task
on startup via HTTP API. Everything is idempotent and non-fatal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add httpx to requirements for PR environment seeding

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: seed all flow types (v2, procedural, maintenance) on deploy

Runs seed_trees, seed_trees_v2, seed_procedural_flows, and
seed_maintenance_flows sequentially as background tasks when
SEED_ON_DEPLOY=true. Each script failure is non-fatal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: trigger redeploy for full seed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 08:39:25 -05:00

108 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
# 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()