Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 87 additions & 30 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,62 +1,119 @@
# Copy to ".env" at the repository root (same folder as docker-compose.yml).
# Both the FastAPI app and Next.js read configuration from this file for local work.
# FastAPI (pydantic-settings) and Next.js (via dotenv-cli in `frontend/package.json` scripts) read
# the same file for local work. Use UPPER_SNAKE names below; they map 1:1 to `backend/app/core/config.py`
# `Settings` fields unless otherwise noted (Clerk + Langfuse aliases are documented in comments).

# --- API (FastAPI / pydantic-settings) ---
# =============================================================================
# Next.js (dev server, static export, browser)
# =============================================================================
# Required: the app wraps with `ClerkProvider` — without a non-empty key the client throws at startup.
# Get the value from Clerk → configure → API Keys → Publishable key (e.g. pk_test_...).
# (Even when API `AUTH_MODE=disabled`, the UI still loads Clerk for the shell.)
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=

# How the browser calls the API (empty = same-origin `/api/*` in dev, with rewrites; see `frontend/next.config.ts`):
# - Local `next dev`: leave empty and use the dev-server rewrite to `BACKEND_URL` (default http://127.0.0.1:8000), or set the API origin explicitly.
# - Docker Compose: set to the API URL the browser can reach (e.g. http://localhost:8000).
# - Static export / CDN: set to your public API base (no trailing slash) or put `/api` behind the CDN.
# NEXT_PUBLIC_API_URL=

# When `NEXT_PUBLIC_API_URL` is empty: proxy target for same-origin `/api` in dev.
# BACKEND_URL=http://127.0.0.1:8000

# Set to 1 to skip the `/api` dev rewrite (handle `/api` only in Next, or for debugging).
# NEXT_DISABLE_API_REWRITE=1

# `frontend/package.json` build uses this: set to 1 for `output: "export"` (production Docker/static hosting).
# NEXT_STATIC_EXPORT=1

# =============================================================================
# API server (FastAPI) — `Settings` in `backend/app/core/config.py`
# =============================================================================
API_HOST=0.0.0.0
API_PORT=8000
# Comma-separated browser origins allowed to call the API
# Comma-separated browser origins for CORS
CORS_ORIGINS=http://localhost:3000
# Exposed on responses (CORS `Access-Control-Expose-Headers`); must match any client that reads the ID.
# REQUEST_ID_HEADER=X-Request-Id

# --- UI (Next.js static export) ---
# Local dev: point at the FastAPI service. Production (CloudFront): leave empty to use same-origin /api/*.
NEXT_PUBLIC_API_URL=http://localhost:8000

# --- Runtime metadata (optional; never hardcode per-environment values in source) ---
# ---------------------------------------------------------------------------
# Runtime (optional; used in logs, Langfuse `environment`, health)
# ---------------------------------------------------------------------------
# Examples: dev | staging | prod | local
# DEPLOYMENT_ENVIRONMENT=local

# --- Auth (Clerk) ---
# For local dev you can leave AUTH_MODE=disabled.
# In deployed envs, set AUTH_MODE=clerk_jwks and provide the JWKS URL + issuer.
# ---------------------------------------------------------------------------
# Auth (API JWT verification)
# ---------------------------------------------------------------------------
# `disabled` = no Clerk verification (local only). `clerk_jwks` = require valid Clerk tokens.
AUTH_MODE=disabled
# Example: https://<your-clerk-domain>/.well-known/jwks.json
# CLERK_JWKS_URL=
# Example: https://<your-clerk-domain>
# CLERK_ISSUER=
# Optional audience validation (depends on your Clerk configuration)
# CLERK_AUDIENCE=

# --- Guardrails / limits ---
# ---------------------------------------------------------------------------
# Guardrails / limits
# ---------------------------------------------------------------------------
# MAX_UPLOAD_BYTES=5242880
# MAX_TEXT_CHARS=80000
# MAX_OUTPUT_CHARS=120000

# --- Persistence (SQLite + local uploads; production should move uploads to S3 and DB to Aurora) ---
# ---------------------------------------------------------------------------
# Persistence (SQLite + local upload dir)
# ---------------------------------------------------------------------------
# SQLITE_PATH=.data/talentstreamai.sqlite3
# UPLOAD_DIR=.data/uploads
# SQLITE_BUSY_TIMEOUT_MS=5000
# SQLITE_ENABLE_WAL=true

# --- Upload storage ---
# UPLOAD_STORAGE=none|local|s3
# ---------------------------------------------------------------------------
# Upload storage (`none` | `local` | `s3`)
# ---------------------------------------------------------------------------
# UPLOAD_STORAGE=none
# For S3:
# S3_BUCKET=your-private-bucket
# S3_BUCKET=
# S3_PREFIX=uploads/
# S3_SSE=AES256
# S3_KMS_KEY_ID= # optional if S3_SSE=aws:kms
# S3_KMS_KEY_ID=

