Trail Permit
Backcountry trail permit API with check-ins, permit bands and a full Pixeltable Cloud lifecycle
One app.py with 3 tables, 6 computed columns, 6 HTTP routes. Needs pixeltable[serve]>=0.7.14. Updated 2026-10-02.
app.py
"""Trail Permit API built with Pixeltable.pxt schema update app.py trailspxt service run app.py trails"""import pixeltable as pxtimport pixeltable.functions as pxtffrom pixeltable.serving import FastAPIRouterfrom udfs import checkin_status, permit_band# ---- tables ----TableModel = pxt.model_base()class Trails(TableModel, name='trails'):code = pxt.Column(type=pxt.String, primary_key=True)name: pxt.Stringregion: pxt.Stringmiles: pxt.Floatdifficulty: pxt.Stringopen: pxt.Boolregion_upper = pxtf.string.upper(region)name_lower = pxtf.string.lower(name)class Permits(TableModel, name='permits'):id = pxt.Column(value=pxtf.uuid.uuid7(), primary_key=True)trail_code: pxt.Stringholder: pxt.Stringdays: pxt.Intparty_size: pxt.Intstart_date: pxt.Stringnotes: pxt.String | Noneband = permit_band(days, party_size)trail_upper = pxtf.string.upper(trail_code)class Checkins(TableModel, name='checkins'):id = pxt.Column(value=pxtf.uuid.uuid7(), primary_key=True)permit_holder: pxt.Stringtrail_code: pxt.Stringstatus: pxt.String # in / outlate_min: pxt.Intgate: pxt.Stringnote: pxt.String | Nonestatus_label = checkin_status(status, late_min)gate_upper = pxtf.string.upper(gate)# ---- queries ----@pxt.querydef open_trails(region: str):return Trails.where((Trails.region == region) & (Trails.open == True)).select( # noqa: E712Trails.code, Trails.name, Trails.miles, Trails.difficulty).order_by(Trails.miles)@pxt.querydef permits_for(trail_code: str):return Permits.where(Permits.trail_code == trail_code).select(Permits.holder, Permits.start_date, Permits.days, Permits.party_size, Permits.band).order_by(Permits.start_date)# ---- routes ----trails_api = FastAPIRouter(name='trails_api')trails_api.add_insert_route(Trails, path='/trails',inputs=[Trails.code, Trails.name, Trails.region, Trails.miles, Trails.difficulty, Trails.open],outputs=[Trails.code, Trails.region_upper, Trails.name_lower])trails_api.add_insert_route(Permits, path='/permits',inputs=[Permits.trail_code, Permits.holder, Permits.days, Permits.party_size,Permits.start_date, Permits.notes],outputs=[Permits.id, Permits.band, Permits.trail_upper])trails_api.add_insert_route(Checkins, path='/checkins',inputs=[Checkins.permit_holder, Checkins.trail_code, Checkins.status, Checkins.late_min,Checkins.gate, Checkins.note],outputs=[Checkins.id, Checkins.status_label, Checkins.gate_upper])trails_api.add_compute_route(Permits, path='/band', inputs=[Permits.days, Permits.party_size], outputs=[Permits.band])trails_api.add_query_route(path='/trails/open', query=open_trails, method='get')trails_api.add_query_route(path='/permits/by-trail', query=permits_for, method='get')
What app.py declares
Each row links to its line.
- runs on insert
- stored
- index
- route
serves trails_api
- POST/trailsinsert, trailstakes code, name, region, miles, difficulty, open; returns code, region_upper, name_lowerL71
- POST/permitsinsert, permitstakes trail_code, holder, days, party_size, start_date, notes; returns id, band, trail_upperL74
- POST/checkinsinsert, checkinstakes permit_holder, trail_code, status, late_min, gate, note; returns id, status_label, gate_upperL78
- POST/bandcompute, permitstakes days, party_size; returns bandL82
- GET/trails/openquery, open_trailstakes regionL83
- GET/permits/by-trailquery, permits_fortakes trail_codeL84
Run it
Needs uv. The routes then answer on port 8000.
terminal
git clone https://github.com/pierrebrunelle/pixeltable-trail-permitscd pixeltable-trail-permitsuv syncuv run pxt schema update app.py trailsuv run python seed.py trailsuv run pxt service run app.py trails --port 8000
Related apps
- Forge Heat CyclesForge heat-cycle registry API: B-tree indexes, chained risk UDFs, and parallel shop-floor writersShares: UDFs
- Climbing Route ToposClimbing-route topo registry API: photo uploads with thumbnails, grayscale copies, grade bands and index-backed crag lookupsShares: UDFs
- Warehouse Pick ListsWarehouse pick-list REST API: units, pick zones, waves and tote labels as incremental computed columns over Json order linesShares: UDFs