---
feature: Cities and categories
slug: catalog
surface: admin
consumer: vue
version: 1.0.0
status: in-progress
brd_version: "Morvia Project Guide"
brd_ids: [ADM-043, ADM-044]
business_rules: [BR-CRS-11, BR-ACC-03]
decisions: [TD-11, TD-14]
schema_tables: [cities, city_translations, countries]
related_docs: []
last_updated: 2026-11-12
---

# Cities and categories — Admin integration

## Quick reference

| | |
|---|---|
| Version | 1.0.0 (2026-11-12); dashboard action: integrate cities with the limitations below. |
| Status | In progress: ADM-043 cities; ADM-044 category integration remains outstanding. |
| Auth | Bearer token; admin route names are permission keys. |

| Method | Path | Permission | Purpose |
|---|---|---|---|
| GET | /cities | admin.cities.index | List cities |
| POST | /cities | admin.cities.store | Create city |
| GET | /cities/{city} | admin.cities.show | Details and translations |
| PUT/PATCH | /cities/{city} | admin.cities.update | Partial update, including activation |
| DELETE | /cities/{city} | admin.cities.destroy | Deactivate and retain links |

Paths are relative to `/api/v1/admin`. Route IDs and country references are UUID strings. 422 means invalid input; 403 means access denied in environments enforcing RBAC. The existing middleware bypasses RBAC in local/testing. See known limitations below before integrating.

## 1. Business summary

Administrators manage bilingual city names, country and active status. Deactivation retains existing links.

## 2. Pages and permissions

Use the route names above for the corresponding list, detail, create, edit and deactivate actions.

## 3. List / table

`GET /cities` supports `search` across names and searchable fields, `filters[is_active]`, `filters[country_id]`, `sort[name]`, `sort[sort_order]`, `sort[is_active]`, `sort[country_id]`, `per_page`, `page`, and `paginate=false`. The list resource provides UUID `id`, localized `name`, `country_id`, localized `country`, `is_active`, `sort_order`, and `created_at`. Integer counts are always present: `courses_count`, `trainers_count`, `halls_count`, `training_centers_count`, and `hall_providers_count`. Trainers are counted through their user city.

## 4. Details view

`GET /cities/{city}` returns the list fields, `updated_at` and `en.name` and `ar.name`.

## 5. Forms (create / edit)

| Field | Create | Validation |
|---|---|---|
| country_id | required | UUID, existing country UUID |
| en.name, ar.name | required | string, maximum 255 characters |
| is_active | optional | boolean |
| sort_order | optional | integer, minimum 0 |

All fields are optional on update. Create and update return the detail resource, including UUID references, counts and translations.

## 6. Actions (non-CRUD)

Set `is_active` through update; DELETE also sets it to false. Neither removes a city or its links. A later update can reactivate it.

## 7. Statuses and enums

`is_active` is a boolean. This feature has no enum fields.

## Data model

`cities` and `city_translations` are read and written; `countries` is read.

## 8. TypeScript types

List items have UUID `id` and `country_id`, string or null `name` and `country`, boolean `is_active`, numeric `sort_order`, and nullable `created_at`.

## 9. Business rules enforced by the backend

Deactivation preserves the city and historical links. `App\Domain\Catalog\Rules\ActiveCity::exists()` provides a rule for new or changed city selections. Consuming record-creation flows must explicitly use it; it is not automatically enforced across the application.

## 10. Notifications triggered

N/A.

## 11. Integration checklist

- Gate controls using the route permissions and handle 403 and 422.
- Send both translations on create and use partial updates for status changes.
- Respect the limitations below.

## 12. Acceptance scenarios

ADM-043: list, create, edit, deactivate and reactivate cities; retain old links. Feature tests cover these actions, validation, filtering and 403.

## 13. Open decisions and known limitations

- ADM-044 category integration documentation is outstanding; the combined catalog feature is not complete.
- No existing request or service accepts a city selection for a new or changed link; future flows must apply the active-city rule while retaining unchanged inactive links.
- RBAC is bypassed by existing middleware in local and testing environments.

## Version history

| Version | Date | Type | Summary | Dashboard action required |
|---|---|---|---|---|
| 1.0.0 | 2026-11-12 | MAJOR | UUID references and usage counts. | Use UUIDs for city routes and country references. |
| 0.1.0 | 2026-11-12 | Initial | City CRUD; catalog incomplete. | Integrate with limitations above. |

## Changelog

### 1.0.0 — 2026-11-12

- City routes and country references use UUIDs; list and detail include linked counts.
- Dashboard action required: replace numeric identifiers with UUID strings.

### 0.1.0 — 2026-11-12

- Added city management and a reusable active-city rule (ADM-043, BR-CRS-11).
- Dashboard action required: integrate the city endpoints and account for the limitations above.
