Skip to main content

property-service — Service Overview

Companion: Summary · Service Template · Naming · 02 Enterprise Architecture · 05 API Design · 06 Data Models · 07 Security & Tenancy

1. One-paragraph mission

property-service is the system of record for the physical inventory every Ghasi Melmastoon tenant sells: the property (hotel, guesthouse, melmastoon), its room types, individual rooms, amenities, photos, policies, and geo-coordinates. It feeds four downstream surfaces: the consumer meta-search index (cross-tenant, read-only), the per-tenant booking site catalog, the Electron desktop backoffice (with offline replication), and the AI orchestrator (for description drafts, photo tagging, and amenity suggestion). It does not own pricing, availability, housekeeping state, or theme visuals.

2. Bounded Context Position

FieldValue
Bounded ContextProperty
Domain TypeCore
Strategic intentDifferentiator: regionally meaningful amenity vocabulary, multi-language fields (Pashto/Dari/Persian/Tajik/EN), PostGIS-backed map, offline-first room state
Upstream contextsIdentity, Tenant, File Storage, Lock Integration, Housekeeping, Maintenance
Downstream contextsInventory, Pricing, Reservation, Search Aggregation, Theme Config (read for slug), BFFs (consumer / tenant-booking / backoffice)
Pattern with downstreamOpen Host Service (REST + Published Language events)
Shared kernelTenantId, I18nString, MediaRef, AddressLine, GeoPoint, AIProvenance from @ghasi/contracts-melmastoon

3. Capabilities

