New App Workflow

Every new app runs the same four stages. Each one has a fixed set of deliverables, and the next stage doesn't start until they exist.

STAGE 1 STAGE 2 STAGE 3 STAGE 4 Aim Sketch Architecture Ship why · terms · flows · scope wireframes, per flow three graphs + a log build | milestones

Stages and deliverables

#StageDeliverables
01 Aim
WHY.mdone person, one pain, the outcome, success in numbers, what this is not
DEFINITIONS.mdevery term defined once: the words the UI, the code, and conversation all use
FLOWS.mdmain flows: trigger, steps, outcome, written from the user's side
SCOPE.mdIn / Later / Never, with every In line naming the flow it protects
02 Sketch
STORYBOARDSone row of wireframes per flow, screens numbered by flow and step (3b = flow 3, step 2)
SCREEN MAPone navigation graph; a node no flow reaches is scope creep
03 Architecture
ENTITY MAPthe nouns, their labeled relationships, and what each one records
SYSTEM MAPthe parts, bought vs built, where state lives, every arrow labeled with what moves
FLOW TRACESa numbered index of every flow, plus a tree and numbered hops for each one worth tracing
DECISIONS.mdone line per decision, the stack included: date, choice, why, the rejected alternative
04 Ship
PLAN.mdvertical milestones, skeleton first, each ending in a demo; tickets carry flow numbers and one "done when" line
PROOF GRIDflow × pass/fail/blocked, walked end to end by someone who didn't build it
Standing rules

One page per document

A page is the target, not a hard limit. Write clearly and concisely rather than exhaustively.

Graphs stay glanceable

If one stops fitting on a screen, split it by concern or zoom out a level.

Everything inherits a flow number

Number the flows once, then every screen, ticket, and test carries the number of the flow it serves. If a piece of work can't name its flow, cut it.

Keep docs in sync with the build

When the build contradicts a doc, fix it that day and add a line to DECISIONS.md.

Appendices

Clipper gets a solo podcaster from published episode to postable clip in five minutes.

Appendix A · Aim

WHY.md
The person

Dana ships a weekly interview podcast, alone. No editor, no VA.

The pain

Cutting a promo clip takes about an hour in a desktop editor, so most weeks she skips it and the episode goes unpromoted.

The outcome

A postable clip within five minutes of publishing, every week.

Why now

Short clips are the one discovery channel working for shows her size, and she isn't in it.

Success, in numbers
  • Clip out in 5 minutes or less
  • 10 exports in week 1
  • 40% of week-1 users export again in week 2
What this is not

Not an editor. Not a scheduler. Not analytics.

DEFINITIONS.md
Show

A podcast feed connected by RSS. One Show per feed.

Episode

One published audio file from a Show, with its transcript.

Clip

A segment of an Episode, rendered as a captioned mp4 for sharing.

Moment

The transcript point Dana taps to start a Clip. Never stored; it becomes the Clip's start.

Words we don't use

Segment, snippet, cut. It is a Clip everywhere.

FLOWS.md
Flow 1 · connect the show

Empty episodes screen, paste RSS url, episodes appear. Outcome: latest episode ready to open.

Flow 2 · find the moment

Open episode, scroll transcript, tap a line to hear it. Outcome: the moment found without scrubbing audio.

Flow 3 · first export (expanded)
  • trigger · new episode published
  • step 1 · opens the episode
  • step 2 · marks the moment in the transcript
  • step 3 · taps export
  • outcome · clip saved, ready to post
FLOW 3 · FIRST EXPORT ep published opens the episode marks the moment taps export clip saved, ready to post
Flow 4 · post it

Share sheet with a captioned mp4. Outcome: the clip is live where her audience is.

SCOPE.md
In (v1)
  • Connect a show by RSS · flow 1
  • Transcript moment-picking · flow 2
  • Single-clip export, under 5 min · flow 3
  • Share sheet with captions baked in · flow 4
Later
  • Caption styling · multi-clip batches · scheduling · teams
Never
  • A timeline editor. The editor is the pain, not the product.
  • Analytics dashboards. Other tools do this well.

Appendix B · Sketch

Storyboard, one row per flow

Screens inherit flow numbers: 3b is flow 3, step 2.

3a transcript 3b mark 3c export 3d saved

Screen map

SCREEN MAP episodes 1a–1b · 2a transcript 2b · 3a–3b export 3c share 3d · 4a stats tap episode tap export render done no flow reaches it → cut it, or it's a new flow

Nodes carry the screen numbers they serve. A node with no numbers is a screen nobody asked for.

Appendix C · Architecture

Entity map

