You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A .env file placed in backend/ (see variable reference below)
First-Time Setup
# Clone the repository
git clone <repo-url> studymation &&cd studymation
# Copy the env template and fill in values
cp backend/.env.example backend/.env
# Edit backend/.env — see variable reference below# Build images
make build
# Start all services in background
make up-detached
# Apply all database migrations
make migrate
# (Optional) Create an admin user
make create-admin email=you@example.com
The API is now available at http://localhost:8000.
Development Workflow
make dev # Backend (Docker) + frontend (local) simultaneously
make logs-api # Tail API logs
make shell # Open bash inside the API container
make down # Stop all services
make db-reset # Drop + recreate dev DB (destructive — dev only)
Creating Migrations
# Auto-generate a migration from model changes
make migrate-create msg="add_column_foo_to_users"# Apply pending migrations
make migrate
Environment Variables Reference
All variables are read by app/config.py via pydantic-settings. Never read os.environ directly — always import settings from app/config.py.
Random 32+ char string. Must not be the default in prod.
JWT_EXPIRE_DAYS
7
Token lifetime in days
GOOGLE_CLIENT_ID
—
Google OAuth client ID
GOOGLE_CLIENT_SECRET
—
Google OAuth client secret
GOOGLE_REDIRECT_URI
—
OAuth callback URL
FRONTEND_URL
—
Used for CSRF redirect and cookie domain
AUTH_COOKIE_NAME
studymation_token
Cookie name for JWT
AUTH_COOKIE_SAMESITE
lax
Cookie SameSite policy
AUTH_COOKIE_DOMAIN
—
Cookie domain (set in prod)
Storage (DigitalOcean Spaces / S3-compatible)
Variable
Default
Description
STORAGE_ENDPOINT
—
S3-compatible endpoint URL
STORAGE_ACCESS_KEY
—
Spaces access key
STORAGE_SECRET_KEY
—
Spaces secret key
STORAGE_BUCKET
—
Bucket name
STORAGE_REGION
—
Region identifier
FREE_DOCUMENT_TTL_HOURS
72
Hours before free-plan docs expire
Payments
Variable
Default
Description
STRIPE_SECRET_KEY
—
Stripe secret key (sk_live_... in prod)
STRIPE_WEBHOOK_SECRET
—
Webhook signing secret (whsec_...)
USD_TO_MXN
17.44
Exchange rate for MXN pricing
USD_TO_MXN_LAST_UPDATED
—
ISO date of last FX update. Staleness alert if >7 days old.
PROFIT_MARGIN_PCT
300
Markup percentage on LLM costs
MAX_NEGATIVE_BALANCE
-20.0
Minimum allowed credit balance
Rate Limiting
Variable
Default
Description
RATE_LIMIT_BACKEND
memory
redis in production, memory in development
REDIS_URL
—
Redis connection URL (redis://host:6379/0)
Citations
Variable
Default
Description
SEMANTIC_SCHOLAR_API_KEY
—
Semantic Scholar API key
BRAVE_API_KEY
—
Brave Search API key
CITATION_MIN_SCORE
0.50
Minimum relevance score for citation inclusion
CITATION_MIN_RELEVANCE
0.16
Minimum Jaccard similarity threshold
CITATION_MAX_CANDIDATES_PER_SECTION
12
Max candidates to evaluate per section
CITATION_CACHE_TTL_DAYS
30
Days before citation cache entries expire
CITATION_MIN_COUNT
2
Minimum citations required for a document
Images
Variable
Default
Description
OPENVERSE_ENABLED
false
Enable Openverse image search
PEXELS_API_KEY
—
Pexels API key (optional)
PIXABAY_API_KEY
—
Pixabay API key (optional)
UNSPLASH_API_KEY
—
Unsplash API key (optional)
IMAGE_SEARCH_TIMEOUT_SECONDS
—
Per-provider timeout
IMAGE_REQUIRED_MIN_COUNT
—
Minimum images required per document
Timeouts
Variable
Default
Description
GENERATION_GLOBAL_TIMEOUT_SECONDS
420
Max end-to-end generation time (7 min)
LLM_TIMEOUT_SECONDS
60
Per LLM call timeout
CITATION_PROVIDER_TIMEOUT_SECONDS
10
Per citation provider timeout
File Upload
Variable
Default
Description
UPLOAD_MAX_FILE_SIZE_MB
10
Max size per uploaded file
UPLOAD_MAX_TOTAL_SIZE_MB
15
Max combined upload size per turn
UPLOAD_MAX_FILES_PER_TURN
5
Max files per conversation turn
UPLOAD_PARSE_TIMEOUT_SECONDS
20
Timeout for file parsing
UPLOAD_MAX_EXTRACTED_CHARS
80000
Max characters extracted from uploads
UPLOAD_PDF_MAX_PAGES
40
Max pages extracted from PDF
UPLOAD_DOCX_MAX_UNCOMPRESSED_MB
40
Zip-bomb guard for DOCX
UPLOAD_MAX_GENERATION_CHARS
20000
Max chars forwarded to generation pipeline
Quality Gate
Variable
Default
Description
QUALITY_GATE_ENABLED
true
Enable post-render quality checks
QUALITY_GATE_BLOCK_ON_P0
true
Block generation on P0-severity failures
MERMAID_OMIT_ON_FAILURE
true
Omit diagram (don't insert raw code) on render failure
IMAGE_ENTITY_ANCHOR_REQUIRED
true
Image caption must mention topic entities
Production Safety Checks
config.py validates these conditions at startup when APP_ENV=production:
DEBUG must be false
JWT_SECRET_KEY must not be the default value
ALLOWED_ORIGINS must use https://
RATE_LIMIT_BACKEND must be redis
STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET must be set
GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET must be set
FRONTEND_URL and APP_URL must use https://
The app will refuse to start if any of these fail.
Testing Setup
Tests run inside the Docker container:
make test# All tests except slow
make test-unit # Unit tests only
make test-integration # Integration (requires running DB)
make test-file f=tests/unit/test_auth.py # Single file
make test-coverage # With HTML report
make test-slow # External API tests (Semantic Scholar, etc.)
conftest.py creates a studymation_test database at session start. Each test gets a transaction that auto-rolls back — no manual cleanup needed. Call get_settings.cache_clear() in tests before overriding env vars.