title: "Scaffold the address module and its resources"
context: |
Build an `address` domain: private postal addresses owned by a user (billing,
shipping). Addresses are personal data, never readable by other users — auth
is owner-or-admin on EVERY operation, reads and lists included. Each user has
at most one default address. An address points at a shared `City` (city
module) for city/region/country/coordinates; it stores only street-specific
data. If `modules/address/` already exists, this work is void — do not run.
goal: |
Create the `address` module + needed resources, wired owner-or-admin on every op.
## Notes
- If `modules/address/` exists, STOP and report. Else `/module:create` address,
then build each resource via its `*:create` skill (`--module=address`),
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 read, list, update, delete — reuse the
permission service, never hand-roll); migration if the project uses
migrations; seed if it uses seeds; event/queue/translation/storage/workflow —
skip (private data, no files, no lifecycle).
- Depends on `city`: confirm `modules/city/` exists, wire a `City` relation, and
reject an address whose `city` does not resolve. Do not duplicate city fields.
- Single default per user: on create/update with `isDefault` true, atomically
clear it on the user's other addresses.
- Throw typed exceptions (e.g. `AddressNotFoundException`), never return null;
another user's address must return the same not-found result.
### Data Model
- `Address.owner` ↔ `User.addresses` — ManyToOne / OneToMany
- `Address.city` ↔ `City.addresses` — ManyToOne / OneToMany
dod: |
- [ ] Aborts with a report if `modules/address/` exists
- [ ] `address` module created and registered into the app and `SharedModule`
- [ ] `Address` entity with fields: `label`, `type` (billing/shipping),
`recipient`, `phone`, `line1`, `line2` (nullable), `postalCode`, `city`
(City relation), `latitude`/`longitude` (nullable), `isDefault`, `owner`,
`createdAt`, `updatedAt`
- [ ] Full CRUD; user accesses only their own, admin any; another user's
address returns not-found
- [ ] References a `City`, not free-text geo; unresolved `city` rejected
- [ ] Setting default demotes the previous default
- [ ] Unneeded resources skipped and reported with a reason
- [ ] `bun run fmt`, `bun run lint`, `bun run test` pass from the root