Skip to content

Commit 6ccbcd8

Browse files
Update
1 parent 9e6beba commit 6ccbcd8

9 files changed

Lines changed: 132 additions & 189 deletions

File tree

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ STORAGE_BUCKET=datasets
2020
# API
2121
API_TITLE=PolicyEngine API
2222
API_VERSION=0.1.0
23+
API_PORT=8000
2324
DEBUG=true
2425

2526
# Logfire (get token from https://logfire.pydantic.dev)

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ COPY src/ ./src/
1010
RUN uv pip install --system -e .
1111

1212
# Run migrations and start server
13-
CMD ["uvicorn", "policyengine_api.main:app", "--host", "0.0.0.0", "--port", "80"]
13+
CMD uvicorn policyengine_api.main:app --host 0.0.0.0 --port ${API_PORT:-80}

README.md

Lines changed: 104 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# PolicyEngine API v2
22

3-
A FastAPI service for running PolicyEngine microsimulations with Supabase backend, object storage, and background task processing.
3+
FastAPI service for PolicyEngine microsimulations with Supabase backend, object storage, and background task processing.
44

55
## Features
66

7-
- RESTful API for creating and managing simulations
8-
- Supabase for database and storage
9-
- Redis caching and Celery for background task processing
7+
- RESTful API for tax-benefit microsimulations
8+
- Supabase for PostgreSQL database and object storage
9+
- Celery workers for background simulation tasks
1010
- SQLModel for type-safe database models
11+
- Logfire observability and monitoring
1112
- Terraform deployment to AWS
1213

1314
## Quick start
@@ -16,257 +17,192 @@ A FastAPI service for running PolicyEngine microsimulations with Supabase backen
1617

