Case Study · iOS
Marqo: What Changed, and Why
Freelancers, consultants and interior designers run on client decisions, and the reasoning behind them rarely gets written down. Marqo keeps the why beside the what, then turns any project into a read-only log the client opens in a browser without an account.
The Product Decision
The decision was to make the reasoning a field, not a note. Every decision carries a why, and the why is the product.
The what is easy to keep. A materials change, a revised layout, a shifted timeline: those land in email threads and project tools and survive on their own. The reasoning behind each one rarely gets written down anywhere, and it is the part nobody can reconstruct a month later.
Designers do not lose it through carelessness. They lose it because every available place to put it is too heavy to open mid-call. So I cut the input to three fields, and built the capture screen for one hand, on a phone, during the conversation where the decision actually gets made.
Key Facts
- Role
- Designer + developer, solo
- Scope
- iOS product, 0 to 1
- Craft
- Decision capture and client handoff
- Outcome
- Live, App Store
- A decision has three fields: what changed, why, and optionally what it affects. There are no status columns, assignees, or priority flags, because none of them serve the record.
- I designed capture for one hand, on a phone, mid-call or immediately after. The bar is less friction than the tools the user already runs, not hand-holding.
- Everything stays on the device. No server, no sync, no account.
- Destructive actions confirm in place. Deleting a project keeps its decisions: they move to Unassigned.
Architecture & Interaction
Marqo is built around one job: decision durability. Not project management.
Interaction Model
The product serves two readers from one record. The designer captures under time pressure and needs the entry finished in seconds, so the capture screen asks three questions and nothing else. The client reads later, without context, and needs the same record to look deliberate rather than defensive, so the export drops every editing control and groups decisions by month. Neither view is a simplified version of the other. They are different jobs performed on the same data, and the export is a separate document, because the client should not need the app at all.
Technical Implementation
React · Vite · CapacitorDesigned and built end to end, from problem framing through App Store release.
Local-First
The record lives on the device:
- No network call in the app
- Backup and restore the user controls
The simplest way to protect client reasoning is not to hold it.
The Client Export
A standalone HTML document:
- Opens in any browser, offline
- Shares through the standard iOS sheet
Nothing is hosted, so nothing can expire or leak.
Design System
A written contract, enforced:
- A nine-step type scale and a thirteen-step spacing grid on a 4px base
- A written list of what cannot change without instruction
- State matrices naming the states that cannot occur
- 44px minimum tap targets, asserted in tests. WCAG 2.1 AA on core flows
The contract is the brief for a person and the context for an AI agent.
Keeping the system consistent
The contract gets tested in small decisions. Late in the build, the Project screen needed a second control beside Share, and the pattern record forbids a fourth quiet-button variant. The sanctioned reuse candidate was a sentence-case rectangle, which beside an uppercase pill would have read as two unrelated controls. I extended the existing pill instead and added no variant. A test now locks the pair, so a later change cannot quietly break it.
Process
I defined the core job before any screen: capture a decision and its reasoning at the moment it happens, in a place that survives the project. I tested everything after that against it. A status field, an assignee, a priority flag: I considered each one and cut it. A field that does not serve the record makes the record slower to write, and therefore less likely to exist.
The handoff was the harder half. A client-facing log has to read as a record and never as evidence, so the export names what changed and why and stops there. It carries no status, no author, and no commentary. I made it a file rather than a link, because a link implies an account, and an account implies a system the client now has to keep.
I record design decisions in the repository as rules: a design contract, a pattern record, and state matrices naming the states a screen cannot reach as well as those it can. Those documents are what a person reads before changing something, and what an AI coding agent is given before it writes anything.
Validation
Five testers, five responsesA TestFlight pilot went out on the first build with three questions: did anything saved go missing, did you delete something you wanted back, did the capture screen slow you down. All three came back no. Five testers over two weeks cannot rule those failures out, but the answers were enough to change the build order: I demoted a fix I had ranked first.
What they volunteered mattered more than what they were asked
All five led with the client export, unprompted, and for the reason the product context had predicted before anyone saw it: one click, and the client cannot alter it. That is the one part of the product with observed evidence behind it, and it started as a written hypothesis.

All five also wanted a reason to come back. One put it plainly: "I used it and then I forgot." The obvious instrument is a time-based reminder, and I ruled it out. A nudge after three quiet days fires mostly on projects where nothing happened, which is how notifications get switched off. It also drifts adversarial, against a product meant to keep you aligned with a client rather than win against one.
One tester offered an explanation: the client was not difficult, and a harder one would have had them in the app more. I recorded that as a hypothesis rather than the finding. One articulate answer is the most dangerous kind to adopt on behalf of four people who reported the same symptom without a reason. If it does hold, it is not a reminder problem. The decisions worth logging are made during the easy phase, when nothing feels worth logging, so a trigger that waits for a client to turn difficult arrives after the window has closed.
Impact
Marqo shipped to the App Store as a subscription product, taken from problem framing through review and release.
- The client log is a file, not a hosted page. It works offline, outlives any subscription, and needs nothing from the client but a browser.
- Single-author capture is deliberate. The product is shaped for one person keeping a record, not a team negotiating one.
- Deleting a project keeps its decisions. They move to Unassigned, because the record is the thing worth protecting.
The scope is intentionally narrow, but structurally disciplined: one job, three fields, and a handoff that asks nothing of the person receiving it.
Reflection
The tradeoff I accepted was reach. Building for a single author, with no sync and no shared workspace, rules out the teams that would otherwise be the larger market. It was the right call for this product. The moment worth designing for is one person, on a phone, immediately after a decision, and a multi-user model would have added an account to the one flow that cannot afford one.
The structural payoff was the export. Treating the client view as a document rather than a screen removed a whole category of work: no permissions model, no expiring links, no hosting, and no account for the client to maintain. Deciding what the product would not hold turned out to define it more than deciding what it would.

