title: "Scaffold the event module and its resources"
context: |
Build an `event` domain: a calendar event a user organizes and others attend.
The organizer owns it; an admin manages any. (This is a domain entity — a
scheduled happening with start/end — not the framework's pub/sub event resource
type, which is one of the resources below.) Auth is owner-or-admin on every
mutation; an attendee link never grants ownership. An event has a window
(`startsAt` → `endsAt`) and attendees; its location is either an online
`meetingUrl` or an in-person `Address` drawn from the organizer's own addresses
(address module). If `modules/event/` already exists, this work is void — do not run.
goal: |
Create the `event` module + needed resources, wired owner-or-admin on mutations.
## Notes
- Run autonomously — do NOT ask the user questions. At every option or
judgment call, pick the recommended/default and proceed, reporting the
choices made in the final summary.
- If `modules/event/` exists, STOP and report. Else `/module:create` event, then
build each resource via its `*:create` skill (`--module=event`), respecting
controllers → services → repositories → entities, registering all.
- Destination — the `/module:create` step takes a `--destination` arg: pass
`app` when the project has a single `api` module; when it has several
`api`/`microservice` modules, infer the destination from this request.
- Dependencies — `user`, `address`. Resolve before the `/module:create` step
above: for each missing `modules/<dep>/`, create it FIRST from its prompt at
https://docs.talosjs.com/ai/prompts/resources/<dep>-resource (resolving its
own dependencies transitively — `address` itself depends on `city`).
- 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); event (pub/sub) a strong fit — emit on create/update/cancel to
notify attendees, only if something subscribes; queue if the project uses
queues (route attendee notifications/reminders — fan-out off the request
thread); migration/seed/translation only if applicable; storage/workflow skip
(the cover is a plain URL/path reference, not an upload; status moves freely).
- Wire the `Address` relation; do not redefine address fields.
- Validate location by mode: online (`isOnline` true) → `meetingUrl`, no
address; in-person → `address`, no `meetingUrl`. Reject mixed/missing.
- The referenced `address` must belong to the event's owner; reject another
user's address.
- Reject `endsAt` not strictly after `startsAt`. When `capacity` is set, reject
attendees beyond it (unset = unlimited). Attendees get no update/delete rights.
- Throw typed exceptions (e.g. `EventNotFoundException`), never return null.
### Data Model
- `Event.owner` ↔ `User.events` — ManyToOne / OneToMany
- `Event.address` ↔ `Address.events` — ManyToOne / OneToMany (nullable for online)
- `Event.attendees` ↔ `User.attendingEvents` — ManyToMany
dod: |
- [ ] Aborts with a report if `modules/event/` exists
- [ ] Missing dependency modules (`user`, `address`) created first from their docs prompts
- [ ] `event` module created and registered into the app and `SharedModule`
- [ ] `Event` entity with fields: `title`, `slug` (unique), `description`,
`icon`, `color` (`SimpleColorType`), `cover`, `status` (`StatusType`,
scheduled → active → completed), `isOnline`, `meetingUrl` (nullable),
`address` (nullable), `startsAt`, `endsAt`, `timezone`, `capacity`
(nullable), `lang` (`LocaleType`), `owner`, `attendees`, `createdAt`, `updatedAt`
- [ ] Full CRUD; user mutates only their own, admin any; non-owner/non-admin
rejected; attending grants no update/delete
- [ ] In-person references an `Address` (not free text); online has
`meetingUrl`/no address, in-person has address/no `meetingUrl`
- [ ] Address not owned by the event owner rejected; `endsAt` ≤ `startsAt`
rejected; attendee beyond `capacity` rejected
- [ ] If queues are used, attendee notifications 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