Root cause: The demo data's model_params was missing `top_p`, but the Zod schema required all three fields (temperature, max_tokens, top_p). This caused silent validation failures when editing agent types. Fixes: 1. Add getInitialValues() that ensures all required fields have defaults 2. Handle nested validation errors in handleFormError (e.g., model_params.top_p) 3. Add useEffect to reset form when agentType changes 4. Add console.error logging for debugging validation failures 5. Update demo data to include top_p in all agent types The form now properly initializes with safe defaults for any missing fields from the API response, preventing silent validation failures.
Syndarix Backend API
The pragmatic, production-ready FastAPI backend for Syndarix.
Overview
Opinionated, secure, and fast. This backend provides the solid foundation you need to ship features, not boilerplate.
Features:
- Authentication: JWT with refresh tokens, session management, device tracking
- Database: Async PostgreSQL with SQLAlchemy 2.0, Alembic migrations
- Security: Rate limiting, CORS, CSP headers, password hashing (bcrypt)
- Multi-tenancy: Organization-based access control with roles (Owner/Admin/Member)
- Testing: 97%+ coverage with security-focused test suite
- Performance: Async throughout, connection pooling, optimized queries
- Modern Tooling: uv for dependencies, Ruff for linting/formatting, mypy for type checking
Quick Start
Prerequisites
- Python 3.12+
- PostgreSQL 14+ (or SQLite for development)
- uv - Modern Python package manager (replaces pip)
Installation
# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install all dependencies (production + dev)
cd backend
uv sync --extra dev
# Or use the Makefile
make install-dev
# Copy environment template
cp .env.example .env
# Edit .env with your configuration
Why uv?
- 🚀 10-100x faster than pip
- 🔒 Reproducible builds via
uv.locklockfile - 📦 Better dependency resolution
- ⚡ Built by Astral (creators of Ruff)
Database Setup
# Run migrations
python migrate.py apply
# Or use Alembic directly
alembic upgrade head
Run Development Server
# Using uv
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# Or activate environment first
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
API will be available at:
- API: http://localhost:8000
- Swagger Docs: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
Dependency Management with uv
Understanding uv
uv is the modern standard for Python dependency management, built in Rust for speed and reliability.
Key files:
pyproject.toml- Declares dependencies and tool configurationsuv.lock- Locks exact versions for reproducible builds (commit to git)
Common Commands
Installing Dependencies
# Install all dependencies from lockfile
uv sync --extra dev
# Install only production dependencies (no dev tools)
uv sync
# Or use the Makefile
make install-dev # Install with dev dependencies
make sync # Sync from lockfile
Adding Dependencies
# Add a production dependency
uv add httpx
# Add a development dependency
uv add --dev pytest-mock
# Add with version constraint
uv add "fastapi>=0.115.0,<0.116.0"
# Add exact version
uv add "pydantic==2.10.6"
After adding dependencies, commit both pyproject.toml and uv.lock to git.
Removing Dependencies
# Remove a package
uv remove httpx
# Remove a dev dependency
uv remove --dev pytest-mock
Updating Dependencies
# Update all packages to latest compatible versions
uv sync --upgrade
# Update a specific package
uv add --upgrade fastapi
# Check for outdated packages
uv pip list --outdated
Running Commands in uv Environment
# Run any Python command via uv (no activation needed)
uv run python script.py
uv run pytest
uv run mypy app/
# Or activate the virtual environment
source .venv/bin/activate
python script.py
pytest
Makefile Commands
We provide convenient Makefile commands that use uv:
# Setup
make install-dev # Install all dependencies (prod + dev)
make sync # Sync from lockfile
# Code Quality
make lint # Run Ruff linter (check only)
make lint-fix # Run Ruff with auto-fix
make format # Format code with Ruff
make format-check # Check if code is formatted
make type-check # Run mypy type checking
make validate # Run all checks (lint + format + types)
# Testing
make test # Run all tests
make test-cov # Run tests with coverage report
# Utilities
make clean # Remove cache and build artifacts
make help # Show all commands
Dependency Workflow Example
# 1. Clone repository
git clone <repo-url>
cd backend
# 2. Install dependencies
make install-dev
# 3. Make changes, add a new dependency
uv add httpx
# 4. Test your changes
make test
# 5. Commit (includes uv.lock)
git add pyproject.toml uv.lock
git commit -m "Add httpx dependency"
# 6. Other developers pull and sync
git pull
make sync # Uses the committed uv.lock
Troubleshooting uv
Dependencies not found after install:
# Make sure you're using uv run or activated environment
uv run pytest # Option 1: Run via uv
source .venv/bin/activate # Option 2: Activate first
pytest
Lockfile out of sync:
# Regenerate lockfile
uv lock
# Force reinstall from lockfile
uv sync --reinstall
uv not found:
# Install uv globally
curl -LsSf https://astral.sh/uv/install.sh | sh
# Add to PATH if needed
export PATH="$HOME/.cargo/bin:$PATH"
Development
Project Structure
app/
├── api/ # API routes and dependencies
│ ├── routes/ # Endpoint implementations
│ └── dependencies/ # Auth, permissions, etc.
├── core/ # Core functionality
│ ├── config.py # Settings management
│ ├── database.py # Database engine setup
│ ├── auth.py # JWT token handling
│ └── exceptions.py # Custom exceptions
├── crud/ # Database operations
├── models/ # SQLAlchemy ORM models
├── schemas/ # Pydantic request/response schemas
├── services/ # Business logic layer
└── utils/ # Utility functions
See docs/ARCHITECTURE.md for detailed architecture documentation.
Configuration
Environment variables (.env):
# Database
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your_password
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=app_db
# Security (IMPORTANT: Change these!)
SECRET_KEY=your-secret-key-min-32-chars-change-in-production
ENVIRONMENT=development # development | production
# Optional
BACKEND_CORS_ORIGINS=["http://localhost:3000"]
CSP_MODE=relaxed # strict | relaxed | disabled
# First superuser (auto-created on startup)
FIRST_SUPERUSER_EMAIL=admin@example.com
FIRST_SUPERUSER_PASSWORD=SecurePass123!
⚠️ Security Note: Never commit .env files. Use strong, unique values in production.
Database Migrations
We use Alembic for database migrations with a helper script:
# Generate migration from model changes
python migrate.py generate "add user preferences"
# Apply migrations
python migrate.py apply
# Generate and apply in one step
python migrate.py auto "add user preferences"
# Check current version
python migrate.py current
# List all migrations
python migrate.py list
Manual Alembic usage:
# Generate migration
alembic revision --autogenerate -m "description"
# Apply migrations
alembic upgrade head
# Rollback one migration
alembic downgrade -1
Testing
# Using Makefile (recommended)
make test # Run all tests
make test-cov # Run with coverage report
# Using uv directly
IS_TEST=True uv run pytest
IS_TEST=True uv run pytest --cov=app --cov-report=term-missing -n 0
# Run specific test file
IS_TEST=True uv run pytest tests/api/test_auth.py -v
# Run single test
IS_TEST=True uv run pytest tests/api/test_auth.py::TestLogin::test_login_success -v
# Generate HTML coverage report
IS_TEST=True uv run pytest --cov=app --cov-report=html -n 0
open htmlcov/index.html
Test Environment: Uses SQLite in-memory database. Tests run in parallel via pytest-xdist.
Code Quality
# Using Makefile (recommended)
make lint # Ruff linting
make format # Ruff formatting
make type-check # mypy type checking
make validate # All checks at once
# Using uv directly
uv run ruff check app/ tests/
uv run ruff format app/ tests/
uv run mypy app/
Tools:
- Ruff: All-in-one linting, formatting, and import sorting (replaces Black, Flake8, isort)
- mypy: Static type checking with Pydantic plugin
All configurations are in pyproject.toml.
API Documentation
Once the server is running, interactive API documentation is available:
-
Swagger UI: http://localhost:8000/docs
- Try out endpoints directly
- See request/response schemas
- View authentication requirements
-
ReDoc: http://localhost:8000/redoc
- Alternative documentation interface
- Better for reading/printing
-
OpenAPI JSON: http://localhost:8000/api/v1/openapi.json
- Raw OpenAPI 3.0 specification
- Use for client generation
Authentication
Token-Based Authentication
The API uses JWT tokens for authentication:
-
Login:
POST /api/v1/auth/login- Returns access token (15 min expiry) and refresh token (7 day expiry)
- Session tracked with device information
-
Refresh:
POST /api/v1/auth/refresh- Exchange refresh token for new access token
- Validates session is still active
-
Logout:
POST /api/v1/auth/logout- Invalidates current session
- Use
logout-allto invalidate all user sessions
Using Protected Endpoints
Include access token in Authorization header:
curl -H "Authorization: Bearer <access_token>" \
http://localhost:8000/api/v1/users/me
Roles & Permissions
- Superuser: Full system access (user/org management)
- Organization Roles:
Owner: Full control of organizationAdmin: Can manage members (except owners)Member: Read-only access
Common Tasks
Create a Superuser
Superusers are created automatically on startup using FIRST_SUPERUSER_EMAIL and FIRST_SUPERUSER_PASSWORD from .env.
To create additional superusers, update a user via SQL or admin API.
Add a New API Endpoint
See docs/FEATURE_EXAMPLE.md for step-by-step guide.
Quick overview:
- Create Pydantic schemas in
app/schemas/ - Create CRUD operations in
app/crud/ - Create route in
app/api/routes/ - Register router in
app/api/main.py - Write tests in
tests/api/
Database Health Check
# Check database connection
python migrate.py check
# Health endpoint
curl http://localhost:8000/health
Docker Support
The Dockerfile uses uv for fast, reproducible builds:
# Development with hot reload
docker-compose -f docker-compose.dev.yml up
# Production
docker-compose up -d
# Rebuild after changes
docker-compose build backend
Docker features:
- Multi-stage builds (development + production)
- uv for fast dependency installation
uv.lockensures exact versions in containers- Development stage includes dev dependencies
- Production stage optimized for size and security
Troubleshooting
Common Issues
Module Import Errors
# Ensure dependencies are installed
make install-dev
# Or sync from lockfile
make sync
# Verify Python environment
uv run python --version
uv command not found
# Install uv globally
curl -LsSf https://astral.sh/uv/install.sh | sh
# Add to PATH (add to ~/.bashrc or ~/.zshrc)
export PATH="$HOME/.cargo/bin:$PATH"
Database Connection Failed
# Check PostgreSQL is running
sudo systemctl status postgresql
# Verify credentials in .env
cat .env | grep POSTGRES
Migration Conflicts
# Check migration history
python migrate.py list
# Downgrade and retry
alembic downgrade -1
alembic upgrade head
Tests Failing
# Run with verbose output
make test
# Run single test to isolate issue
IS_TEST=True uv run pytest tests/api/test_auth.py::TestLogin::test_login_success -vv
Dependencies out of sync
# Regenerate lockfile from pyproject.toml
uv lock
# Reinstall everything
make install-dev
Getting Help
See our detailed documentation:
- ARCHITECTURE.md - System design and patterns
- CODING_STANDARDS.md - Code quality guidelines
- COMMON_PITFALLS.md - Mistakes to avoid
- FEATURE_EXAMPLE.md - Adding new features
Performance
Database Connection Pooling
Configured in app/core/config.py:
- Pool size: 20 connections
- Max overflow: 50 connections
- Pool timeout: 30 seconds
- Connection recycling: 1 hour
Async Operations
- All I/O operations use async/await
- CPU-intensive operations (bcrypt) run in thread pool
- No blocking calls in request handlers
Query Optimization
- N+1 query prevention via eager loading
- Bulk operations for admin actions
- Indexed foreign keys and common lookups
Security
Built-in Security Features
- Password Security: bcrypt hashing, strength validation, common password blocking
- Token Security: HMAC-SHA256 signed, short-lived access tokens, algorithm validation
- Session Management: Database-backed, device tracking, revocation support
- Rate Limiting: Per-endpoint limits on auth/sensitive operations
- CORS: Explicit origins, methods, and headers only
- Security Headers: CSP, HSTS, X-Frame-Options, etc.
- Input Validation: Pydantic schemas, SQL injection prevention (ORM)
Security Best Practices
- Never commit secrets: Use
.envfiles (git-ignored) - Strong SECRET_KEY: Min 32 chars, cryptographically random
- HTTPS in production: Required for token security
- Regular updates: Keep dependencies current (
uv sync --upgrade) - Audit logs: Monitor authentication events
Monitoring
Health Check
curl http://localhost:8000/health
Returns:
- API version
- Environment
- Database connectivity
- Timestamp
Logging
Logs are written to stdout with structured format:
# Configure log level
logging.basicConfig(level=logging.INFO)
# In production, use JSON logs for log aggregation
Additional Resources
Official Documentation
- uv: https://docs.astral.sh/uv/
- FastAPI: https://fastapi.tiangolo.com
- SQLAlchemy 2.0: https://docs.sqlalchemy.org/en/20/
- Pydantic: https://docs.pydantic.dev/
- Alembic: https://alembic.sqlalchemy.org/
- Ruff: https://docs.astral.sh/ruff/
Our Documentation
- Root README - Project-wide information
- CLAUDE.md - Comprehensive development guide
Built with modern Python tooling:
- 🚀 uv - 10-100x faster dependency management
- ⚡ Ruff - 10-100x faster linting & formatting
- 🔍 mypy - Static type checking
- ✅ pytest - Comprehensive test suite
All configured in a single pyproject.toml file!