Skip to content

Add flowsheet write commands for the in-show workflow - #2

Merged
rybesh merged 1 commit into
mainfrom
flowsheet-write-core
Jul 10, 2026
Merged

rybesh merged 1 commit into
mainfrom
flowsheet-write-core

Conversation

@rybesh

@rybesh rybesh commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Adds the core on-air loop to wxyc flowsheet, so a DJ can drive their show from the CLI: start a show, add played tracks, log talksets and breakpoints, and close out.

Commands

wxyc flowsheet start [--name X] [--specialty ID] [--as "Name"] --write
wxyc flowsheet add --track T [--artist A --album AL --label L] [--album-id N] [--rotation-id N] [--segue] [--request] --write
wxyc flowsheet talkset --write
wxyc flowsheet breakpoint --write
wxyc flowsheet end --write

All are gated behind --write / WXYC_ALLOW_WRITE=1 (annotations + central gate, like bin add), and echo the created row — including its id — as a one-row table, or full JSON with --json.

Notes on backend semantics

  • start/end POST to /flowsheet/join and /flowsheet/end, auto-filling dj_id from the token claims (the same resolveDJID path djs playlists uses). The backend cross-checks dj_id against the authenticated user and 403s on a mismatch, so this is filled server-side-safe. start transparently covers the co-host case when a show is already live; end covers leave-as-co-host vs. end-the-show.
  • add omits blank artist/album/label when --album-id is given so the server takes its library-backfill path, and validates --artist+--album client-side otherwise (fail fast instead of a 400).
  • talkset/breakpoint send an explicit entry_type rather than relying on the server's message-text inference, so content can't be misclassified.
  • The DJ role holds flowsheet: ['read', 'write'] in the backend's auth.roles, so no 403 risk on the write endpoints themselves.

Plumbing

  • postRaw in internal/api/client.go — raw bytes for the decode-plus---json pattern the read methods already use.
  • Request/response types in types.go; write methods in internal/api/flowsheet_writes.go.

Tests

  • internal/api/flowsheet_writes_test.go — method/path/body assertions per write, optional-field omission, co-host vs. show-row decode, StatusError passthrough.
  • cmd/flowsheet_test.go — write-gate blocks without --write, dj_id derived from the token, client-side validation, confirmation output.

Full suite green; go vet clean.

Deferred (tracked in a follow-up issue)

move (reorder via PATCH /flowsheet/play-order), edit (PATCH /flowsheet), rm (DELETE /flowsheet), the note message command, and read helpers (latest/on-air/show).

🤖 Generated with Claude Code

Adds the core on-air loop to the flowsheet command: start/end a show,
add a played track, and log talksets and breakpoints. All are gated
behind --write like the existing bin add, and start/end fill dj_id from
the token so it matches the authenticated user (the backend 403s
otherwise).

- internal/api: postRaw helper (raw bytes for the decode + --json
  pattern the reads use), request/response types, and write methods in
  flowsheet_writes.go.
- cmd: start, add, talkset, breakpoint, end subcommands. add omits blank
  fields when --album-id is given so the server takes the backfill path,
  and validates artist/album client-side otherwise. Markers send an
  explicit entry_type rather than relying on server text inference.

Deferred to a follow-up: move (reorder), edit, rm, the note message
command, and the read helpers (latest/on-air/show).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rybesh
rybesh force-pushed the flowsheet-write-core branch from c013bd2 to 8e28a25 Compare July 10, 2026 17:16
@rybesh
rybesh merged commit 0763d8f into main Jul 10, 2026
1 check passed
rybesh pushed a commit that referenced this pull request Jul 10, 2026
Follow-up to the in-show write loop (#2), closing out the remaining
mutating flowsheet operations for mid-show correction (#3): reorder the
queue, edit an entry, and delete one.

Shared plumbing: factor postRaw's body-sending path into bodyRaw and add
patchRaw/deleteRaw on top of it. DELETE carries a JSON body (the backend
reads req.body.entry_id); the *bytes.Reader gives NewRequestWithContext a
GetBody so the auth Transport's 401-retry rewind still replays it — covered
by an explicit rewind test.

- flowsheet move <entry_id> <new_position>: PATCH /flowsheet/play-order,
  1-based, validated client-side.
- flowsheet edit <entry_id> [flags]: PATCH /flowsheet with only the flags
  changed (pointer/omitempty fields keyed off Flags().Changed), so unset is
  left alone and --flag "" clears; fails fast on no fields rather than a 400.
- flowsheet rm <entry_id>: DELETE /flowsheet, echoes the removed row, gated
  by --write.

All three decode the projected entry and reuse entryResultRows for the
confirmation; 404 maps to ExitNotFound.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rybesh pushed a commit that referenced this pull request Jul 10, 2026
Follow-up to the in-show write loop (#2), closing out the remaining
mutating flowsheet operations for mid-show correction (#3): reorder the
queue, edit an entry, and delete one.

Shared plumbing: factor postRaw's body-sending path into bodyRaw and add
patchRaw/deleteRaw on top of it. DELETE carries a JSON body (the backend
reads req.body.entry_id); the *bytes.Reader gives NewRequestWithContext a
GetBody so the auth Transport's 401-retry rewind still replays it — covered
by an explicit rewind test.

- flowsheet move <entry_id> <new_position>: PATCH /flowsheet/play-order,
  1-based, validated client-side.
- flowsheet edit <entry_id> [flags]: PATCH /flowsheet with only the flags
  changed (pointer/omitempty fields keyed off Flags().Changed), so unset is
  left alone and --flag "" clears; fails fast on no fields rather than a 400.
- flowsheet rm <entry_id>: DELETE /flowsheet, echoes the removed row, gated
  by --write.

All three decode the projected entry and reuse entryResultRows for the
confirmation; 404 maps to ExitNotFound.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rybesh added a commit that referenced this pull request Jul 11, 2026
* Add flowsheet move, edit, and rm commands

Follow-up to the in-show write loop (#2), closing out the remaining
mutating flowsheet operations for mid-show correction (#3): reorder the
queue, edit an entry, and delete one.

Shared plumbing: factor postRaw's body-sending path into bodyRaw and add
patchRaw/deleteRaw on top of it. DELETE carries a JSON body (the backend
reads req.body.entry_id); the *bytes.Reader gives NewRequestWithContext a
GetBody so the auth Transport's 401-retry rewind still replays it — covered
by an explicit rewind test.

- flowsheet move <entry_id> <new_position>: PATCH /flowsheet/play-order,
  1-based, validated client-side.
- flowsheet edit <entry_id> [flags]: PATCH /flowsheet with only the flags
  changed (pointer/omitempty fields keyed off Flags().Changed), so unset is
  left alone and --flag "" clears; fails fast on no fields rather than a 400.
- flowsheet rm <entry_id>: DELETE /flowsheet, echoes the removed row, gated
  by --write.

All three decode the projected entry and reuse entryResultRows for the
confirmation; 404 maps to ExitNotFound.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Clarify update-field clear semantics and type the delete request

The FlowsheetUpdateFields doc claimed a uniform "clear vs leave alone"
distinction, but omitempty on a pointer only expresses a true clear for
the string fields; the *int fields can send 0 but not null. Correct the
comment to say so.

Also give DELETE /flowsheet a typed flowsheetDeleteRequest to match the
move/update request structs instead of an inline map.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Sprite <noreply@sprites.dev>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant