Skip to content

MATRIX ROOMS BRIDGE — DAARION.city

Version: 1.0.0

0. PURPOSE

Звʼязати City Rooms у DAARION з Matrix-кімнатами так, щоб:

  • кожна city_room мала свій matrix_room_id / matrix_room_alias,
  • UI для /city/[slug] працював поверх справжньої Matrix-кімнати,
  • подальший presence/typing/реальний чат використовували Matrix як єдине джерело істини.

Це база для:

  • живих чатів у City,
  • спільної присутності,
  • інтеграції агентів як Matrix-botʼів.

1. ARCHITECTURE OVERVIEW

Сервіси

  • city-service (7001)
  • зберігає список кімнат (rooms)
  • розширюється полями для Matrix

  • matrix-gateway (новий сервіс, 7025)

  • проксі до Synapse REST API
  • хендлить auth до Matrix від імені DAARION

  • auth-service (7020)

  • вже створює Matrix акаунти для юзерів (auto-provisioning)

  • synapse (8018)

  • Matrix homeserver

Мапінг

Кожна City Room має:

Поле Опис Приклад
room_id внутрішній DAARION id room_city_general
slug URL/імена кімнати general
matrix_room_id Matrix ID !abc123xyz:daarion.space
matrix_room_alias Matrix alias #city_general:daarion.space

2. DATA MODEL CHANGES (PostgreSQL)

2.1. Таблиця city_rooms

Додати поля:

ALTER TABLE city_rooms
  ADD COLUMN IF NOT EXISTS matrix_room_id TEXT,
  ADD COLUMN IF NOT EXISTS matrix_room_alias TEXT;

CREATE UNIQUE INDEX IF NOT EXISTS city_rooms_matrix_room_id_uq
  ON city_rooms (matrix_room_id)
  WHERE matrix_room_id IS NOT NULL;

CREATE UNIQUE INDEX IF NOT EXISTS city_rooms_matrix_room_alias_uq
  ON city_rooms (matrix_room_alias)
  WHERE matrix_room_alias IS NOT NULL;

2.2. Invariants

  • matrix_room_id → або NULL, або валідний Matrix room id (!....:domain)
  • matrix_room_alias → або NULL, або вигляду #city_<slug>:daarion.space
  • Один Matrix room = одна City room

3. NAMING CONVENTION

Для Matrix-кімнат:

  • room alias:
  • формат: #city_<slug>:daarion.space
  • приклад: #city_general:daarion.space

  • room name:

  • "DAARION City — <Room Name>"
  • приклад: "DAARION City — General"

Ці назви видно в Matrix-клієнтах (Element Web).


4. FLOWS

4.1. Створення нової City Room

Коли в city-service створюється новий room:

  1. Генерується slug (як є зараз).

  2. Викликається Matrix Gateway: POST /internal/matrix/rooms/create: json { "slug": "energy", "name": "Energy", "visibility": "public" }

  3. Matrix Gateway:

  4. викликає Synapse API POST /_matrix/client/v3/createRoom
  5. задає:
    • name: "DAARION City — Energy"
    • room_alias_name: "city_energy"
    • preset: "public_chat"
  6. повертає: json { "matrix_room_id": "!abc123:daarion.space", "matrix_room_alias": "#city_energy:daarion.space" }

  7. city-service зберігає ці значення в city_rooms.

Якщо Matrix недоступний: * MVP: fail створення кімнати цілком, щоб не було "неповних" кімнат. * TODO: retry-механізм для production.


4.2. Синхронізація існуючих кімнат (backfill)

Для вже створених city_rooms:

  1. Endpoint: POST /internal/city/matrix/backfill:
  2. бере всі кімнати, де matrix_room_id IS NULL.
  3. для кожної:
    • пробує знайти Matrix room по alias #city_<slug>:daarion.space через Matrix Gateway:
    • якщо знайдено → зберігає matrix_room_id / matrix_room_alias;
    • якщо не знайдено → створює нову Matrix room, як у п. 4.1.

4.3. Архівація / деактивація Room

Коли Room в DAARION позначається як "archived" / "inactive":

MVP: * не видаляти Matrix room, * показувати статус в DAARION UI як archived.

Future: * змінити power levels, * закрити можливість писати, * додати m.room.tombstone.


