import asyncpg import os import logging logger = logging.getLogger(__name__) DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@localhost:5432/daarion") async def run_migrations(): conn = None try: conn = await asyncpg.connect(DATABASE_URL) # Add logo_url and banner_url to microdaos table (previous task) await conn.execute(""" ALTER TABLE microdaos ADD COLUMN IF NOT EXISTS logo_url TEXT, ADD COLUMN IF NOT EXISTS banner_url TEXT; """) # Add logo_url and banner_url to city_rooms table (previous task) await conn.execute(""" ALTER TABLE city_rooms ADD COLUMN IF NOT EXISTS logo_url TEXT, ADD COLUMN IF NOT EXISTS banner_url TEXT; """) # NEW: Add crew_team_key to agents table (TASK 044) await conn.execute(""" ALTER TABLE agents ADD COLUMN IF NOT EXISTS crew_team_key TEXT; """) logger.info("Migration: Added crew_team_key to agents table.") # TASK 044: Add room_role, is_public, sort_order to city_rooms table await conn.execute(""" ALTER TABLE city_rooms ADD COLUMN IF NOT EXISTS room_role TEXT, ADD COLUMN IF NOT EXISTS is_public BOOLEAN DEFAULT TRUE, ADD COLUMN IF NOT EXISTS sort_order INTEGER DEFAULT 100; """) logger.info("Migration: Added room_role, is_public, sort_order to city_rooms table.") # ROOMS_LAYER_RESTORE: Add owner_type, owner_id, space_scope, visibility, room_type, updated_at await conn.execute(""" ALTER TABLE city_rooms ADD COLUMN IF NOT EXISTS room_type TEXT DEFAULT 'chat', ADD COLUMN IF NOT EXISTS owner_type TEXT DEFAULT 'city', ADD COLUMN IF NOT EXISTS owner_id TEXT, ADD COLUMN IF NOT EXISTS space_scope TEXT DEFAULT 'city', ADD COLUMN IF NOT EXISTS visibility TEXT DEFAULT 'public-city', ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ DEFAULT NOW(); """) logger.info("Migration: Added room_type, owner_type, owner_id, space_scope, visibility, updated_at to city_rooms table.") # TASK C2: Create nodes table with owner_microdao (replaces node_cache for ontology) await conn.execute(""" CREATE TABLE IF NOT EXISTS nodes ( id TEXT PRIMARY KEY, display_name TEXT NOT NULL, hostname TEXT, owner_microdao_id TEXT REFERENCES microdaos(id), node_type TEXT, environment TEXT DEFAULT 'unknown', cpu_cores INTEGER, ram_gb INTEGER, gpu_count INTEGER DEFAULT 0, disk_gb INTEGER, status TEXT DEFAULT 'unknown', guardian_agent_id TEXT, steward_agent_id TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); """) logger.info("Migration: Created nodes table with owner_microdao.") # TASK C3: Insert NODE1 and NODE2 if not exist await conn.execute(""" INSERT INTO nodes (id, display_name, hostname, owner_microdao_id, node_type, environment, status, guardian_agent_id, steward_agent_id) VALUES ('node-1-hetzner-gex44', 'Hetzner GEX44 Production', '144.76.224.179', 'dao_daarion', 'compute', 'production', 'online', 'monitor-node1', 'node-steward-node1'), ('node-2-macbook-m4max', 'MacBook Pro M4 Max', '192.168.1.33', 'dao_daarion', 'hybrid', 'development', 'online', 'monitor-node2', 'node-steward-node2') ON CONFLICT (id) DO UPDATE SET display_name = EXCLUDED.display_name, hostname = EXCLUDED.hostname, owner_microdao_id = EXCLUDED.owner_microdao_id, node_type = EXCLUDED.node_type, environment = EXCLUDED.environment, guardian_agent_id = EXCLUDED.guardian_agent_id, steward_agent_id = EXCLUDED.steward_agent_id, updated_at = NOW(); """) logger.info("Migration: Inserted/updated NODE1 and NODE2 in nodes table.") # ========================================================================= # ROOMS LAYER RESTORE (TASK_PHASE_ROOMS_LAYER_RESTORE_AND_MATRIX_INTEGRATION) # ========================================================================= # Seed City Rooms (8 standard rooms) await conn.execute(""" INSERT INTO city_rooms (id, slug, name, description, room_type, owner_type, owner_id, space_scope, visibility, is_public, sort_order, created_at, updated_at) VALUES (gen_random_uuid(), 'general', 'General', 'Main city chat room for all citizens', 'chat', 'city', 'daarion', 'city', 'public-city', true, 1, NOW(), NOW()), (gen_random_uuid(), 'welcome', 'Welcome', 'Welcome new citizens to DAARION City', 'chat', 'city', 'daarion', 'city', 'public-city', true, 2, NOW(), NOW()), (gen_random_uuid(), 'leadership-hall', 'Leadership Hall', 'City governance and leadership discussions', 'chat', 'city', 'daarion', 'city', 'public-city', true, 3, NOW(), NOW()), (gen_random_uuid(), 'builders', 'Builders', 'Builders and developers community', 'chat', 'city', 'daarion', 'city', 'public-city', true, 4, NOW(), NOW()), (gen_random_uuid(), 'science-lab', 'Science Lab', 'Research, AI, and innovation discussions', 'chat', 'city', 'daarion', 'city', 'public-city', true, 5, NOW(), NOW()), (gen_random_uuid(), 'security-bureau', 'Security Bureau', 'Security and safety discussions', 'chat', 'city', 'daarion', 'city', 'public-city', true, 6, NOW(), NOW()), (gen_random_uuid(), 'economics-square', 'Economics Square', 'Economics, tokenomics, and finance', 'chat', 'city', 'daarion', 'city', 'public-city', true, 7, NOW(), NOW()), (gen_random_uuid(), 'announcements', 'Announcements', 'Official city announcements', 'broadcast', 'city', 'daarion', 'city', 'public-city', true, 8, NOW(), NOW()) ON CONFLICT (slug) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, room_type = EXCLUDED.room_type, is_public = EXCLUDED.is_public, sort_order = EXCLUDED.sort_order, updated_at = NOW(); """) logger.info("Migration: Seeded 8 City Rooms.") # Seed MicroDAO Rooms for DAARION root DAO await conn.execute(""" INSERT INTO city_rooms (id, slug, name, description, room_type, owner_type, owner_id, space_scope, visibility, is_public, room_role, sort_order, created_at, updated_at) VALUES (gen_random_uuid(), 'daarion-lobby', 'DAARION Lobby', 'Main lobby for DAARION DAO', 'chat', 'microdao', 'dao_daarion', 'microdao', 'public-city', true, 'primary', 1, NOW(), NOW()), (gen_random_uuid(), 'daarion-governance', 'DAARION Governance', 'Governance and voting discussions', 'chat', 'microdao', 'dao_daarion', 'microdao', 'members', false, 'governance', 2, NOW(), NOW()), (gen_random_uuid(), 'daarion-news', 'DAARION News', 'News and updates from DAARION', 'broadcast', 'microdao', 'dao_daarion', 'microdao', 'public-city', true, 'news', 3, NOW(), NOW()), (gen_random_uuid(), 'daarion-builders', 'DAARION Builders', 'Development and technical discussions', 'chat', 'microdao', 'dao_daarion', 'microdao', 'members', false, 'builders', 4, NOW(), NOW()), (gen_random_uuid(), 'daarion-help', 'DAARION Help', 'Help and support for DAARION members', 'chat', 'microdao', 'dao_daarion', 'microdao', 'public-city', true, 'help', 5, NOW(), NOW()) ON CONFLICT (slug) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, room_role = EXCLUDED.room_role, is_public = EXCLUDED.is_public, sort_order = EXCLUDED.sort_order, updated_at = NOW(); """) logger.info("Migration: Seeded 5 MicroDAO Rooms for DAARION.") # Seed Node Support Rooms await conn.execute(""" INSERT INTO city_rooms (id, slug, name, description, room_type, owner_type, owner_id, space_scope, visibility, is_public, room_role, created_at, updated_at) VALUES (gen_random_uuid(), 'node-support-node1', 'NODE1 Support', 'Support room for Hetzner GEX44 Production node', 'node-support', 'node', 'node-1-hetzner-gex44', 'node', 'members', false, 'support', NOW(), NOW()), (gen_random_uuid(), 'node-support-node2', 'NODE2 Support', 'Support room for MacBook Pro M4 Max node', 'node-support', 'node', 'node-2-macbook-m4max', 'node', 'members', false, 'support', NOW(), NOW()) ON CONFLICT (slug) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, room_role = EXCLUDED.room_role, updated_at = NOW(); """) logger.info("Migration: Seeded 2 Node Support Rooms.") # Update public agents to be visible as citizens await conn.execute(""" UPDATE agents SET is_public = true WHERE gov_level IN ('city_governance', 'district_lead', 'orchestrator', 'core_team') OR kind IN ('civic', 'governance', 'orchestrator'); """) logger.info("Migration: Updated public agents for Citizens Layer.") except Exception as e: logger.error(f"Error running migrations: {e}") raise finally: if conn: await conn.close()