The names come from DEFINITIONS.md. Fields are logical identifiers and state, not a database schema.

Show Episode Clip contains is cut into

What each entity records

Show
 ├─ identity → showId
 ├─ feed address → feedUrl
 ├─ display name → title
 └─ last successful fetch → fetchedAt

Episode
 ├─ identity → episodeId
 ├─ Show → showId
 ├─ audio file → audioUrl
 ├─ transcript → transcriptKey
 ├─ published date → publishedAt
 └─ length → durationMs

Clip
 ├─ identity → clipId
 ├─ Episode → episodeId
 ├─ Moment in the Episode → startMs
 ├─ end of the Clip → endMs
 ├─ draft, rendering, ready, or failed → status
 └─ rendered file, once ready → fileKey

A Clip carries a fileKey only once its status is ready.

Re-fetching a feed adds Episodes and never edits existing ones, so a Clip's source cannot change underneath it.

System map

What talks to what, and what moves along each arrow.

app api store transcoder feed state lives here clips writes mp4 job rss dashed = not ours to build

Every arrow names what moves, state gets a badge, and dashed outlines are parts we do not build.

Flow traces

Use these flow numbers on screens, tickets, tests, and release notes. A hop number marks one system boundary.

FlowOutcome
F1Connect a Show and list its Episodes.
F2Find the Moment in an Episode without scrubbing audio.
F3Render a Clip from a Moment and save it.
F4Share a rendered Clip.

F1: connect a Show

Dana pastes a feed url
 └─ the app sends it to the api
    └─ the api fetches the feed from outside
       ├─ the feed is unreachable → nothing is saved, the app says so
       └─ the feed parses → the api saves the Show and its Episodes
          └─ the app lists the Episodes, newest first
app api feed store F1.1 feed url F1.2 fetch F1.3 rss xml F1.4 Show and Episodes F1.5 episode list

An unreachable feed writes nothing. There is no half-connected Show.

F3 starts from an Episode saved at F1.4.

F3: render a Clip

Dana marks a Moment in the transcript
 └─ the app asks the api to cut a Clip
    └─ the api saves the Clip as draft and queues a render
       └─ the transcoder renders the mp4
          ├─ the render fails → the Clip becomes failed
          └─ the render succeeds → the file lands in the store
             └─ the Clip becomes ready and the app shows it
app api transcoder store F3.1 Moment F3.3 render job F3.4 mp4 file F3.2 Clip as draft F3.5 render result F3.6 ready or failed

F3.2 writes the Clip before F3.3 queues the render, so a Clip always exists to carry the failed state.

A failed render leaves the Clip in failed and does not retry. Dana marks a new Moment.

F3 is the row that must be green on the proof grid before Ship.

F2 and F4 carry numbers but no trace. F2 reads what F1 already saved, and F4 hands a finished file to the operating system, so neither crosses a boundary the system map does not already show.

DECISIONS.md

One line per decision, the stack included. Written as the graphs take shape, and again whenever the build later overrules one. A decision that needs its argument written out also gets a file in docs/adr/, and its line points to it.

jul 29Expo for the appiOS and Android from one codebase, team of two · rejected: native Swift and Kotlin · docs/adr/0001-expo.md
aug 02Postgres for the apione region is enough at this size · rejected: Firebase
aug 12video files in R2, not the DBfiles run >100MB · rejected: blob columns
aug 19buy transcoding (Mux)not our fight · rejected: ffmpeg on workers · docs/adr/0002-buy-transcoding.md
sep 02Clip status is an enum, not a boolrendering can fail · rejected: is_ready flag

Appendix D · Ship

PLAN.md
EACH BLOCK ENDS IN A DEMO M1 skeleton M2 flow 3 full M3 flows 1–2 full M4 flow 4 + proof all flows, thin
M1 · walking skeleton

All flows, thin: hardcoded show, one transcript line, render, share sheet. Demo: the full path on a real device.

M2 · flow 3 full

Real moment marking, adjustable start and end, Clip statuses.

M3 · flows 1–2 full

RSS connect, transcript browsing and preview.

M4 · flow 4 full + proof

Baked-in captions on the share sheet, empty and failure states, then the proof pass.

A ticket, whole

#41 · flow 3 · screens 3b–3d · export to mp4 · done when: a real device puts the mp4 in the share sheet

Proof grid

Walked end to end by someone who didn't build it, on a real device.

PROOF GRID flow 1 · connect flow 2 · find moment flow 3 · first export flow 4 · post it pass pass fail blocked bug #62 waits on 3

Two bug piles only: blocks a flow, or goes to Later. Ship when the column is green.