Fieldmark
Your PDF floor plan becomes a live checklist — pins are tasks, and it works with no signal.
For a founder — cost, outcome, time
- To App Store
- 7 days
- Crews live
- 3
- Fix after rejection
- 18 h
- Offline
- yes

Installer crews work off paper plans and texts; the foreman chases status by phone all day, and signal dies in mechanical rooms.
The PDF becomes the task list — pins are tasks, and it works offline.
- Flutter
- Riverpod
- Supabase
- Firebase
- Apple Sign-In
Fieldmark is a Flutter app that turns a PDF floor plan into a live installation checklist — foremen drop numbered pins, installers pick up tasks offline in the field.
A rejection email became the clearest spec of the sprint. Build 20 bounced, Build 21 submitted the next morning, approved.
Context
Installer crews (electric, HVAC, low-voltage) work off paper plans and text messages. A foreman marks up a PDF, hands it out, and then chases status by phone all day. Fieldmark makes the same PDF interactive: pins are tasks, tasks have photos and voice notes, status flows back automatically.
Problem
Existing task apps (Asana, ClickUp, Fieldwire) treat plans as attachments. In practice, installers navigate by where on the plan the work is, not by task title. And they lose signal in mechanical rooms. Todo apps don't survive that. Fieldmark starts from the PDF and works offline first.
Division of Labor
| Layer | Who |
|---|---|
| Field validation (test with crews) | Me |
| One-sentence spec | Me |
| Impact analysis, options, trade-offs | Claude |
| Implementation, Riverpod codegen, git | Claude |
| Device test | Me |
| DEVLOG entry (Problem → Decision → Result → Lesson) | Claude, after every session |
Prompt Architecture — Analyze → Propose → Decide → Implement
CLAUDE.md defines a four-stage gate:
CLAUDE.md — the four-stage gateprompt
I state the problem, Claude analyzes and proposes 2–3 options with trade-offs, I decide, then Claude implements. No code before decision. Any change touching more than 2 files or a UX flow gets a written plan first.
The knowledge layer is DEVLOG.md, structured as Problem/Decision/Result/Lesson blocks. It's not a diary — it's the memory Claude loads next session so we don't re-litigate solved problems. .claude/settings.local.json pre-permits 30+ flutter/git commands so nothing stalls on approval prompts.
Iteration Moment — Apple Sign-In rewrite
Initial build used Supabase's web-based signInWithOAuth for Apple. Apple review rejected Build 20 with Guideline 2.1(a): sign-in flow broken.
feat(auth): switch Sign in with Apple to native ASAuthorization (build 21) — pivoted to native ASAuthorization with nonce + sha256 validation. 5 files changed. Submitted the next morning, 2026-09-19 071b10c.
Build 20 → Build 21 · the 18-hour rejection-resubmit loop
BeforeBuild 20 — web OAuth path, bounced on Guideline 2.1(a)
2026-09-12 · f05b752
- Person / role
- Process step
- Decision / gate
- Outcome
- Flow
Read as steps (4)
- 01Dev → signInWithOAuth
- 02signInWithOAuth → Submit build 20
- 03Submit build 20 → Apple review
- 04Apple review → Rejection email (✕ denied)
AfterBuild 21 — native ASAuthorization, approved next morning
2026-09-18 → 09-19 · 8b18221 → 071b10c
- Data / signal
- Process step
- Outcome
- Flow
- Key path / outcome
Read as steps (4)
- 01Rejection as spec → ASAuthorization
- 02ASAuthorization → PKCE + credential
- 03PKCE + credential → Resubmit build 21
- 04Resubmit build 21 → Approved (✓ approved)
Lesson: When Apple bounces you on auth UX, Claude can implement the native replacement in one session — but only if DEVLOG already contains the rejection text verbatim. Feelings don't route back into code; error strings do.
Trade-Offs
Riverpod over Bloc
Less boilerplate, code generation, faster velocity on a solo project. Cost: fewer middleware plugins.
Supabase Postgres RLS over Firebase
Real row-level security in SQL. Cost: no built-in offline sync — handled by connectivity_plus + a local queue.
Native ASAuthorization over web OAuth
No redirect dance, Apple review passes. Cost: Apple client secret rotates every 6 months — automated with a Python script and a calendar reminder before the first user signed up.
PKCE flow
Required for native Apple Sign-In. Cost: nonce validation complexity — mitigated by codegen.
Results (honest)
PDF → pin → task card · the Build 21 steady state
- People · person / role
- Signal / data · data / signal
- Data store
- Server work · process step
- Gate · decision / gate
- Outcome
- Flow
- Key path / outcome
- Async / optional
Read as steps (10)
- 01Foreman → Floor plan PDF — upload
- 02Floor plan PDF → Pin placed — tap place
- 03Pin placed → Riverpod notifier
- 04Riverpod notifier → Online?
- 05Online? → Supabase + RLS — yes
- 06Online? → Offline queue — no (async / optional)
- 07Supabase + RLS → Firebase FCM — notify
- 08Supabase + RLS → Task card (✓ approved) — sync
- 09Offline queue → Supabase + RLS — reconnect (async / optional)
- 10Firebase FCM → Crew
Build 20 rejected → Build 21 submitted 2026-09-19 → approved and live on the App Store. Three post-launch bugs surfaced on real signups within days (OTP delivery, Delete Account, invitation idempotency across deletion) — all diagnosed root-cause and fixed, documented in DEVLOG.md so the next session doesn't re-litigate them.
Reflection
Rejection emails are the best specs. Guideline 2.1(a) with the reviewer's screenshot was cleaner than any AC I would have written myself.
- A DEVLOG that captures why survives context resets. Claude Code hits context limits mid-project; DEVLOG is what lets the next session pick up without me re-explaining.
- Automating the boring future task pays off before the future arrives. The 6-month Apple secret rotation script was written the same day as the auth pivot — because the pivot's context was the only time I'd remember to.
Receipts
How it was made
Token scorecard
- Complexity
- M
- Duration
- 4 days active
- Tier
- 1 · self-spec
Model mix
- Opus
- 89%
- Sonnet
- 11%
Have a Fieldmark-sized problem?
Send one paragraph about it. I reply within two business days with a scope and a fixed price.