# --- Agent / LLM ---
# Local: AGENT_MODE=stub (no external calls). Deployed: AGENT_MODE=llm.
# ---------------------------------------------------------------------------
# Agent + LLM (OpenAI-compatible `/v1/chat/completions`)
# ---------------------------------------------------------------------------
# `stub` = no external LLM. `llm` = call external API (see startup checks in `app/main.py` in prod).
AGENT_MODE=stub
# OpenAI-compatible base URL. For OpenRouter, you might use https://openrouter.ai/api
# Product: reported match % in API responses (floor / cap; not a third-party ATS score).
# MIN_TAILORED_MATCH_SCORE=90
# MAX_REPORTED_MATCH_SCORE=99
LLM_BASE_URL=https://api.openai.com
# LLM_API_KEY=... # preferred
# OPENROUTER_API_KEY=... # accepted alias
# LLM_MODEL=...
# OPENROUTER_API_KEY=
# OPENAI_API_KEY=
# LLM_MODEL=gpt-4.1-mini
# LLM_TIMEOUT_SECONDS=45
# LLM_MAX_TOKENS=1800
# LLM_TEMPERATURE=0.2
# OpenRouter optional headers (recommended)
# OPENROUTER_REFERER=https://your-app.example
# OPENROUTER_TITLE=TalentStreamAI
# OPENROUTER_REFERER=
# OPENROUTER_TITLE=

# ---------------------------------------------------------------------------
# Observability (API)
# ---------------------------------------------------------------------------
# LOG_LEVEL=INFO
# LOG_JSON=false
# ENABLE_PROMETHEUS=true
# SERVICE_NAME=talentstreamai-api
# OTEL_EXPORTER_OTLP_ENDPOINT=

# ---------------------------------------------------------------------------
# Langfuse (LLM tracing; optional)
# https://langfuse.com/docs
# ---------------------------------------------------------------------------
# LANGFUSE_PUBLIC_KEY=
# LANGFUSE_SECRET_KEY=
# LANGFUSE_BASE_URL=https://cloud.langfuse.com
# Alias for base URL: LANGFUSE_HOST
# LANGFUSE_TRACING_ENABLED=true

# =============================================================================
# Not set here (injected by platforms)
# =============================================================================
# `app/main.py` reads AWS/Lambda/ECS environment detection from standard variables
# (e.g. `AWS_EXECUTION_ENV`, `AWS_LAMBDA_FUNCTION_NAME`, `ECS_CONTAINER_METADATA_URI*`) — do not set in `.env` locally.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,7 @@ coverage/
htmlcov/
.coverage

.cursor

# Backend local data (sqlite, uploads)
backend/.data/
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ Located in `backend/app/tools/`:
Required in `.env`:
| Key | Description |
| --- | --- |
| `OPENAI_API_KEY` | OpenAI API key for LLM calls (GPT-4o) |
| `OPENROUTER_API_KEY` / `OPENAI_API_KEY` | At least one for `AGENT_MODE=llm`: OpenRouter for chat if set, else `OPENAI_API_KEY` (see `.env.example`). |
| `LANGFUSE_*` | Optional: Langfuse keys for API-side LLM observability (see `.env.example`). |

## Prerequisites

Expand Down Expand Up @@ -101,7 +102,9 @@ Both FastAPI (`pydantic-settings`) and Next.js (via `dotenv-cli` in `frontend/pa
| `CORS_ORIGINS` | API | Comma-separated browser origins allowed to call the API. |
| `NEXT_PUBLIC_API_URL` | UI (build + browser) | Public API base URL the browser calls. Leave empty for production builds that should call same-origin `/api/*` through CloudFront. |
| `DEPLOYMENT_ENVIRONMENT` | API (`/api/v1/health` metadata) | Optional label such as `local`, `dev`, `staging`, or `prod`. |
| `OPENAI_API_KEY` | API | OpenAI API key for LLM calls (GPT-4o). Required for `/api/v1/apply` endpoint. |
| `OPENROUTER_API_KEY` | API | OpenRouter key; used for chat when set (with `LLM_BASE_URL` for OpenRouter). |
| `OPENAI_API_KEY` | API | Used for chat when `OPENROUTER_API_KEY` is unset; optional when OpenRouter is set. |
| `LANGFUSE_PUBLIC_KEY` / `LANGFUSE_SECRET_KEY` | API | Optional. [Langfuse](https://langfuse.com) project keys for LLM tracing; set with `LANGFUSE_BASE_URL` (or `LANGFUSE_HOST`) for EU/US/self-hosted. |

## Run the full stack in Docker

Expand Down
Loading
Loading