CapabilityNotes
Property CRUDCreate / read / update / soft-delete with multi-language fields; status machine draft → published → unpublished → archived
Property publish gateValidates rooms ≥ 1, geo present, name + description in default locale, ≥ 1 ready photo, terms accepted
Geo locationgeography(POINT, 4326); bounding-box and nearby (great-circle) queries; tile-friendly result shapes for Leaflet
Room type catalogKing / Twin / Suite / Family / Dorm / Apartment with bed configs and max occupancy
Individual roomsNumber, floor, status (active / out_of_order / out_of_service / archived), accessibility flags, lock device binding
AmenitiesCanonical registry + per-property selection; regional codes (halal kitchen, prayer room, generator, hot-water schedule, women-only floor)
PhotosSigned-URL upload via file-storage-service; ordered set per property; per-room-type photos
PoliciesProperty-level overrides for tenant defaults: check-in/out, cancellation, child, smoking, pets, deposit, ID required
Room groupsFloor / building / wing for housekeeping routing and operator UX
SyncExposes change stream to bff-backoffice-service for `/sync/v1/pull
AIDescription draft, photo auto-tagging, amenity suggestion, geocode fallback (HITL)

4. Non-Capabilities (explicitly out of scope)

CapabilityOwned by
Per-night availability and holdsinventory-service
Rate plans, prices, derivationspricing-service
Live housekeeping state machine (clean / dirty / inspected timeline)housekeeping-service
Maintenance work ordersmaintenance-service
Reservations, walk-ins, check-in/outreservation-service
Theme tokens, layouts, hero imagestheme-config-service
Cross-tenant search index and rankersearch-aggregation-service
Lock device hardware integrationlock-integration-service
File bytes, virus scan, retentionfile-storage-service
Tax / VAT / locale defaultstenant-service

5. Architecture (Clean / Hexagonal)

property-service/
└── src/
├── domain/ # pure: aggregates, VOs, domain events, invariants
│ ├── property/
│ │ ├── Property.ts # Property aggregate root
│ │ ├── PropertyStatus.ts # VO enum + transitions
│ │ ├── PropertyPublished.ts # invariant set for publish
│ │ └── events/ # PropertyCreated, PropertyPublished, ...
│ ├── room-type/
│ │ ├── RoomType.ts
│ │ ├── BedConfig.ts # VO
│ │ └── events/
│ ├── room/
│ │ ├── Room.ts
│ │ ├── RoomStatus.ts
│ │ ├── RoomNumber.ts # VO with normalization rules
│ │ └── events/
│ ├── photo/
│ │ ├── Photo.ts
│ │ ├── PhotoOrder.ts # VO with reorder algebra
│ │ └── events/
│ ├── policy/
│ │ ├── PropertyPolicies.ts # aggregate of overrides
│ │ └── events/
│ ├── amenity/
│ │ ├── AmenityCode.ts # VO matching canonical registry
│ │ └── AmenityRegistry.ts # in-memory canonical list
│ ├── room-group/
│ │ └── RoomGroup.ts
│ └── shared/
│ ├── PropertyId.ts # branded ID `ppt_…`
│ ├── RoomTypeId.ts # `rmt_…`
│ ├── RoomId.ts # `rmu_…`
│ ├── PhotoId.ts # `pht_…`
│ ├── PolicyId.ts # `pol_…`
│ ├── AmenityId.ts # `amn_…`
│ ├── RoomGroupId.ts # `rgp_…`
│ └── errors/
├── application/ # use cases, ports, CQRS handlers
│ ├── ports/
│ │ ├── PropertyRepository.ts
│ │ ├── RoomTypeRepository.ts
│ │ ├── RoomRepository.ts
│ │ ├── PhotoRepository.ts
│ │ ├── PolicyRepository.ts
│ │ ├── RoomGroupRepository.ts
│ │ ├── AmenityRegistry.ts
│ │ ├── EventPublisher.ts # outbox publisher
│ │ ├── FileStoragePort.ts # signed URL request
│ │ ├── GeocodePort.ts
│ │ ├── AIClient.ts
│ │ ├── ReservationLookupPort.ts # check active reservations on a room
│ │ └── Clock.ts
│ ├── commands/ # one file per command + handler
│ ├── queries/ # query handlers
│ ├── sagas/ # nothing local; this service hosts choreography only
│ └── policies/ # publish-eligibility, OOO-eligibility
├── infrastructure/ # adapters
│ ├── postgres/
│ │ ├── PropertyRepositoryPg.ts
│ │ ├── RoomTypeRepositoryPg.ts
│ │ ├── RoomRepositoryPg.ts
│ │ ├── PhotoRepositoryPg.ts
│ │ ├── PolicyRepositoryPg.ts
│ │ ├── RoomGroupRepositoryPg.ts
│ │ ├── OutboxRepositoryPg.ts
│ │ ├── InboxRepositoryPg.ts
│ │ └── tenant-context.ts # SET LOCAL app.tenant_id
│ ├── pubsub/
│ │ ├── EventPublisherPubSub.ts
│ │ └── consumers/ # tenant.created, housekeeping.maintenance_required, etc.
│ ├── filestorage/
│ │ └── FileStorageHttpAdapter.ts
│ ├── geocode/
│ │ ├── GoogleMapsGeocodeAdapter.ts
│ │ └── OpenCageGeocodeAdapter.ts
│ ├── ai/
│ │ └── AIClientHttpAdapter.ts
│ ├── reservation/
│ │ └── ReservationLookupHttpAdapter.ts
│ └── cache/
│ └── PropertyCacheRedis.ts
└── presentation/ # controllers, DTOs, OpenAPI
├── http/
│ ├── PropertiesController.ts
│ ├── RoomTypesController.ts
│ ├── RoomsController.ts
│ ├── PhotosController.ts
│ ├── PoliciesController.ts
│ ├── AmenitiesController.ts
│ ├── RoomGroupsController.ts
│ ├── GeoController.ts
│ ├── SyncController.ts # /internal/v1/property/changes
│ └── HealthController.ts
└── dto/
├── PropertyDto.ts
├── RoomTypeDto.ts
├── RoomDto.ts
├── PhotoDto.ts
└── PolicyDto.ts

Dependency rule: presentation → application → domain, infrastructure → application (adapters implement ports). domain imports nothing outside itself and @ghasi/contracts-melmastoon shared-kernel VOs.

6. Tech Stack

LayerChoice
Language / runtimeTypeScript on Node 20 LTS
HTTP frameworkNestJS (Fastify adapter)
ORM / DB driverpg + kysely (typed query builder); migrations via node-pg-migrate
Validationzod for DTOs and event payloads
MessagingGCP Pub/Sub (transactional outbox)
CacheMemorystore (Redis 7)
GeoPostGIS 3.x extension
Loggingpino JSON
TracingOpenTelemetry → Cloud Trace
MetricsOpenTelemetry → Cloud Monitoring

7. SLOs

SLITarget
API p95 latency (read)≤ 80 ms
API p95 latency (write)≤ 250 ms
Availability99.9 % monthly
Outbox publish lag (p95)≤ 2 s
Search projection freshness≤ 5 s after publish
RLS leak0
Photo upload signed-URL acquisitionp95 ≤ 200 ms

8. Quotas / limits per tenant (defaults; overridable by plan)

ResourceDefault cap
Properties100
RoomTypes per property50
Rooms per property2 000
Photos per property200
Photos per room type30
Bulk room create batch size200 per call
Geo nearby radius100 km
Geo bbox area5 000 km²

Plan-level overrides come from tenant-service via tenant.plan_changed.v1.

9. Risks Snapshot

RiskMitigation
Cross-tenant leak via geo bboxRLS + WHERE tenant_id enforced by query layer; audited test
Stale projection in searchdedicated outbox publisher SLO + replay endpoint
OOO during occupied staydomain guard + reservation lookup port
AI photo tagging hallucinated amenityHITL-only; never auto-applied
PostGIS misconfigurationinfra-as-code + smoke test in deploy pipeline

Full register: SERVICE_RISK_REGISTER.

10. Definition of Ready / Done

  • Ready (per story): AC, NFRs, OpenAPI delta, event schema delta, tenancy implications, AI provenance, sync impact, observability, runbook entry.
  • Done (per story): tests in pyramid (unit, integration, contract, sync, AI), tenant-isolation spec passes, outbox spec passes, OpenAPI lint passes, dashboards updated, ADR if cross-cutting.

11. Glossary

TermMeaning
PropertySellable physical site (hotel, guesthouse, melmastoon) within a tenant.
RoomTypeSellable category (King, Twin, Suite, Family, Dorm, Apartment) with bed config + max occupancy.
RoomIndividual physical room (numbered) belonging to one RoomType.
AmenityCanonical tag from the platform registry (wifi, halal_kitchen, …).
PolicyProperty-level override of tenant defaults (check-in/out, cancellation, …).
RoomGroupLogical grouping of rooms (floor, wing, building).
OOOOut of Order — temporarily unsellable, e.g., maintenance.
OOSOut of Service — long-term decommissioned.
PublishStatus transition that exposes the property to search and booking surfaces.