- 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
134 lines
5.0 KiB
PL/PgSQL
134 lines
5.0 KiB
PL/PgSQL
-- ============================================================================
|
|
-- Migration 010: Living Map Tables
|
|
-- Phase 9: Living Map (Full Stack Service)
|
|
-- ============================================================================
|
|
|
|
-- ============================================================================
|
|
-- Table: living_map_history
|
|
-- Purpose: Event log for all Living Map events
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS living_map_history (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
event_type TEXT NOT NULL,
|
|
payload JSONB NOT NULL,
|
|
source_service TEXT,
|
|
entity_id TEXT,
|
|
entity_type TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- Indexes for efficient querying
|
|
CREATE INDEX IF NOT EXISTS idx_living_map_history_timestamp
|
|
ON living_map_history (timestamp DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_living_map_history_event_type
|
|
ON living_map_history (event_type);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_living_map_history_entity_id
|
|
ON living_map_history (entity_id);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_living_map_history_entity_type
|
|
ON living_map_history (entity_type);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_living_map_history_source_service
|
|
ON living_map_history (source_service);
|
|
|
|
-- Composite index for common queries
|
|
CREATE INDEX IF NOT EXISTS idx_living_map_history_type_timestamp
|
|
ON living_map_history (event_type, timestamp DESC);
|
|
|
|
COMMENT ON TABLE living_map_history IS 'Event log for Living Map - tracks all network state changes';
|
|
COMMENT ON COLUMN living_map_history.event_type IS 'Type of event (e.g., node.metrics.update, agent.status.change)';
|
|
COMMENT ON COLUMN living_map_history.payload IS 'Full event data in JSON format';
|
|
COMMENT ON COLUMN living_map_history.source_service IS 'Service that generated the event';
|
|
COMMENT ON COLUMN living_map_history.entity_id IS 'ID of the entity (for filtering)';
|
|
COMMENT ON COLUMN living_map_history.entity_type IS 'Type: city|space|node|agent|dao|microdao';
|
|
|
|
-- ============================================================================
|
|
-- Table: living_map_snapshots (optional, for caching)
|
|
-- Purpose: Store periodic full snapshots for fast recovery
|
|
-- ============================================================================
|
|
|
|
CREATE TABLE IF NOT EXISTS living_map_snapshots (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
generated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
snapshot_data JSONB NOT NULL,
|
|
version TEXT NOT NULL DEFAULT '1.0',
|
|
compressed BOOLEAN DEFAULT FALSE,
|
|
size_bytes INTEGER,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_living_map_snapshots_generated_at
|
|
ON living_map_snapshots (generated_at DESC);
|
|
|
|
COMMENT ON TABLE living_map_snapshots IS 'Periodic full state snapshots for fast recovery';
|
|
COMMENT ON COLUMN living_map_snapshots.snapshot_data IS 'Complete Living Map state in JSON';
|
|
|
|
-- ============================================================================
|
|
-- Function: Clean old history (retention policy)
|
|
-- ============================================================================
|
|
|
|
CREATE OR REPLACE FUNCTION cleanup_living_map_history()
|
|
RETURNS INTEGER AS $$
|
|
DECLARE
|
|
deleted_count INTEGER;
|
|
BEGIN
|
|
-- Delete events older than 30 days
|
|
DELETE FROM living_map_history
|
|
WHERE timestamp < NOW() - INTERVAL '30 days';
|
|
|
|
GET DIAGNOSTICS deleted_count = ROW_COUNT;
|
|
|
|
-- Delete old snapshots (keep last 100)
|
|
DELETE FROM living_map_snapshots
|
|
WHERE id NOT IN (
|
|
SELECT id FROM living_map_snapshots
|
|
ORDER BY generated_at DESC
|
|
LIMIT 100
|
|
);
|
|
|
|
RETURN deleted_count;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON FUNCTION cleanup_living_map_history IS 'Cleanup old history and snapshots';
|
|
|
|
-- ============================================================================
|
|
-- Grants
|
|
-- ============================================================================
|
|
|
|
GRANT SELECT, INSERT, DELETE ON living_map_history TO postgres;
|
|
GRANT SELECT, INSERT, DELETE ON living_map_snapshots TO postgres;
|
|
|
|
-- ============================================================================
|
|
-- Seed Data: Initial event
|
|
-- ============================================================================
|
|
|
|
INSERT INTO living_map_history (event_type, payload, source_service, entity_type)
|
|
VALUES (
|
|
'living_map.initialized',
|
|
'{"message": "Living Map service initialized", "version": "1.0"}'::jsonb,
|
|
'living-map-service',
|
|
'system'
|
|
) ON CONFLICT DO NOTHING;
|
|
|
|
-- ============================================================================
|
|
-- Migration Complete
|
|
-- ============================================================================
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF EXISTS (
|
|
SELECT 1 FROM information_schema.tables
|
|
WHERE table_name = 'living_map_history'
|
|
) THEN
|
|
RAISE NOTICE 'Migration 010: Living Map Tables created successfully';
|
|
ELSE
|
|
RAISE EXCEPTION 'Migration 010: Failed to create tables';
|
|
END IF;
|
|
END $$;
|
|
|