title: "Scaffold the audio module and its resources"
context: |
Build an `audio` domain: users upload audio they own; admins manage any. The
source file and cover art are stored by the app (not external URLs), and a new
audio runs through a pipeline (upload → processing → published) before it is
playable. Auth is owner-or-admin on every mutation. If `modules/audio/`
already exists, this work is void — do not run.
goal: |
Create the `audio` module + needed resources, wired owner-or-admin on mutations.
## Notes
- If `modules/audio/` exists, STOP and report. Else `/module:create` audio,
then build each resource via its `*:create` skill (`--module=audio`),
respecting controllers → services → repositories → entities, registering all.
- Judge each resource; create the justified, skip the rest with a reason.
Defaults: entity + repository always; service + controller per use case;
permission always (owner-or-admin on update/delete, reuse the permission
service); storage always (file + cover art); queue if the project uses queues
(route uploads/re-processing — transcoding is long-running); workflow yes
(reversible upload → processing → published that rolls back artifacts + DB
together on failure); migration/seed/event/translation only if applicable.
- On delete, remove the stored file and cover art; never orphan blobs.
- Throw typed exceptions (e.g. `AudioNotFoundException`), never return null.
### Data Model
- `Audio.owner` ↔ `User.audios` — ManyToOne / OneToMany
dod: |
- [ ] Aborts with a report if `modules/audio/` exists
- [ ] `audio` module created and registered into the app and `SharedModule`
- [ ] `Audio` entity with fields: `title`, `slug` (unique), `description`,
`icon`, `color` (`SimpleColorType`), `src`, `cover`, `duration`, `status`
(upload → processing → published), `plays`, `publishedAt`, `lang`
(`LocaleType`), `owner`, `createdAt`, `updatedAt`
- [ ] Full CRUD (create = upload); file + cover stored via storage, not URLs
- [ ] User mutates only their own, admin any; non-owner/non-admin rejected
- [ ] Delete removes stored file + cover art
- [ ] Lifecycle rolls back artifacts + DB together on failure
- [ ] If queues are used, uploads/re-processing run through a queue
- [ ] Unneeded resources skipped and reported with a reason
- [ ] `bun run fmt`, `bun run lint`, `bun run test` pass from the root