-- ============================================================ -- QZ TOKEN SYSTEM — quiXzoom Token & Payment Schema -- ============================================================ -- Komplett schema inklusive zoomers, missions, observations -- ============================================================ -- ZOOMERS -- ============================================================ CREATE TABLE zoomers ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, email VARCHAR(255) UNIQUE, phone VARCHAR(50), status VARCHAR(50) DEFAULT 'active', capabilities JSONB DEFAULT '[]', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- ============================================================ -- AREAS -- ============================================================ CREATE TABLE areas ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, country VARCHAR(100), city VARCHAR(100), priority FLOAT DEFAULT 0.5, status VARCHAR(50) DEFAULT 'active', metadata JSONB DEFAULT '{}', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- ============================================================ -- OBSERVATIONS -- ============================================================ CREATE TABLE observations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), observation_id VARCHAR(255) UNIQUE NOT NULL, source_type VARCHAR(50) NOT NULL, source_id VARCHAR(255), zoomer_id UUID REFERENCES zoomers(id), media_type VARCHAR(50), media_url TEXT, status VARCHAR(50) DEFAULT 'pending', validated_by VARCHAR(255), validated_at TIMESTAMP WITH TIME ZONE, ai_analysis JSONB DEFAULT '{}', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- ============================================================ -- OBJECTS -- ============================================================ CREATE TABLE objects ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), object_id VARCHAR(255) UNIQUE NOT NULL, type VARCHAR(100) NOT NULL, subtype VARCHAR(100), status VARCHAR(50) DEFAULT 'active', verification_status VARCHAR(50) DEFAULT 'unverified', confidence FLOAT DEFAULT 0, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- ============================================================ -- MISSIONS -- ============================================================ CREATE TABLE missions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), mission_id VARCHAR(255) UNIQUE NOT NULL, type VARCHAR(50) NOT NULL, area_id UUID REFERENCES areas(id), assigned_to UUID REFERENCES zoomers(id), assigned_at TIMESTAMP WITH TIME ZONE, status VARCHAR(50) DEFAULT 'pending', result JSONB DEFAULT '{}', completed_at TIMESTAMP WITH TIME ZONE, priority FLOAT DEFAULT 0.5, instructions JSONB DEFAULT '[]', metadata JSONB DEFAULT '{}', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- ============================================================ -- ZOOMER WALLETS -- ============================================================ CREATE TABLE zoomer_wallets ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), zoomer_id UUID NOT NULL REFERENCES zoomers(id) ON DELETE CASCADE, balance_qz_token DECIMAL(18, 8) DEFAULT 0.0, balance_pending_qz_token DECIMAL(18, 8) DEFAULT 0.0, stripe_connect_account_id VARCHAR(255), stripe_connect_status VARCHAR(50) DEFAULT 'pending', payout_schedule VARCHAR(50) DEFAULT 'weekly_monday', payout_minimum_qz_token DECIMAL(18, 8) DEFAULT 10.0, status VARCHAR(50) DEFAULT 'active', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(zoomer_id) ); CREATE INDEX idx_zoomer_wallets_zoomer ON zoomer_wallets(zoomer_id); CREATE INDEX idx_zoomer_wallets_stripe ON zoomer_wallets(stripe_connect_account_id); -- ============================================================ -- TOKEN TRANSACTIONS (Immutable Ledger) -- ============================================================ CREATE TABLE token_transactions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tx_hash VARCHAR(255) UNIQUE NOT NULL, tx_type VARCHAR(50) NOT NULL, from_wallet_id UUID REFERENCES zoomer_wallets(id), to_wallet_id UUID REFERENCES zoomer_wallets(id), amount_qz_token DECIMAL(18, 8) NOT NULL, amount_usd DECIMAL(18, 8) NOT NULL, exchange_rate DECIMAL(18, 8) NOT NULL, mission_id UUID REFERENCES missions(id), observation_id UUID REFERENCES observations(id), stripe_payment_intent_id VARCHAR(255), stripe_payout_id VARCHAR(255), description TEXT, metadata JSONB DEFAULT '{}', signature VARCHAR(512), signed_by VARCHAR(255), status VARCHAR(50) DEFAULT 'confirmed', confirmed_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), CONSTRAINT no_negative_amount CHECK (amount_qz_token >= 0) ); CREATE INDEX idx_token_tx_hash ON token_transactions(tx_hash); CREATE INDEX idx_token_tx_from ON token_transactions(from_wallet_id); CREATE INDEX idx_token_tx_to ON token_transactions(to_wallet_id); CREATE INDEX idx_token_tx_type ON token_transactions(tx_type); CREATE INDEX idx_token_tx_mission ON token_transactions(mission_id); CREATE INDEX idx_token_tx_created ON token_transactions(created_at); -- ============================================================ -- MISSION PRICING -- ============================================================ CREATE TABLE mission_pricing ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), mission_type VARCHAR(50) NOT NULL, base_price_qz_token DECIMAL(18, 8) NOT NULL, base_price_usd DECIMAL(18, 8) NOT NULL, complexity_multiplier DECIMAL(5, 2) DEFAULT 1.0, distance_bonus_qz_token DECIMAL(18, 8) DEFAULT 0.0, time_bonus_qz_token DECIMAL(18, 8) DEFAULT 0.0, quality_bonus_qz_token DECIMAL(18, 8) DEFAULT 0.0, min_price_qz_token DECIMAL(18, 8) DEFAULT 0.5, max_price_qz_token DECIMAL(18, 8) DEFAULT 100.0, country_code VARCHAR(10), city VARCHAR(100), status VARCHAR(50) DEFAULT 'active', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(mission_type, country_code, city) ); CREATE INDEX idx_mission_pricing_type ON mission_pricing(mission_type); CREATE INDEX idx_mission_pricing_geo ON mission_pricing(country_code, city); -- ============================================================ -- PAYOUT SCHEDULES -- ============================================================ CREATE TABLE payout_schedules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), zoomer_id UUID NOT NULL REFERENCES zoomers(id), wallet_id UUID NOT NULL REFERENCES zoomer_wallets(id), day_of_week INTEGER NOT NULL DEFAULT 1, time_of_day TIME NOT NULL DEFAULT '09:00:00', timezone VARCHAR(50) DEFAULT 'UTC', minimum_qz_token DECIMAL(18, 8) DEFAULT 10.0, status VARCHAR(50) DEFAULT 'active', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(zoomer_id) ); CREATE INDEX idx_payout_schedules_zoomer ON payout_schedules(zoomer_id); CREATE INDEX idx_payout_schedules_day ON payout_schedules(day_of_week); -- ============================================================ -- PAYOUT EXECUTIONS -- ============================================================ CREATE TABLE payout_executions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), zoomer_id UUID NOT NULL REFERENCES zoomers(id), wallet_id UUID NOT NULL REFERENCES zoomer_wallets(id), amount_qz_token DECIMAL(18, 8) NOT NULL, amount_usd DECIMAL(18, 8) NOT NULL, exchange_rate DECIMAL(18, 8) NOT NULL, stripe_payout_id VARCHAR(255), stripe_transfer_id VARCHAR(255), status VARCHAR(50) DEFAULT 'pending', error_message TEXT, retry_count INTEGER DEFAULT 0, processed_at TIMESTAMP WITH TIME ZONE, completed_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), CONSTRAINT no_negative_payout CHECK (amount_qz_token > 0) ); CREATE INDEX idx_payout_exec_zoomer ON payout_executions(zoomer_id); CREATE INDEX idx_payout_exec_status ON payout_executions(status); CREATE INDEX idx_payout_exec_stripe ON payout_executions(stripe_payout_id); -- ============================================================ -- CUSTOMER TOP-UPS -- ============================================================ CREATE TABLE customer_topups ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), customer_id VARCHAR(255) NOT NULL, amount_qz_token DECIMAL(18, 8) NOT NULL, amount_usd DECIMAL(18, 8) NOT NULL, exchange_rate DECIMAL(18, 8) NOT NULL, stripe_payment_intent_id VARCHAR(255), stripe_charge_id VARCHAR(255), status VARCHAR(50) DEFAULT 'pending', metadata JSONB DEFAULT '{}', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), completed_at TIMESTAMP WITH TIME ZONE ); CREATE INDEX idx_customer_topups_customer ON customer_topups(customer_id); CREATE INDEX idx_customer_topups_stripe ON customer_topups(stripe_payment_intent_id); -- ============================================================ -- VIEWS -- ============================================================ CREATE VIEW zoomer_balance AS SELECT z.id as zoomer_id, z.name as zoomer_name, zw.id as wallet_id, zw.balance_qz_token, zw.balance_pending_qz_token, zw.balance_qz_token + zw.balance_pending_qz_token as total_balance, zw.stripe_connect_status, zw.payout_schedule FROM zoomers z JOIN zoomer_wallets zw ON zw.zoomer_id = z.id; CREATE VIEW token_flow_summary AS SELECT DATE_TRUNC('day', created_at) as date, tx_type, COUNT(*) as transaction_count, SUM(amount_qz_token) as total_qz_token, SUM(amount_usd) as total_usd FROM token_transactions WHERE status = 'confirmed' GROUP BY DATE_TRUNC('day', created_at), tx_type ORDER BY date DESC, tx_type; -- ============================================================ -- TRIGGERS -- ============================================================ CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ language 'plpgsql'; CREATE TRIGGER update_zoomers_updated_at BEFORE UPDATE ON zoomers FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_areas_updated_at BEFORE UPDATE ON areas FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_objects_updated_at BEFORE UPDATE ON objects FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_missions_updated_at BEFORE UPDATE ON missions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_zoomer_wallets_updated_at BEFORE UPDATE ON zoomer_wallets FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_mission_pricing_updated_at BEFORE UPDATE ON mission_pricing FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_payout_schedules_updated_at BEFORE UPDATE ON payout_schedules FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================================ -- LEDGER INTEGRITY -- ============================================================ CREATE OR REPLACE FUNCTION prevent_tx_update() RETURNS TRIGGER AS $$ BEGIN IF OLD.status = 'confirmed' THEN RAISE EXCEPTION 'Cannot modify confirmed transaction: %', OLD.tx_hash; END IF; RETURN NEW; END; $$ language 'plpgsql'; CREATE TRIGGER prevent_confirmed_tx_update BEFORE UPDATE ON token_transactions FOR EACH ROW EXECUTE FUNCTION prevent_tx_update(); CREATE OR REPLACE FUNCTION prevent_tx_delete() RETURNS TRIGGER AS $$ BEGIN RAISE EXCEPTION 'Cannot delete transactions from immutable ledger'; END; $$ language 'plpgsql'; CREATE TRIGGER prevent_tx_deletion BEFORE DELETE ON token_transactions FOR EACH ROW EXECUTE FUNCTION prevent_tx_delete();