Skip to main content

Places Directory

The Places Directory is Concordia’s core feature for managing physical establishments and points of interest. It supports multi-language translations, dynamic attributes, and a complete ownership model where proprietors can manage their own listings.

Overview

The directory system enables:
  • Submission and management of places by proprietors (owners)
  • Multi-language translations for international reach
  • Dynamic attribute system for flexible place characteristics
  • Moderation workflow with status management
  • Integration with reviews, bookings, and services

Place Entity

Based on the specifications in concordia-specs.md, places represent physical establishments or points of interest.

Core Fields

id
uuid
required
Unique identifier for the place
owner_id
uuid
required
Reference to the user who owns/manages this place. User must have the owner role.
category_id
uuid
required
Reference to a leaf category of type place. Categories can be hierarchical (max 3 levels).
slug
text
required
Unique URL-friendly identifier (2-220 chars, alphanumeric + hyphens)Example: "hotel-du-parc-paris"
type
enum
required
Place type from: restaurant, hotel, camping, commerce, admin, activity, poi, trail, balade, randonnee, velo
address_id
uuid
Optional reference to normalized address with geolocation
latitude
decimal(10,7)
Latitude coordinate (-90 to 90)Example: 48.8566969
longitude
decimal(10,7)
Longitude coordinate (-180 to 180)Example: 2.3514616

Contact Information

email
text
Contact email for the establishment
phone
text
Phone number in E.164 format
website
text
Valid URL for the establishment’s website

Business Details

open_hours
jsonb
Structured JSON object with opening hours by day of week
{
  "monday": [{"open": "07:00", "close": "23:00"}],
  "tuesday": [{"open": "07:00", "close": "23:00"}]
}
accessibility
text[]
Accessibility featuresExample: ["wheelchair", "elevator"]
audience
text[]
Target audience labelsExample: ["families", "couples", "business"]
price_range
enum
Price level: low, medium, high, luxury

Ratings

rating_avg
decimal(2,1)
Average rating (0.0 to 5.0), calculated automatically from reviewsExample: 4.2
rating_count
integer
Total number of published reviewsExample: 42

Status Workflow

Places follow a state machine for moderation:
status
enum
default:"pending_review"
required
Current status: pending_review, published, archived, rejected

State Transitions

When status transitions to published, the published_at timestamp is automatically set.

Multi-Language Translations

From concordia-specs.md (lines 484-502), places support translations via the place_translation table:

Translation Fields

place_id
uuid
required
Reference to the parent place
language
text
required
ISO 639-1 language code: fr, en, ar, es
name
text
required
Translated name (2-200 chars)Example: "Hôtel du Parc"
description
text
Translated description (max 2000 chars)Example: "Un hôtel charmant au cœur de la ville..."
A place must have at least one translation in the owner’s preferred language. The composite key (place_id, language) ensures uniqueness.

Dynamic Attributes

The attribute system allows flexible, admin-defined characteristics for places.

Attribute Definition

From concordia-specs.md (lines 337-359), administrators create attribute definitions:
name
text
required
Attribute name (2-100 chars, globally unique)Example: "Wifi"
value_type
enum
required
Data type: boolean, string, integer, decimal, enum
possible_values
text[]
Required if value_type is enumExample: ["gratuit", "payant"]
applicable_category_ids
uuid[]
Categories this attribute applies to (null = all categories)

Attribute Values

From concordia-specs.md (lines 504-521), owners set values via place_attribute_value:
place_id
uuid
required
Reference to the place
attribute_id
uuid
required
Reference to the attribute definition
value_boolean
boolean
Populated if attribute type is boolean
value_string
text
Populated if attribute type is string or enum (max 255 chars)
value_integer
integer
Populated if attribute type is integer
value_decimal
decimal
Populated if attribute type is decimal
Exactly one value_* field must be non-null, matching the attribute definition’s value_type.

Ownership Model

Places follow the “Propriétaire” (owner) model from the specifications:
  1. User Role: User must have the owner role in the user_role table
  2. Submission: Owner creates a place with status pending_review
  3. Moderation: Admin reviews and approves/rejects
  4. Management: Owner can update, archive, and reactivate their places
  5. Restrictions: Delete only allowed if no bookings or reviews exist

Specialized Place Types

Based on place type, additional detail tables provide type-specific fields:

Accommodation Details

From concordia-specs.md (lines 523-542):
{
  place_id: uuid,        // Primary key and foreign key
  stars: integer,        // 1-5 star rating
  accommodation_type: text,
  capacity: integer,
  pets_allowed: boolean,
  pool: boolean,
  spa: boolean,
  family_rooms: boolean,
  booking_url: text,
  availability: jsonb
}

Gastronomy Details

From concordia-specs.md (lines 544-561):
{
  place_id: uuid,
  cuisine: text,
  price_range: enum,
  takeaway: boolean,
  delivery: boolean,
  vegan: boolean,
  brunch: boolean,
  seating_capacity: integer
}

Activity Details

From concordia-specs.md (lines 563-579):
{
  place_id: uuid,
  duration_min: integer,
  min_age: integer,
  max_age: integer,
  price_min: decimal,
  price_max: decimal,
  seasons: text[]  // ["spring", "summer", "autumn", "winter"]
}

Address Structure

From concordia-specs.md (lines 581-599), addresses are normalized:
{
  id: uuid,
  street: text,
  city: text,           // Required
  postcode: text,
  region: text,
  country: text,        // ISO 3166-1 alpha-2
  latitude: decimal(10,7),
  longitude: decimal(10,7)
}

Integration Points

With Reviews

Places can receive reviews that automatically update rating_avg and rating_count fields.

With Services

Places can have associated services via the local_service table’s place_id foreign key.

With Bookings

Places can define availability schedules via service_availability for reservation systems.

With Blog Articles

Articles can reference places via article_place_link for editorial content.

Example JSON

From concordia-specs.md (lines 450-480):
{
  "id": "place-uuid-1",
  "owner_id": "user-uuid-1",
  "category_id": "cat-hotel-uuid",
  "slug": "hotel-du-parc-paris",
  "type": "hotel",
  "address_id": "addr-uuid-1",
  "latitude": 48.8566969,
  "longitude": 2.3514616,
  "email": "contact@hotelduparc.fr",
  "phone": "+33140000000",
  "website": "https://hotelduparc.fr",
  "open_hours": {
    "monday": [{"open": "07:00", "close": "23:00"}],
    "tuesday": [{"open": "07:00", "close": "23:00"}]
  },
  "accessibility": ["wheelchair", "elevator"],
  "audience": ["families", "couples", "business"],
  "price_range": "high",
  "rating_avg": 4.2,
  "rating_count": 42,
  "status": "published",
  "submitted_at": "2026-01-15T09:00:00Z",
  "published_at": "2026-01-16T14:30:00Z",
  "created_at": "2026-01-15T09:00:00Z",
  "updated_at": "2026-02-01T11:00:00Z"
}