API details
LIVE and DEMO workspaces
The top navigation selects LIVE or DEMO. All existing entries belong to LIVE. DEMO starts empty; its observations, cases, jobs and stored photos can be cleared together without deleting LIVE records. The public switch selects a view for that visitor. The operator CLI changes capture mode or clears DEMO records; neither action changes requests already sent to the city.
GET /api/workspace returns the selected mode and its generation.PATCH /api/workspace with {"mode":"demo"} selects the test workspace; use live to return.DELETE /api/workspace accepts only {"mode":"demo"}. It advances the generation so older jobs cannot recreate cleared data.POST /api/patrols accepts {mode, generation, observation}. Capture producers freeze mode and generation when capture begins. A stale generation returns HTTP 409.
Viewing the portal, observations, approved photos, and workspace selection requires no sign-in. Visitors switch views locally; changing capture mode or clearing data requires operator credentials. Device capture producers use a server-issued bearer token. Workspace records use Supabase Postgres when server-side credentials are configured, with SQLite as the local fallback. The migrated Pixel observations and cases use private Supabase Storage for original and reviewed SAM images.
Trippie observation feed
GET /api/patrols?mode=live returns an observation array with Cache-Control: no-store. The portal refreshes every five seconds, scopes observations and cases to the selected Trippie, and sorts dated captures newest first.
{
"id": "capture-unique-id",
"trippieId": "trippie-02",
"capturedAt": "2026-11-03T16:45:00Z",
"title": "Potential obstruction",
"category": "Obstruction",
"priority": "Medium",
"lat": 33.0463, "lng": -96.8515,
"time": "10:45 AM",
"image": "/captures/original.jpg",
"samImage": "/captures/sam-outline.png",
"interpretation": "Model assessment and uncertainty",
"caseText": "Exact draft or recorded report text",
"status": "Needs review",
"sample": false
}Current data adapter: reads workspace observations from Supabase Postgres (or local SQLite). Labeled sample fixtures also come from data/patrols.json. The private JSON photo feed is used only when cloud storage is not configured. Fleet names, neighborhoods, map centers, and example routes are in lib/fleet.ts. Existing browser observations use IndexedDB. Validated observations can be saved through the authenticated observation endpoint; raw camera upload and city submission require their own adapters. GET /api/media/[id] publicly serves approved image assets only after checking the stored image hash and workspace generation. The storage bucket itself remains private.
samImage, caseText, capturedAt, and receipt are optional. Include the real city reference only after a submission response. The legacy Receipt recorded status describes an admin-entered reference, not independently verified acceptance.
Accela / PublicStuff city API
The vendor publishes a REST API with a create-request operation. Its documentation requires an API key and describes a session token for some content. Availability of the API does not establish that a key has permission to submit to Plano.
| Operation | Documented endpoint | Use |
|---|
| Create request | POST https://api.publicstuff.com/app/requests | Send a validated city request through an authorized integration. |
| Read requests | GET /app/requests | Find existing requests and avoid duplicates. |
| Read one request | GET /app/requests/{id} | Retrieve case status and follow-up information. |
Authentication header: Authorization: Token token={API_KEY}. Some operations also use PublicStuff-Session-Token. Keep both server-side. The create schema exposes fields such as request[client_id], request[request_type_id], request[description], contact fields, request[geo_location_id], and request[primary_attachment_id].
The generic API schema marks many request fields optional; the city’s form-specific required fields still apply. Discover request-type IDs, custom-field mappings, location creation, attachment upload, and permissions before implementing a submission adapter. Do not guess IDs from form names.
Vendor sources: Swagger documentation · API index · Request schema. Documentation inspected November 3, 2026; no city requests sent.
Pixel photo workflow
- Import and identify. Retain the original JPEG, SHA-256, capture time, EXIF coordinates, and device. Normalize orientation and strip EXIF from the image sent to the model. The November 3 intake contains 15 photos and one excluded video.
- Analyze with Muse Spark Open. Fireworks model
accounts/fireworks/models/muse-spark-open returns observed facts, uncertainty, request routing, draft text, and missing fields. Preserve the response ID and token usage. No issue is a valid result. - Group evidence. A multi-image pass groups angles of one defect into a case candidate. Reused GPS alone does not establish that two views are the same location. Resolve the nearest street and connected intersection automatically from photo GPS and cached City of Plano road geometry. Include the estimate, photo coordinates, offset, and uncertainty in the draft; no address entry by a user is required.
- Segment and check. Meta
sam-3.1 supports point, box and crop prompts. The edge-localization trial uses a photo-specific crop and grid to refine a difficult boundary. Decode the actual mask and verify that it outlines the intended surface or object. Acorns selected instead of concrete are rejected. A refined prompt retains its review provenance. Only reviewed masks matching the source, prompt, and request appear in the feed. - Prepare the city form. Match the audited request type, required fields, and original evidence. This run stops before final Submit. A draft is never counted as a city receipt.
Processing entry point: npm run process:photos runs analysis, GIS resolution for every capture, multi-view case grouping, segmentation, and feed publication. Nearby captures reuse a bounded map cache; hashes and photo coordinates prevent stale location reuse. The local intake reads imported Pixel files. Raw Android camera ingestion requires an authenticated upload adapter; the current input is imported Pixel files.
Local evidence: /api/evidence/[id]/original and /api/evidence/[id]/sam serve private assets only on localhost, with no caching. The public sample dataset stays separate. Credentials remain in the server environment.
Capture improvements for Android: save fresh location timestamp and accuracy with every photo; provide a wider context image and a close-up; collect a measured offset when needed; associate multiple captures with one stable defect ID; review segmentation before preparing a report.
Utility cover routing: the inspected Water Meter Boxes/Lids form requires address, Meter Box Issue (METER BOX or METER LID), and description. The city requests separate reports for box and lid issues. A valve cover is not automatically a water-meter lid: verify asset ownership and routing first. Raw audit: research/water-meter-lids-form.txt.
Operator controls
The website stays open without sign-in. Operator commands use the existing server credential in .env.local; the password is never passed on the command line. Commands target https://www.fixitplano.com by default. Set TRIPPIE_PORTAL_URL to another HTTPS portal origin or a local loopback address for development.
npm run operator -- status
npm run operator -- mode demo
npm run operator -- mode live
npm run operator -- clear-demo --confirm
Mode: changes the workspace reported to capture producers. A visitor's LIVE/DEMO view does not change this setting. Clear: deletes DEMO records and registered images, keeps LIVE data, and advances the generation so late jobs cannot restore deleted entries. The command requires the explicit confirmation flag and never automatically retries a deletion.
Public data: both LIVE and DEMO feeds, approved images, locations and model provenance are public. DEMO is a disposable public workspace. Local source-file paths, credentials and raw provider responses are excluded from the public feed.
Read-only cloud verification: npm run verify:cloud checks the imported observations, SAM references, supporting evidence, case attachments, approved asset records and stored image hashes. It does not run inference or upload data.
City form preparation
The demonstrated result is two draft city cases with a request type, estimated location, concise description and original-photo attachment. The city forms were inspected and prepared in the browser; the portal does not submit them. finalSubmitAllowed remains false in the prepared case records.
- Classify and route. Muse selects a request type using visible evidence and the audited city instructions.
- Check evidence. Keep the original, reviewed SAM output, capture time, location estimate and uncertainty together.
- Group views. Compare physical landmarks across images before treating multiple captures as one case.
- Build the draft. Fill supported fields from evidence, retain missing requirements and avoid invented contact details or measurements.
- Review the form. Check the address selection, description and original-photo attachment against the actual city screen. Stop before final Submit.
- Record an outcome. A city receipt and public workflow status require an actual city response. The current case feed contains drafts.
Agent acceptance test: an app-owned reporting agent should expose its routing decisions, tool calls, filled fields and verification results, stop at the final-submit boundary, and reconcile uncertain responses before retrying. A choice of browser transport alone does not establish an end-to-end reporting agent.
Developer notes
Robot control
The demonstrated inspection workflow starts with imported Pixel photos. For Android/BLE acceptance, exercise camera capture → Muse action selection → command validation → Bluetooth movement → a fresh camera frame. Verify local stopping on stale evidence, lost connectivity or a rejected action before describing autonomous patrol as demonstrated.
Bench-tested hardware baseline: replacement Rugged Robot travelled five forward steps straight through its official app. Mode 2 steady; obstacle avoidance was off for that diagnostic test. This is distinct from validating autonomous outdoor navigation.
Evidence and models
Server-side scripts call Muse Spark Open on Fireworks and SAM 3.1 through Meta Model API. Keep credentials off Android and out of browser bundles. Store model/version, request IDs, prompts, and output timestamps with the case.
SAM highlights regions; it does not measure defect height or decide city eligibility. Store the actual SAM image in samImage. Example outlines remain labeled examples.
Feed integration
Stable observation IDs prevent duplicate cards. Include trippieId to isolate neighborhoods and an ISO capturedAt for ordering. A failed refresh retains the last received observations and displays an error. Cloud observations and evidence use the durable Supabase adapter. Read access is public through the portal; writes remain protected. Capture producers must attach mode and generation at capture time.
Local development
Use Node 24.x, matching .nvmrc, package.json and the build checks. Installation, development and build commands verify the runtime and built-in SQLite. npm run dev serves localhost port 3015. npm run build compiles and checks TypeScript. The portal is at /, the presentation at /hackathon, and these notes at /documentation.
Next.js 16 · React 19 · TypeScript · Leaflet / OpenStreetMap · Mermaid. Preserve map attribution. Public demo data must not contain private contact details or credentials.