Python ยท FastAPI reference application

Field Notebook

A quiet environmental journal that validates typed field observations with Pydantic and persists them through an asynchronous FastAPI-to-Trestle boundary.

Field Notebook showing categorized environmental observation cards

What it proves

Validation

Typed observations

Pydantic bounds required text, categories, conditions, notes and temperatures before a record reaches Trestle.

Python boundary

Async public API calls

FastAPI exposes two domain endpoints while an httpx client holds the credential and calls one fixed collection.

Developer experience

Docs included

The application exposes interactive domain API documentation at /api/docs without exposing Trestle's administrative API.

Run the example

git clone https://github.com/trestle-cv/dogfood-field-notebook
cd dogfood-field-notebook
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e '.[dev]'

export TRESTLE_URL=http://127.0.0.1:7333
export TRESTLE_ADMIN_EMAIL=admin@example.test
export TRESTLE_ADMIN_PASSWORD='choose-a-real-password'

python scripts/bootstrap.py
nift build
uvicorn app.main:app --reload --host 127.0.0.1 --port 4182

Start Trestle first, then open http://127.0.0.1:4182. Bootstrap creates fn_observations, applies service-only rules and saves its copy-once credential in .field-notebook.json with owner-only permissions.

Observation contract

Each entry has a title and location, a flora, fauna, weather or terrain category, a stable, watch or critical condition, bounded notes and an optional temperature between -80 and 80 degrees. The browser can list and create observations through the domain API; it never supplies an upstream path.

GET  /api/observations
POST /api/observations
GET  /api/docs

Architecture and authority

browser -> FastAPI domain endpoints -> Trestle HTTP API -> configured Trestle store

FastAPI owns the narrow browser boundary and Trestle owns schema enforcement and persistence. Static presentation remains independently rebuildable with Nift, and the service credential never enters generated HTML or browser responses.

Useful checks

pytest
python -m compileall -q app scripts