Compose flow review: create and edit song
What we checked in the Music Studio create / edit song flow, what is fixed, and what is next. For Leong, requested by Haikal, 2026-10-02. All three parts are done: A in v2.968 (server), B in v2.975, C in v2.984. Web version and server are live; phones get B and C with the next TestFlight build.

At a glance

Done7A · server security and money fixes, live since v2.968
Done6B · app bugs in the compose page, v2.975
Done4C · app enhancements, v2.984
Already safe before this review: nobody can edit, re-compose, tag, rename or change the cover of someone else's song. The server checks the owner on every one of those. Length limits, locked statuses (review / published / removed) and cover file checks are also enforced on the server, not only in the app.

A · Server security and money Done in v2.968

#Problem (before)Fix (now)Risk
A1Publishing an album or EP skipped the collaborator check and never locked the split. Example: A and B agree 90/10, A publishes the song inside an EP, tips get paid 50/50. A pending invite could still be accepted after release and start earning.Album / EP publish now checks every song going live, the same way single publish does. It stops with the song name and who it is waiting for. After publishing, the split is locked.High · money
A2Pressing Publish again on a live song reset its publish time, so a creator could keep it at the top of "New releases" and followers' feeds.Says "This song is already live" and changes nothing.Medium
A3Tapping re-compose twice quickly on the same song could overwrite one version's audio with the other's, show an error and use 2 daily songs.One compose at a time per song. The second tap says "This song is already being composed" and uses no quota.Medium
A4If the AI made the song but our server failed to save it, the user still lost 1 of 10 daily songs. Being blocked (not your song, song locked) also used a daily song.The daily song is given back when we fail. Blocked requests no longer use one.Low
A5If Redis had a problem, the daily limits on compose, magic pen and AI covers stopped counting. Every one of those is a paid AI call.When the counter fails, the request is refused with "busy, try again in a moment".Low
A6The 3 genres / 2 moods limit was only in the app. A direct API call could put one song in 5 genre pages.The server keeps the first 3 genres and 2 moods and drops the rest.Low
A7Small leaks and races: a stranger could see collaborator names through the publish error, or check who is on a song. The collaborator cap allowed 11 people instead of 10. Parallel requests could go past the 10 a day genre-suggestion limit.Owner is checked first ("This isn't your song", no names). Max 9 collaborators plus the owner, also under parallel invites. Suggestion limit holds under parallel requests.Low

How it was checked: for every item a test against a real database (or Redis) was written, then the fix was removed on purpose to confirm the test fails. One test was too weak the first time (it passed with the fix removed) and was replaced with a stricter one. The running server binary was checked to contain the new code. Tests: release_split_gate_1002_db_test, republish_1002_db_test, compose_lock_1002_test, song_tags_caps_1002_db_test, leaks_races_1002_db_test in backend/internal/domain/music/. No database migration; the app only changed its version number.

What users notice: almost nothing in normal use, since these only show when someone misuses the API or something fails. The one visible change: publishing an EP with a collaborator who hasn't accepted now stops and names them.

B · App bugs in the compose page Done in v2.975

#Problem (before)Fix (now)
B1"Save draft" still worked while a song was composing, so one song could end up as a draft plus a finished song.Save draft and Save are greyed out while composing.
B2After a failed compose, "Save draft" made a second draft instead of updating the one we rescued.It updates the rescued draft.
B3On "Try again", the old red failure box stayed up while it retried, so it looked like it was still failing.The old box clears the moment Try again starts.
B4No connection or a timeout: tapping Compose showed nothing on the page.A grey "No reply yet" box above Compose. Not red, because the song may still arrive; it clears when it does.
B5A song in review could open with a "Save draft" that always failed, and with "Save" hidden, so it couldn't be renamed.Songs in review open with Save.
B6Saving a draft dropped the More options (instrumental, exclude, vocal, length) and the picked cover. When editing, the cover box didn't show the current cover.Drafts keep all of these (one new database column, migration 000494). Editing shows the current cover.

C · Enhancements Done in v2.984

#BeforeNow
C1Swiping back with unsaved work lost everything, with no warning.Asks "Leave without saving?" with Keep editing / Save draft / Discard. Only when something changed; not while a song is composing (nothing is lost then).
C2While composing, the button was just grey for 30–120 s and every input still looked editable.The button shows a spinner and "Composing…" in the brand colour, and the form is locked until it finishes. Scrolling still works.
C3Collaborators and locked songs could still tap vocal, length and cover, but nothing could save them.Those controls are disabled there.
C4Magic pen and the clear-lyrics bin were small and 8 pt apart, and clearing had no undo.Clearing lyrics or style now shows an Undo for 5 seconds, so a slip is no longer lost. Bigger touch areas: not done yet, needs Leong. Making them 44 pt makes the card headers taller and shifts the whole page layout he tuned, so it's his call (see the question below).
Question for Leong: the magic pen (34 pt), clear buttons (32 pt) and the More options reset (30 pt) are below Apple's 44 pt minimum touch size. Enlarging their touch area makes each card header about 10 pt taller and moves everything below. OK to do that, or keep the current layout (the Undo now covers accidental clears)?
Found and fixed along the way: the app-wide toast had an invisible layer on top that blocked its own button. Every toast with an action, about seven places across the app (Undo in chat, "Start chat", "Add to folder"…), showed the button but couldn't be tapped. It works everywhere now.

How B and C were checked: one test per item on the real screen (only the network is faked), each fix broken on purpose once to confirm its test fails, and every test file that touches this page compared one by one with the current master before shipping.

Also checked this round