Files
microdao-daarion/services/messaging-service
Apple 744c149300
Some checks failed
Build and Deploy Docs / build-and-deploy (push) Has been cancelled
Add automated session logging system
- Created logs/ structure (sessions, operations, incidents)
- Added session-start/log/end scripts
- Installed Git hooks for auto-logging commits/pushes
- Added shell integration for zsh
- Created CHANGELOG.md
- Documented today's session (2026-01-10)
2026-01-10 04:53:17 -08:00
..
2026-01-10 04:53:17 -08:00
2026-01-10 04:53:17 -08:00

DAARION Messaging Service

Matrix-aware messaging service for DAARION

Overview

The messaging-service provides a DAARION-specific API layer over Matrix protocol:

  • Manages channels (mapped to Matrix rooms)
  • Indexes messages (full content stored in Matrix)
  • Handles real-time WebSocket connections
  • Integrates agents into conversations
  • Bridges Matrix ↔ DAARION entity model

Architecture

Frontend (React)
    ↓
messaging-service (FastAPI)
    ↓
matrix-gateway (internal)
    ↓
Matrix Homeserver (Synapse)

Features

Channel management (create, list, update)
Message sending/receiving
Real-time WebSocket subscriptions
Agent posting to channels
Member invitations (users + agents)
Threading/replies support
Reactions (via Matrix)
Message editing/deletion (via Matrix redaction)

Setup

1. Prerequisites

  • Python 3.11+
  • PostgreSQL (with messenger schema migrated)
  • matrix-gateway service running
  • Matrix homeserver (Synapse/Dendrite)

2. Install dependencies

pip install -r requirements.txt

3. Environment variables

export DATABASE_URL="postgresql://user:pass@localhost:5432/daarion"
export MATRIX_GATEWAY_URL="http://matrix-gateway:7003"
export MATRIX_GATEWAY_SECRET="your-shared-secret"
export NATS_URL="nats://localhost:4222"

4. Run migrations

psql -d daarion -f ../../migrations/001_create_messenger_schema.sql

5. Start service

uvicorn main:app --host 0.0.0.0 --port 7004 --reload

Service will be available at http://localhost:7004

API Documentation

Interactive API docs: http://localhost:7004/docs

Key endpoints

Channels

  • GET /api/messaging/channels — List channels
  • POST /api/messaging/channels — Create channel (creates Matrix room)
  • GET /api/messaging/channels/{id} — Get channel details

Messages

  • GET /api/messaging/channels/{id}/messages — List messages (paginated)
  • POST /api/messaging/channels/{id}/messages — Send message

Members

  • GET /api/messaging/channels/{id}/members — List members
  • POST /api/messaging/channels/{id}/members — Invite member

WebSocket

  • WS /ws/messaging/{channel_id} — Real-time message stream

Internal (agent integration)

  • POST /internal/agents/{agent_id}/post-to-channel — Agent posting

Matrix Integration

Channel → Room mapping

Every DAARION channel is backed by a Matrix room:

