Locations (Spaces) — Code Map
API
| File | Purpose |
|---|---|
apps/api/src/locations/locations.module.ts | Wires controller + service; imports MembershipsModule. |
apps/api/src/locations/locations.controller.ts | Routes, toLocationResponse mapper. |
apps/api/src/locations/locations.service.ts | CRUD + tier-limit check (maxSpaces) via @taikan/shared.checkTierLimit. List ordered by sortOrder, name. |
apps/api/src/locations/dto/create-location.dto.ts | name, address?, city?, country?, latitude?, longitude?, capacity?, concurrency? (exclusive|shared), sortOrder? (int ≥ 0). |
apps/api/src/locations/dto/update-location.dto.ts | PartialType of create. |
Routes (prefix organizations/:orgId/locations)
| Method | Path | Handler | Notes |
|---|---|---|---|
| POST | / | create | owner/admin + maxSpaces tier check |
| GET | / | list | any member |
| GET | /:id | getById | any member |
| PATCH | /:id | update | owner/admin |
| DELETE | /:id | remove (deactivate) | owner/admin |
Web
apps/web/src/components/onboarding/address-autocomplete.tsx— Google Places integration that fills address + city + country + lat/lng.apps/web/src/app/[lang]/(protected)/dashboard/settings/(shell)/locations/page.tsx— settings page, titled Spaces in the UI. RendersLocationsTab.apps/web/src/components/overview/schedule/locations-tab.tsx+location-dialog.tsx— list and create/edit dialog (i18n keys:schedule.locationsTab,schedule.locationSheet). Driver + spec:locations-tab.driver.tsx,locations-tab.int.spec.tsx.- Space pickers elsewhere:
class-type-dialog.tsx(default space),create-session-sheet.tsx/session-fields.tsx/session-detail-sheet.tsx(session space; required when thespacesflag is on and the org has two or more active spaces; owner/admin override dialog on the space 409s,space-override-dialog.tsx).
DB tables
| Table | Used as |
|---|---|
locations | Owned. |
organizations | Direct parent (FK on locations.organization_id). |
class_sessions | References location_id (nullable). Index class_sessions_location_starts_at_idx on (location_id, starts_at) serves the overlap check. |
class_types | default_location_id (nullable, ON DELETE SET NULL). |
Shared schemas
libs/shared/src/lib/schemas/scheduling.schema.ts—locationResponseSchema/LocationResponse({ id, name, address, city, country, latitude, longitude, capacity, concurrency, sortOrder, isActive, createdAt });spaceConcurrencyValues/SpaceConcurrency;spaceOverrideSchema;spaceConflictErrorSchema/spaceCapacityErrorSchema(409 bodies).libs/shared/src/lib/constants/scheduling-error-codes.ts—SchedulingErrorCodes.SPACE_CONFLICT(space_conflict),SPACE_CAPACITY_EXCEEDED(space_capacity_exceeded).libs/shared/src/lib/constants/feature-flags.ts—FeatureFlags.SPACES(spaces).checkTierLimit(platformTier, 'maxSpaces', currentCount)exported from@taikan/shared(platform-tiers.ts).
Migration
libs/db/drizzle/0167_spaces.sql — enum space_concurrency, locations.concurrency (default exclusive), locations.sort_order (default 0), class_types.default_location_id, index class_sessions_location_starts_at_idx.
Tests
No dedicated locations.service.unit.spec.ts found. Tier limit logic is covered via integration tests on the platform-tiers module. TODO: add unit tests for CRUD + tier rejection.