Case study · One Frame
One photograph and
one sentence a day
A local-first Android journal whose whole design is a refusal: today only, on this device only. Taken to a signed release build and validated on hardware, then deliberately not shipped to a store.
- CI
- TESTS
- RELEASE
- DEVICE QA
- REPORT

Product decisions
The constraint is the product
Today only
One entry per local calendar day, enforced by the database key rather than by the interface. You can rewrite today as often as you like; you cannot fill in yesterday.
A missed day stays missed
A journal you can backfill becomes a backlog, and a backlog becomes homework. The calendar shows the gap instead of inviting you to repair it.
No account, no server
V1 has no backend at all. Which also means uninstalling loses everything — so the app says that on the first screen, before anyone has anything to lose.
Backup is the user's job, stated plainly
One encrypted file through the system share sheet, with the part most apps leave out: forget the password and nobody can recover it.
Implementation evidence
The repository is private, so most of this is Partial rather than verified: the unedited output of each command is committed to this site and can be read, but you cannot re-run it yourself. That distinction is kept rather than smoothed over.
| Claim supported | Status | Evidence |
|---|---|---|
The local-first data and backup paths hold flutter test — 220 tests passed. The source repository is private, so the unedited output is committed here: readable, not re-runnable | PARTIAL | Open ↗ |
A release build refuses to produce an unsigned artifact flutter build apk --release fails by design when the signing key is absent. A green build here would mean signing had regressed to the debug key | PARTIAL | Open ↗ |
Quality workflow green on the default branch Format, analyze, test and Android build. The repository is private, so the run itself is not publicly inspectable | PARTIAL | — |
The app was run and photographed on an Android device Three screens captured on hardware. Screenshots are the artifact; there is no public run to accompany them | PARTIAL | Open ↗ |
The privacy position is published and checkable Public repository holding the privacy policy | VERIFIED | Open ↗ |
Source code Private repository. Access for review on request | UNAVAILABLE | — |
Play Store or App Store publication Not published to any store, and no store listing is claimed. No GitHub release exists either | UNAVAILABLE | — |
The release gate, and why it is a failing build
In a clean checkout the release build fails, on purpose: the signing key is gitignored, so Gradle refuses rather than falling back to the debug key. A green build in that state would mean signing had silently regressed.
Distribution and access
Stated here rather than left for a client to discover.
- —The source repository is private. The committed command output is what a reader can inspect — it can be read, not re-run.
- —Not published to Google Play or the App Store, and there is no GitHub release. The Android build exists; distribution does not.
- —iOS is a release-parity target, not a shipped platform. No iOS build has been verified here.
- —No sync, no cloud backup and no account, by design rather than by omission.
- —A portfolio project with no users.