DAARION Matrix
channels.id Unique UUID
channels.matrix_room_id !roomid:daarion.city
channels.slug Room alias (#slug:daarion.city)
channels.visibility Room visibility (public/private)

Message → Event mapping

DAARION messages are indexed references to Matrix events:

DAARION Matrix
messages.id Unique UUID
messages.matrix_event_id $eventid:daarion.city
messages.content_preview Truncated text (full in Matrix)
messages.sender_id DAARION entity ID (user:..., agent:...)
messages.sender_matrix_id Matrix user ID (@user:server)

Why index messages?

We don't duplicate Matrix events in full, only index them for:

  • Fast listing and pagination
  • MicroDAO context filtering
  • Agent memory integration
  • Task/project linking
  • Analytics and metrics

Full message content is always fetched from Matrix when needed.

Database Schema

See ../../migrations/001_create_messenger_schema.sql

Key tables:

  • channels — Channel metadata + Matrix room mapping
  • messages — Message index (not full content)
  • channel_members — Membership + permissions
  • message_reactions — Reactions index
  • channel_events — Audit log

NATS Events

Published by messaging-service:

messaging.message.created

{
  "channel_id": "uuid",
  "matrix_event_id": "$event:server",
  "sender_id": "user:alice",
  "sender_type": "human",
  "preview": "Hello world",
  "created_at": "2025-11-24T10:30:00Z"
}

messaging.channel.created

{
  "channel_id": "uuid",
  "microdao_id": "microdao:7",
  "matrix_room_id": "!room:server",
  "created_by": "user:alice"
}

messaging.member.invited

{
  "channel_id": "uuid",
  "member_id": "agent:sofia",
  "invited_by": "user:admin",
  "role": "agent"
}

Agent Integration

Agents can post to channels via internal API:

POST /internal/agents/agent:sofia/post-to-channel
{
  "channel_id": "uuid",
  "text": "Hello from Sofia!"
}

Requirements:

  • Agent must be a member of the channel
  • Agent posts are sent as m.notice messages in Matrix
  • Agent messages are indexed with sender_type="agent"

WebSocket Protocol

Connect to /ws/messaging/{channel_id}:

Client → Server:

"ping"

Server → Client:

"pong"

Server → Client (new message):

{
  "type": "message.created",
  "message": {
    "id": "uuid",
    "channel_id": "uuid",
    "sender_id": "user:alice",
    "content_preview": "Hello!",
    "created_at": "2025-11-24T10:30:00Z"
  }
}

Element Compatibility

All channels created via messaging-service are visible in Element:

  • Same Matrix homeserver
  • Standard Matrix room types
  • Federation enabled (optional)
  • E2EE support (optional, per channel)

Users can use Element, DAARION UI, or any Matrix client interchangeably.

Security

  • Authentication: X-User-Id header (TODO: replace with JWT)
  • Authorization: Channel membership + permissions checked
  • Matrix gateway: Internal service, not exposed to public
  • Confidential mode: E2EE channels, content not indexed

Testing

Manual testing with httpx

import httpx

# Create channel
resp = httpx.post(
    "http://localhost:7004/api/messaging/channels",
    headers={"X-User-Id": "user:admin"},
    json={
        "slug": "test",
        "name": "Test Channel",
        "microdao_id": "microdao:daarion",
        "visibility": "public"
    }
)
channel = resp.json()

# Send message
resp = httpx.post(
    f"http://localhost:7004/api/messaging/channels/{channel['id']}/messages",
    headers={"X-User-Id": "user:alice"},
    json={
        "text": "Hello from Alice!"
    }
)
message = resp.json()

Testing with Element

  1. Login to Element with Matrix user
  2. Join room by alias: #test-daarion:daarion.city
  3. Send message in Element
  4. Check it appears in DAARION UI (via /api/messaging/channels/.../messages)

Deployment

Docker

docker build -t daarion/messaging-service .
docker run -p 7004:7004 \
  -e DATABASE_URL="postgresql://..." \
  -e MATRIX_GATEWAY_URL="http://matrix-gateway:7003" \
  daarion/messaging-service

Docker Compose

See ../../docker-compose.yml for full stack deployment.

Production checklist

  • Enable JWT authentication (replace X-User-Id header)
  • Add rate limiting (per user, per channel)
  • Enable NATS event publishing
  • Configure Matrix webhook subscriptions
  • Set up monitoring (Prometheus metrics)
  • Configure logging (structured JSON)
  • Enable HTTPS/TLS for WebSocket
  • Set DATABASE_URL from secrets
  • Set MATRIX_GATEWAY_SECRET from secrets

Roadmap

v1.1

  • NATS JetStream integration
  • Matrix webhook subscription (push model)
  • Message search (full-text via PostgreSQL)
  • Typing indicators
  • Read receipts

v1.2

  • Voice messages
  • File uploads (via Matrix media API)
  • Link previews
  • Message pinning

v2.0

  • End-to-end encryption (E2EE) support
  • Voice/video calls (via Matrix VoIP)
  • Spaces support (channel groups)

Troubleshooting

"Failed to create Matrix room"

Check matrix-gateway is running:

curl http://localhost:7003/health

"Database connection failed"

Check PostgreSQL is running and migrations applied:

psql -d daarion -c "SELECT COUNT(*) FROM channels;"

WebSocket disconnects immediately

Check CORS settings and WebSocket upgrade headers.

License

MIT

Maintainer

DAARION Platform Team