1718
- [Supabase CLI](https://supabase.com/docs/guides/cli)
1819
- Docker and Docker Compose
19-
- Python 3.11+
20+
- Python 3.13+ with uv
2021

21-
### Local development with Supabase
22+
### Local development
2223

2324
1. **Set up environment**
2425

25-
Copy the example environment file:
26-
2726
```bash
2827
cp .env.example .env
2928
```
3029

31-
The `.env` file contains default values for local Supabase development. Key variables:
30+
The defaults in `.env.example` work with local Supabase. Key settings:
3231

3332
```bash
34-
# Supabase local instance (defaults work with `supabase start`)
3533
SUPABASE_URL=http://127.0.0.1:54321
36-
SUPABASE_KEY=<anon-key> # Public anon key
37-
SUPABASE_SERVICE_KEY=<service-role-key> # Admin key for seeding
3834
SUPABASE_DB_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
39-
40-
# Storage
41-
STORAGE_BUCKET=datasets
42-
43-
# Redis (via Docker)
4435
REDIS_URL=redis://localhost:6379/0
36+
STORAGE_BUCKET=datasets
4537
```
4638

47-
**Important:** The service key is required for database seeding operations (uploading datasets to storage). The default keys in `.env.example` work with local Supabase.
48-
4939
2. **Start Supabase**
5040

5141
```bash
5242
supabase start
5343
```
5444

55-
This creates a local instance at `http://localhost:54321` with:
56-
- PostgreSQL on port 54322
57-
- Storage API with S3-compatible interface
58-
- Auth API
59-
- Studio dashboard at `http://localhost:54323`
45+
Creates a local instance with PostgreSQL (port 54322), Storage API, and Studio dashboard at `http://localhost:54323`.
6046

6147
3. **Run integration tests**
6248

63-
This will set up the database, seed it with UK/US models, and run tests:
49+
Sets up database, seeds models, and runs tests:
6450

6551
```bash
6652
make integration-test
6753
```
6854

6955
This command:
70-
- Starts Supabase (if not running)
7156
- Creates all database tables from SQLModel definitions
72-
- Applies RLS policies and storage bucket configuration
73-
- Seeds UK and US tax-benefit models with all variables, parameters, and datasets
74-
- Runs integration tests to verify everything works
57+
- Applies RLS policies and storage bucket migrations
58+
- Seeds UK and US tax-benefit models with variables, parameters, and datasets
59+
- Runs integration tests
7560

7661
4. **Start the API**
7762

7863
```bash
7964
docker compose up
8065
```
8166

82-
The API will be available at `http://localhost:8000`. Visit `http://localhost:8000/docs` for interactive API documentation.
83-
84-
## Observability
85-
86-
The API uses [Logfire](https://logfire.pydantic.dev/) for observability and monitoring. Logfire automatically instruments:
87-
- All HTTP requests and responses
88-
- Database queries
89-
- Background tasks
90-
- Performance metrics
91-
92-
To view traces and logs, visit the [Logfire dashboard](https://logfire.pydantic.dev).
93-
94-
## Architecture
95-
96-
The system consists of three main components:
97-
98-
1. **API server** - FastAPI application serving REST endpoints
99-
2. **Database** - Supabase PostgreSQL storing models, parameters, simulations
100-
3. **Storage** - Supabase storage for dataset files (.h5)
101-
4. **Worker** - Celery workers executing simulations in background
102-
103-
### Models
104-
105-
The API provides eleven core resources:
106-
107-
- **Datasets** - Microdata for simulations (stored in Supabase storage)
108-
- **Policies** - Parametric reforms to tax-benefit systems
109-
- **Simulations** - Execution of tax-benefit models on datasets
110-
- **Variables** - Calculated outputs (income_tax, universal_credit, etc.)
111-
- **Parameters** - System settings (personal_allowance, benefit_rates, etc.)
112-
- **ParameterValues** - Time-bound parameter values
113-
- **Dynamics** - Dynamic modeling configurations
114-
- **TaxBenefitModels** - Country models (UK, US)
115-
- **TaxBenefitModelVersions** - Model versions
116-
- **AggregateOutputs** - Aggregate statistics from simulations
117-
- **ChangeAggregates** - Reform impact analysis
118-
119-
### Workflow
120-
121-
1. Upload dataset: `POST /datasets` with file upload to Supabase storage
122-
2. Create policy reform: `POST /policies`
123-
3. Create simulation: `POST /simulations`
124-
4. Poll simulation status: `GET /simulations/{id}`
125-
5. Create aggregates: `POST /outputs/aggregate`
67+
API available at `http://localhost:8000`. Visit `http://localhost:8000/docs` for interactive documentation.
12668

12769
## API endpoints
12870

129-
All endpoints at root level:
71+
Base URL: `http://localhost:8000`
13072

131-
```bash
132-
GET /health → {"status": "healthy"}
133-
GET /datasets → List all datasets
73+
### Core resources
74+
75+
```
76+
GET /health → Health check
77+
GET /datasets → List datasets
13478
POST /datasets → Create dataset
135-
GET /policies → List all policies
79+
GET /policies → List policies
13680
POST /policies → Create policy
137-
GET /simulations → List all simulations
138-
POST /simulations → Create and queue simulation
139-
GET /variables → List all variables
140-
GET /parameters → List all parameters
141-
GET /parameter-values → List all parameter values
142-
GET /dynamics → List all dynamics
143-
GET /tax-benefit-models → List all models
144-
GET /tax-benefit-model-versions → List all model versions
145-
GET /outputs/aggregate → List aggregates
146-
POST /outputs/aggregate → Compute aggregate
147-
GET /change-aggregates → List change aggregates
148-
POST /change-aggregates → Compute reform impact
149-
150-
POST /initialize/uk → Initialize UK model
151-
POST /initialize/us → Initialize US model
81+
GET /simulations → List simulations
82+
POST /simulations → Create simulation
83+
GET /simulations/{id} → Get simulation status
15284
```
15385

154-
## Configuration
155-
156-
Set environment variables or create a `.env` file:
86+
### Model metadata
15787

158-
```bash
159-
SUPABASE_URL=http://localhost:54321
160-
SUPABASE_KEY=your-anon-key
161-
SUPABASE_DB_URL=postgresql://postgres:postgres@localhost:54322/postgres
162-
REDIS_URL=redis://localhost:6379/0
163-
CELERY_BROKER_URL=redis://localhost:6379/0
164-
CELERY_RESULT_BACKEND=redis://localhost:6379/1
165-
STORAGE_BUCKET=datasets
166-
DEBUG=false
88+
```
89+
GET /variables → List variables
90+
GET /parameters → List parameters
91+
GET /parameter-values → List parameter values
92+
GET /tax-benefit-models → List models
93+
GET /tax-benefit-model-versions → List model versions
16794
```
16895

169-
## Storage
96+
### Aggregates and analysis
17097

171-
Datasets are stored in Supabase storage:
98+
```
99+
GET /aggregates → List aggregates
100+
POST /aggregates → Create aggregate
101+
GET /aggregates/{id} → Get aggregate
102+
GET /change-aggregates → List change aggregates
103+
POST /change-aggregates → Create change aggregate
104+
GET /change-aggregates/{id} → Get change aggregate
105+
DELETE /change-aggregates/{id} → Delete change aggregate
106+
```
172107

173-
```python
174-
from policyengine_api.services import storage
108+
## Typical workflow
175109

176-
# Upload dataset
177-
url = storage.upload_dataset("/path/to/dataset.h5", "frs_2023_24.h5")
110+
1. Create simulation: `POST /simulations` with dataset and policy
111+
2. Poll status: `GET /simulations/{id}` until status is "completed"
112+
3. Request aggregates: `POST /aggregates` with simulation_id and variable
113+
4. Compare reforms: `POST /change-aggregates` with baseline and reform simulation IDs
178114

179-
# Download dataset
180-
storage.download_dataset("frs_2023_24.h5", "/local/path.h5")
115+
## Database management
181116

182-
# Get public URL
183-
url = storage.get_dataset_url("frs_2023_24.h5")
117+
### Local development
184118

185-
# List all datasets
186-
files = storage.list_datasets()
119+
```bash
120+
make integration-test # Full setup: tables, migrations, seeding, tests
121+
make seed # Seed UK/US models only
122+
make reset # Reset Supabase database
187123
```
188124

189-
## Development
190-
191-
### Running tests
125+
### Production
192126

193127
```bash
194-
pytest
128+
make db-reset-prod # Reset production database (requires confirmation)
195129
```
196130

197-
### Code formatting
131+
**Warning:** `db-reset-prod` drops all tables, recreates schema, and reseeds data. It requires typing "yes" to confirm.
132+
133+
## Development
134+
135+
### Code quality
198136

199137
```bash
200-
ruff format .
201-
ruff check --fix .
138+
make format # Format code with ruff
139+
make lint # Lint and fix with ruff
140+
make test # Run unit tests
202141
```
203142

204143
### Database schema
205144

206-
The database schema uses a hybrid approach:
145+
Schema is defined in two parts:
207146

208-
**SQLModel for tables:** All table schemas are defined in Python using SQLModel (see `src/policyengine_api/models/`). This provides:
209-
- Single source of truth in Python code
210-
- Type safety and IDE autocomplete
211-
- Automatic relationship handling
212-
- Easy testing
147+
**SQLModel tables** (`src/policyengine_api/models/`): All table definitions use SQLModel for type safety and single source of truth.
213148

214-
**SQL migrations for Postgres features:** SQL files in `supabase/migrations/` handle:
215-
- Row-level security (RLS) policies
216-
- Storage bucket configuration
217-
- Postgres-specific features SQLModel can't express
149+
**SQL migrations** (`supabase/migrations/`): Row-level security policies, storage buckets, and Postgres-specific features.
218150

219-
To regenerate the schema:
151+
To recreate tables:
220152

221153
```bash
222-
# Creates all tables from SQLModel and applies SQL migrations
223154
uv run python scripts/create_tables.py
224155
```
225156

226-
**When to create SQL migrations:**
157+
Only create SQL migrations for RLS policies or storage configuration, not table schemas.
227158

228-
Only create new SQL migrations for RLS policies, storage buckets, or other Postgres-specific features. Table schemas should be defined in SQLModel classes, not SQL.
159+
## Observability
229160

230-
```bash
231-
# Create a new migration (only for RLS/storage/triggers)
232-
supabase migration new add_new_rls_policy
233-
```
161+
[Logfire](https://logfire.pydantic.dev/) instruments:
162+
- HTTP requests and responses
163+
- Database queries
164+
- Background tasks
165+
- Performance metrics
234166

235-
### Supabase management
167+
View traces at the [Logfire dashboard](https://logfire.pydantic.dev).
236168

237-
```bash
238-
# Start local Supabase
239-
supabase start
169+
## Architecture
240170

241-
# Stop Supabase
242-
supabase stop
171+
### Components
243172

244-
# Reset database
245-
supabase db reset
173+
- **API server**: FastAPI application (port 8000 local, 80 production)
174+
- **Database**: Supabase PostgreSQL
175+
- **Storage**: Supabase object storage for .h5 dataset files
176+
- **Worker**: Celery workers for background simulations
177+
- **Cache**: Redis for Celery broker and API caching
246178

247-
# View logs
248-
supabase logs
179+
### Data models
249180

250-
# Open Studio dashboard
251-
supabase studio
252-
```
181+
- **Datasets**: Microdata files in Supabase storage
182+
- **Policies**: Parameter reforms
183+
- **Simulations**: Tax-benefit calculations
184+
- **Variables**: Model outputs (income_tax, universal_credit)
185+
- **Parameters**: System settings (personal_allowance, benefit_rates)
186+
- **ParameterValues**: Time-bound parameter values
187+
- **Aggregates**: Statistics from simulations
188+
- **ChangeAggregates**: Reform impact analysis
253189

254-
## Project structure
190+
### Project structure
255191

256192
```
257193
policyengine-api-v2/
258-
├── src/
259-
── policyengine_api/
260-
├── api/ # FastAPI routers
261-
├── config/ # Settings
262-
├── models/ # SQLModel database models
263-
├── services/ # Database, storage, initialization
264-
── tasks/ # Celery tasks
265-
│ └── main.py # FastAPI application
266-
── supabase/ # Supabase configuration and migrations
267-
├── tests/ # Test suite
268-
├── docker-compose.yml # Docker services (API, worker, Redis)
269-
└── pyproject.toml # Dependencies
194+
├── src/policyengine_api/
195+
── api/ # FastAPI routers
196+
│ ├── config/ # Settings
197+
│ ├── models/ # SQLModel database models
198+
│ ├── services/ # Database, storage
199+
│ ├── tasks/ # Celery tasks
200+
── main.py # FastAPI app
201+
── supabase/
202+
│ └── migrations/ # RLS policies and storage
203+
├── scripts/ # Database setup and seeding
204+
├── tests/ # Test suite
205+
└── docker-compose.yml # Local services
270206
```
271207

272208
## License

0 commit comments

Comments
 (0)