- Add backend/app/core/scheduler.py with AsyncIOScheduler, CronTrigger-based
job registration, and _fire_maintenance_schedule to create batch sessions
- Wire scheduler.start()/load_all_schedules()/shutdown() into main.py lifespan
- Call register_schedule() in create_schedule endpoint after commit
- Call register_schedule()/unregister_schedule() in update_schedule based on is_active
- Add TreeShare to models/__init__.py so all SQLAlchemy mapper relationships
resolve before ORM queries in the scheduler context
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Server-side regex redaction masks IPs, emails, bearer/API tokens, and
UNC paths in exported session content. Redaction runs post-generation
and post-variable-resolution with fail-closed error handling. Frontend
gets a "Mask Sensitive Data" toggle in the export preview modal with
a summary of what was redacted. 24 unit tests passing, frontend build clean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The /debug/cors endpoint is now conditionally registered, preventing
information leakage about CORS configuration in production.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase B addresses 7 high-severity gaps from the permissions audit:
- B1: Enforce tree access check on session start via can_access_tree
- B2: Replace all inline permission helpers with centralized permissions.py
- B3: Fix require_engineer_or_admin to check is_team_admin before role
- B4: Add is_active field on User with enforcement in get_current_active_user
- B5: Add admin user management endpoints (list, get, role, team-admin, deactivate, activate)
- B6: Add rate limiting on auth/invite endpoints via slowapi (disabled in DEBUG)
- B7: Implement refresh token rotation with JTI-based revocation and meaningful logout
Also reduces access token TTL from 15 to 5 minutes and updates CLAUDE.md
with SaaS/MSP context for future planning sessions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CORS middleware was only using the regex pattern for *.up.railway.app
when ALLOW_RAILWAY_ORIGINS was enabled, ignoring the explicit allowed_origins
list that includes custom domains like app.patherly.com.
Now includes both allow_origins and allow_origin_regex so custom domains
work alongside Railway PR environments.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
Implements Phase 2.5 Step Library Foundation:
### Issues Completed
- #3 User Preferences - export format default setting
- #5 Step Categories - database table and seed data
- #6 Step Library - database schema and migrations
- #7 Step Library - CRUD API endpoints
- #8 Step Library - rating and review system
### Changes
**Backend:**
- Migration 007: step_categories table with 10 seeded global categories
- Migration 008: step_library, step_ratings, step_usage_log tables
- Full CRUD API for step categories (/api/v1/step-categories)
- Full CRUD API for step library (/api/v1/steps) with search, filters, ratings
- CORS support for Railway PR environments (ALLOW_RAILWAY_ORIGINS)
**Frontend:**
- User preferences store (Zustand + localStorage)
- Settings page at /settings with export format dropdown
- Default export format applied in SessionDetailPage
### Testing
- Tested in Railway PR environment
- Database seeded with 7 MSP troubleshooting trees
- All API endpoints verified working
- Add Dockerfiles for backend (FastAPI) and frontend (nginx)
- Add railway.toml configs with health checks
- Add .dockerignore files for optimized builds
- Update config.py to auto-convert Railway DATABASE_URL format
- Add FRONTEND_URL env var for production CORS
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>