5. MATRIX GATEWAY SERVICE

5.1. Конфігурація

MATRIX_GATEWAY_PORT=7025
SYNAPSE_URL=http://daarion-synapse:8008
SYNAPSE_ADMIN_TOKEN=<admin_access_token>
MATRIX_SERVER_NAME=daarion.space

5.2. API Endpoints

POST /internal/matrix/rooms/create

Викликається тільки з city-service.

Request:

{
  "slug": "energy",
  "name": "Energy",
  "visibility": "public"
}

Response (200):

{
  "matrix_room_id": "!abc123:daarion.space",
  "matrix_room_alias": "#city_energy:daarion.space"
}

Response (500):

{
  "error": "matrix_unavailable",
  "detail": "Failed to create Matrix room"
}

GET /internal/matrix/rooms/find-by-alias

Request: GET /internal/matrix/rooms/find-by-alias?alias=%23city_energy%3Adaarion.space

Response (200, exists):

{
  "matrix_room_id": "!abc123:daarion.space",
  "matrix_room_alias": "#city_energy:daarion.space"
}

Response (404, not found):

{
  "error": "not_found"
}

GET /healthz

{
  "status": "ok",
  "synapse": "connected"
}

6. CITY-SERVICE API CHANGES

6.1. GET /api/city/rooms

Додати у відповідь:

[
  {
    "id": "room_city_general",
    "slug": "general",
    "name": "General",
    "description": "Головна кімната міста",
    "is_default": true,
    "members_online": 42,
    "last_event": "2025-11-26T20:00:00Z",
    "matrix_room_id": "!abc123:daarion.space",
    "matrix_room_alias": "#city_general:daarion.space"
  }
]

6.2. GET /api/city/rooms/{slug}

Також включити matrix_room_id / matrix_room_alias.

6.3. POST /api/city/rooms

При створенні кімнати автоматично створювати Matrix room.


7. FRONTEND INTEGRATION

На сторінці /city/[slug]:

  • при завантаженні room:
  • отримати matrix_room_id / matrix_room_alias,
  • передати їх у чат-Layout.

Чат-шар (ChatRoom) повинен: * використовувати Matrix-клієнт для: * приєднання до кімнати, * отримання історії, * відправки повідомлень.


8. SECURITY

  • matrix-gateway endpoint'и /internal/matrix/*:
  • тільки internal auth (service-to-service)
  • перевірка internal token або Docker network

  • Кінцеві користувачі не повинні напряму бачити Matrix admin-credentials.


9. DEPLOYMENT

Docker Compose addition

matrix-gateway:
  build: ./services/matrix-gateway
  container_name: daarion-matrix-gateway
  restart: unless-stopped
  environment:
    - MATRIX_GATEWAY_PORT=7025
    - SYNAPSE_URL=http://daarion-synapse:8008
    - SYNAPSE_ADMIN_TOKEN=${SYNAPSE_ADMIN_TOKEN}
    - MATRIX_SERVER_NAME=daarion.space
  ports:
    - "7025:7025"
  networks:
    - dagi-network
  depends_on:
    - synapse

Nginx routing

location /internal/matrix/ {
    # Internal only - block external access
    allow 127.0.0.1;
    deny all;

    proxy_pass http://127.0.0.1:7025/internal/matrix/;
}

10. ROADMAP AFTER BRIDGE

Після реалізації цього SPEC:

  1. Presence & Typing:
  2. читати m.presence, m.typing, m.receipt з Matrix,
  3. транслювати в фронт (через WebSocket).

  4. Agents як Matrix Bot:

  5. окремі Matrix accounts для агентів,
  6. відповіді агентів у тій же кімнаті, що й користувачі.

  7. City Map:

  8. візуалізація активності кімнат на 2D/2.5D мапі.

  9. PWA/Mobile:

  10. manifest.json,
  11. service worker,
  12. offline кеш.

11. ACCEPTANCE CRITERIA

  • [ ] city_rooms має поля matrix_room_id / matrix_room_alias
  • [ ] При створенні City Room автоматично створюється Matrix room
  • [ ] Backfill endpoint синхронізує існуючі кімнати
  • [ ] API /api/city/rooms повертає matrix поля
  • [ ] Matrix Gateway працює і відповідає на healthcheck
  • [ ] Element Web показує створені кімнати