-
Notifications
You must be signed in to change notification settings - Fork 76
Feat: Real-time Blockchain-Database Synchronization System #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d4a8928
8cb8ffe
b1a6c65
91c0e41
53518ec
13ff00c
5c2a617
05d544f
ba5bcfa
08c437b
8ad499b
db1c97b
8bec58e
5acc8d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| -- Migration: Create sync tables for blockchain synchronization | ||
| -- This migration adds tables to track blockchain events and sync state | ||
|
|
||
| -- Create sync_state table to track synchronization progress | ||
| CREATE TABLE IF NOT EXISTS public.sync_state ( | ||
| id INTEGER PRIMARY KEY DEFAULT 1, | ||
| last_processed_block BIGINT NOT NULL DEFAULT 0, | ||
| total_events_processed INTEGER NOT NULL DEFAULT 0, | ||
| failed_events INTEGER NOT NULL DEFAULT 0, | ||
| last_sync_time TIMESTAMPTZ, | ||
| created_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now()), | ||
| updated_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now()) | ||
| ); | ||
|
|
||
| -- Create sync_events table to track all blockchain events | ||
| CREATE TABLE IF NOT EXISTS public.sync_events ( | ||
| id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||
| event_id TEXT NOT NULL UNIQUE, | ||
| event_type TEXT NOT NULL CHECK (event_type IN ('booking_created', 'booking_updated', 'booking_cancelled', 'payment_confirmed')), | ||
| booking_id TEXT, | ||
| property_id TEXT, | ||
| user_id TEXT, | ||
| event_data JSONB NOT NULL, | ||
| processed BOOLEAN NOT NULL DEFAULT FALSE, | ||
| error TEXT, | ||
| created_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now()), | ||
| processed_at TIMESTAMPTZ, | ||
|
|
||
| CONSTRAINT valid_event_type CHECK (event_type IN ('booking_created', 'booking_updated', 'booking_cancelled', 'payment_confirmed')) | ||
| ); | ||
|
|
||
| -- Create sync_logs table for detailed logging | ||
| CREATE TABLE IF NOT EXISTS public.sync_logs ( | ||
| id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||
| operation TEXT NOT NULL, | ||
| status TEXT NOT NULL CHECK (status IN ('success', 'error', 'warning')), | ||
| message TEXT, | ||
| data JSONB, | ||
| error_details JSONB, | ||
| created_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now()) | ||
| ); | ||
|
|
||
| -- Create indexes for better performance | ||
| CREATE INDEX IF NOT EXISTS sync_events_event_type_idx ON public.sync_events(event_type); | ||
| CREATE INDEX IF NOT EXISTS sync_events_processed_idx ON public.sync_events(processed); | ||
| CREATE INDEX IF NOT EXISTS sync_events_created_at_idx ON public.sync_events(created_at); | ||
| CREATE INDEX IF NOT EXISTS sync_events_booking_id_idx ON public.sync_events(booking_id); | ||
| CREATE INDEX IF NOT EXISTS sync_events_property_id_idx ON public.sync_events(property_id); | ||
| CREATE INDEX IF NOT EXISTS sync_events_user_id_idx ON public.sync_events(user_id); | ||
|
|
||
| CREATE INDEX IF NOT EXISTS sync_logs_operation_idx ON public.sync_logs(operation); | ||
| CREATE INDEX IF NOT EXISTS sync_logs_status_idx ON public.sync_logs(status); | ||
| CREATE INDEX IF NOT EXISTS sync_logs_created_at_idx ON public.sync_logs(created_at); | ||
|
|
||
| -- Insert initial sync state | ||
| INSERT INTO public.sync_state (id, last_processed_block, total_events_processed, failed_events) | ||
| VALUES (1, 0, 0, 0) | ||
| ON CONFLICT (id) DO NOTHING; | ||
|
|
||
| -- Create function to update updated_at timestamp | ||
| CREATE OR REPLACE FUNCTION update_sync_updated_at_column() | ||
| RETURNS TRIGGER AS $$ | ||
| BEGIN | ||
| NEW.updated_at = timezone('utc'::text, now()); | ||
| RETURN NEW; | ||
| END; | ||
| $$ language 'plpgsql'; | ||
|
|
||
| -- Create triggers for updated_at | ||
| CREATE TRIGGER update_sync_state_updated_at | ||
| BEFORE UPDATE ON public.sync_state | ||
| FOR EACH ROW | ||
| EXECUTE FUNCTION update_sync_updated_at_column(); | ||
|
|
||
| -- Add RLS policies for sync tables (if RLS is enabled) | ||
| ALTER TABLE public.sync_state ENABLE ROW LEVEL SECURITY; | ||
| ALTER TABLE public.sync_events ENABLE ROW LEVEL SECURITY; | ||
| ALTER TABLE public.sync_logs ENABLE ROW LEVEL SECURITY; | ||
|
|
||
| -- Create policies for admin access only | ||
| CREATE POLICY "Admin access to sync_state" ON public.sync_state | ||
| FOR ALL USING (auth.role() = 'admin'); | ||
|
|
||
| CREATE POLICY "Admin access to sync_events" ON public.sync_events | ||
| FOR ALL USING (auth.role() = 'admin'); | ||
|
|
||
| CREATE POLICY "Admin access to sync_logs" ON public.sync_logs | ||
| FOR ALL USING (auth.role() = 'admin'); | ||
|
|
||
| -- Create view for sync dashboard | ||
| CREATE OR REPLACE VIEW public.sync_dashboard AS | ||
| SELECT | ||
| s.last_processed_block, | ||
| s.total_events_processed, | ||
| s.failed_events, | ||
| s.last_sync_time, | ||
| s.updated_at as last_updated, | ||
| COUNT(se.id) as total_events, | ||
| COUNT(CASE WHEN se.processed = false THEN 1 END) as pending_events, | ||
| COUNT(CASE WHEN se.processed = false AND se.error IS NOT NULL THEN 1 END) as failed_events_count, | ||
| MAX(se.created_at) as last_event_time | ||
| FROM public.sync_state s | ||
| LEFT JOIN public.sync_events se ON true | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ ๏ธ Refactor suggestion Optimize dashboard view join condition. The FROM public.sync_state s
-LEFT JOIN public.sync_events se ON true
+LEFT JOIN public.sync_events se ON s.id IS NOT NULLOr consider restructuring the view to use subqueries for better performance: CREATE OR REPLACE VIEW public.sync_dashboard AS
SELECT
s.last_processed_block,
s.total_events_processed,
s.failed_events,
s.last_sync_time,
s.updated_at as last_updated,
(SELECT COUNT(*) FROM public.sync_events) as total_events,
(SELECT COUNT(*) FROM public.sync_events WHERE processed = false) as pending_events,
(SELECT COUNT(*) FROM public.sync_events WHERE processed = false AND error IS NOT NULL) as failed_events_count,
(SELECT MAX(created_at) FROM public.sync_events) as last_event_time
FROM public.sync_state s;๐ค Prompt for AI Agents |
||
| GROUP BY s.id, s.last_processed_block, s.total_events_processed, s.failed_events, s.last_sync_time, s.updated_at; | ||
|
|
||
| -- Grant permissions | ||
| GRANT SELECT ON public.sync_dashboard TO authenticated; | ||
| GRANT ALL ON public.sync_state TO authenticated; | ||
| GRANT ALL ON public.sync_events TO authenticated; | ||
| GRANT ALL ON public.sync_logs TO authenticated; | ||
|
Comment on lines
+107
to
+110
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ ๏ธ Refactor suggestion Reconsider broad permissions for authenticated users. Granting -- Grant permissions
GRANT SELECT ON public.sync_dashboard TO authenticated;
-GRANT ALL ON public.sync_state TO authenticated;
-GRANT ALL ON public.sync_events TO authenticated;
-GRANT ALL ON public.sync_logs TO authenticated;
+-- Grant specific permissions based on actual service needs
+GRANT SELECT, INSERT, UPDATE ON public.sync_state TO service_role;
+GRANT SELECT, INSERT, UPDATE ON public.sync_events TO service_role;
+GRANT SELECT, INSERT ON public.sync_logs TO service_role;๐ค Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Database Configuration | ||
| SUPABASE_URL=your_supabase_url | ||
| SUPABASE_ANON_KEY=your_supabase_anon_key | ||
| SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key | ||
|
|
||
| # JWT Configuration | ||
| JWT_SECRET=your_jwt_secret_key | ||
|
|
||
| # Stellar Network Configuration | ||
| SOROBAN_RPC_URL=https://soroban-testnet.stellar.org | ||
| SOROBAN_CONTRACT_ID=your_contract_id_here | ||
| SOROBAN_NETWORK_PASSPHRASE=Test SDF Network ; September 2015 | ||
| STELLAR_SECRET_KEY=your_stellar_secret_key | ||
|
Comment on lines
+12
to
+13
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix duplicate network passphrase configuration. The SOROBAN_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
STELLAR_SECRET_KEY=your_stellar_secret_key
# Legacy Stellar Configuration (for backward compatibility)
STELLAR_RPC_URL=https://horizon-testnet.stellar.org
BOOKING_CONTRACT_ADDRESS=your_booking_contract_address
STELLAR_SOURCE_ACCOUNT=your_stellar_source_account
-STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
+# STELLAR_NETWORK_PASSPHRASE uses SOROBAN_NETWORK_PASSPHRASE for consistencyAlso applies to: 19-19 ๐ค Prompt for AI Agents |
||
|
|
||
| # Legacy Stellar Configuration (for backward compatibility) | ||
| STELLAR_RPC_URL=https://horizon-testnet.stellar.org | ||
| BOOKING_CONTRACT_ADDRESS=your_booking_contract_address | ||
| STELLAR_SOURCE_ACCOUNT=your_stellar_source_account | ||
| STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015 | ||
|
|
||
| # Sync Service Configuration | ||
| SYNC_POLL_INTERVAL=5000 | ||
| SYNC_MAX_RETRIES=3 | ||
| SYNC_RETRY_DELAY=1000 | ||
|
|
||
| # Server Configuration | ||
| PORT=3001 | ||
| NODE_ENV=development | ||
|
|
||
| # Mock Configuration (for testing) | ||
| USE_MOCK=false | ||
|
|
||
| # Rate Limiting | ||
| RATE_LIMIT_WINDOW_MS=900000 | ||
| RATE_LIMIT_MAX_REQUESTS=100 | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate constraint definition.
The
event_typeconstraint is defined twice - once inline and once as a separate constraint.event_type TEXT NOT NULL CHECK (event_type IN ('booking_created', 'booking_updated', 'booking_cancelled', 'payment_confirmed')), booking_id TEXT, property_id TEXT, user_id TEXT, event_data JSONB NOT NULL, processed BOOLEAN NOT NULL DEFAULT FALSE, error TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT timezone('utc'::text, now()), processed_at TIMESTAMPTZ, - CONSTRAINT valid_event_type CHECK (event_type IN ('booking_created', 'booking_updated', 'booking_cancelled', 'payment_confirmed'))Also applies to: 29-29
๐ค Prompt for AI Agents