Files
microdao-daarion/migrations/010_create_city_backend.sql
Apple 3de3c8cb36 feat: Add presence heartbeat for Matrix online status
- matrix-gateway: POST /internal/matrix/presence/online endpoint
- usePresenceHeartbeat hook with activity tracking
- Auto away after 5 min inactivity
- Offline on page close/visibility change
- Integrated in MatrixChatRoom component
2025-11-27 00:19:40 -08:00

152 lines
7.4 KiB
SQL

-- Migration 010: City Backend (Rooms, Feed, Second Me)
-- DAARION City MVP Backend Completion
-- =============================================================================
-- City Rooms (Public Rooms)
-- =============================================================================
CREATE TABLE IF NOT EXISTS city_rooms (
id TEXT PRIMARY KEY, -- room_city_general, room_city_science, etc.
slug TEXT NOT NULL UNIQUE, -- general, science, builders
name TEXT NOT NULL, -- General, Science, Builders
description TEXT,
is_default BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by TEXT -- user_id (u_*) or NULL for system
);
CREATE INDEX IF NOT EXISTS ix_city_rooms_slug ON city_rooms(slug);
CREATE INDEX IF NOT EXISTS ix_city_rooms_created_at ON city_rooms(created_at DESC);
COMMENT ON TABLE city_rooms IS 'Публічні кімнати DAARION City';
-- =============================================================================
-- City Room Messages
-- =============================================================================
CREATE TABLE IF NOT EXISTS city_room_messages (
id TEXT PRIMARY KEY, -- m_city_ulid
room_id TEXT NOT NULL REFERENCES city_rooms(id) ON DELETE CASCADE,
author_user_id TEXT, -- u_* (user who sent)
author_agent_id TEXT, -- ag_* (agent who sent)
body TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT check_author CHECK (
(author_user_id IS NOT NULL AND author_agent_id IS NULL) OR
(author_user_id IS NULL AND author_agent_id IS NOT NULL)
)
);
CREATE INDEX IF NOT EXISTS ix_city_room_messages_room_time
ON city_room_messages(room_id, created_at DESC);
CREATE INDEX IF NOT EXISTS ix_city_room_messages_author_user
ON city_room_messages(author_user_id);
CREATE INDEX IF NOT EXISTS ix_city_room_messages_author_agent
ON city_room_messages(author_agent_id);
COMMENT ON TABLE city_room_messages IS 'Повідомлення в публічних кімнатах City';
-- =============================================================================
-- City Feed Events
-- =============================================================================
CREATE TABLE IF NOT EXISTS city_feed_events (
id TEXT PRIMARY KEY, -- evt_city_ulid
kind TEXT NOT NULL, -- 'room_message', 'agent_reply', 'system', 'dao_event'
room_id TEXT REFERENCES city_rooms(id) ON DELETE SET NULL,
user_id TEXT, -- u_*
agent_id TEXT, -- ag_*
payload JSONB NOT NULL, -- flexible event data
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_city_feed_time ON city_feed_events(created_at DESC);
CREATE INDEX IF NOT EXISTS ix_city_feed_kind ON city_feed_events(kind);
CREATE INDEX IF NOT EXISTS ix_city_feed_room ON city_feed_events(room_id) WHERE room_id IS NOT NULL;
COMMENT ON TABLE city_feed_events IS 'City Feed — агрегатор всіх подій міста';
-- =============================================================================
-- Second Me Sessions (персональний агент)
-- =============================================================================
CREATE TABLE IF NOT EXISTS secondme_sessions (
id TEXT PRIMARY KEY, -- smsess_ulid
user_id TEXT NOT NULL, -- u_*
agent_id TEXT, -- ag_secondme_*
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_interaction_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS ix_secondme_sessions_user ON secondme_sessions(user_id);
CREATE INDEX IF NOT EXISTS ix_secondme_sessions_last_interaction
ON secondme_sessions(user_id, last_interaction_at DESC NULLS LAST);
COMMENT ON TABLE secondme_sessions IS 'Сесії взаємодії користувачів з Second Me';
-- =============================================================================
-- Second Me Messages
-- =============================================================================
CREATE TABLE IF NOT EXISTS secondme_messages (
id TEXT PRIMARY KEY, -- smmsg_ulid
session_id TEXT NOT NULL REFERENCES secondme_sessions(id) ON DELETE CASCADE,
user_id TEXT NOT NULL, -- u_*
role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
content TEXT NOT NULL,
tokens_used INT, -- для assistant messages
latency_ms INT, -- для assistant messages
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS ix_secondme_messages_session_time
ON secondme_messages(session_id, created_at DESC);
CREATE INDEX IF NOT EXISTS ix_secondme_messages_user
ON secondme_messages(user_id);
COMMENT ON TABLE secondme_messages IS 'Історія розмов з Second Me';
-- =============================================================================
-- Insert Default City Rooms
-- =============================================================================
INSERT INTO city_rooms (id, slug, name, description, is_default) VALUES
('room_city_general', 'general', 'General', 'Головна кімната DAARION City — тут зустрічається вся спільнота', TRUE),
('room_city_welcome', 'welcome', 'Welcome', 'Вітаємо нових учасників! Почніть свою подорож тут', TRUE),
('room_city_builders', 'builders', 'Builders', 'Кімната для будівників та розробників DAARION', TRUE),
('room_city_science', 'science', 'Science', 'Наукова спільнота — обговорення досліджень та експериментів', FALSE),
('room_city_energy', 'energy', 'Energy Union', 'Енергетична спільнота — decarbonization, renewables', FALSE)
ON CONFLICT (id) DO NOTHING;
-- =============================================================================
-- Seed: Welcome Message
-- =============================================================================
INSERT INTO city_room_messages (id, room_id, author_agent_id, body, created_at) VALUES
('m_city_welcome_001', 'room_city_welcome', 'ag_system',
'Вітаємо в DAARION City! Це публічний простір для спілкування, співпраці та інновацій. Приєднуйтесь до обговорень! 🚀',
NOW())
ON CONFLICT (id) DO NOTHING;
INSERT INTO city_room_messages (id, room_id, author_agent_id, body, created_at) VALUES
('m_city_general_001', 'room_city_general', 'ag_system',
'Головна кімната міста активна! Тут ви можете обговорювати будь-які теми, пов''язані з DAARION. 🌆',
NOW())
ON CONFLICT (id) DO NOTHING;
-- =============================================================================
-- Feed Event for Welcome
-- =============================================================================
INSERT INTO city_feed_events (id, kind, room_id, agent_id, payload, created_at) VALUES
('evt_city_welcome_001', 'system', 'room_city_welcome', 'ag_system',
'{"message": "Система ініціалізована", "type": "bootstrap"}',
NOW())
ON CONFLICT (id) DO NOTHING;
-- =============================================================================
-- END OF MIGRATION 010
-- =============================================================================