feat: migrate clients module to patients + add docs

This commit is contained in:
colinislit
2025-11-23 10:13:00 +01:00
parent 8e3925ea09
commit 6fcb9a0e7b
277 changed files with 9131 additions and 458 deletions

View File

@@ -0,0 +1,76 @@
#!/bin/bash
# ============================================================================
# Apply Organization Seed Migration
# ============================================================================
# Epic: E3.S1 - Organization seed
# Purpose: Create default organization for development
# ============================================================================
set -e
echo "🚀 Applying organization seed migration..."
echo ""
# Load environment variables
if [ -f .env.local ]; then
export $(cat .env.local | grep -v '^#' | grep -v '^$' | xargs)
fi
# Check if Supabase is available
echo "Checking Supabase connection..."
curl -s -o /dev/null -w "%{http_code}" "${NEXT_PUBLIC_SUPABASE_URL}/rest/v1/" -H "apikey: ${NEXT_PUBLIC_SUPABASE_ANON_KEY}" | grep -q "200" || {
echo "❌ Cannot connect to Supabase. Please check if:"
echo " - Supabase is online (not under maintenance)"
echo " - Environment variables are set correctly"
exit 1
}
echo "✅ Supabase is reachable"
echo ""
# Apply migration using psql
MIGRATION_FILE="supabase/migrations/20251122_seed_default_organization.sql"
if [ ! -f "$MIGRATION_FILE" ]; then
echo "❌ Migration file not found: $MIGRATION_FILE"
exit 1
fi
echo "📄 Applying migration: $MIGRATION_FILE"
echo ""
# Get database connection string from Supabase dashboard
# Format: postgresql://postgres:[PASSWORD]@db.dqugbrpwtisgyxscpefg.supabase.co:5432/postgres
# You can find this in: Supabase Dashboard > Project Settings > Database > Connection string
echo "⚠️ To apply this migration, run the SQL file in Supabase SQL Editor:"
echo ""
echo " 1. Go to https://supabase.com/dashboard/project/dqugbrpwtisgyxscpefg/sql"
echo " 2. Copy and paste the contents of:"
echo " $MIGRATION_FILE"
echo " 3. Click 'Run'"
echo ""
echo "Or use the Supabase CLI:"
echo " npx supabase db push"
echo ""
echo "Or use psql (if you have database password):"
echo " psql 'postgresql://postgres:[PASSWORD]@db.dqugbrpwtisgyxscpefg.supabase.co:5432/postgres' -f $MIGRATION_FILE"
echo ""
# Alternative: Use Supabase Management API to apply migration
# This requires the service role key
# Uncomment if you want to use this method:
#
# echo "Applying migration via Supabase Management API..."
#
# MIGRATION_SQL=$(cat "$MIGRATION_FILE")
#
# curl -X POST \
# "${NEXT_PUBLIC_SUPABASE_URL}/rest/v1/rpc/exec" \
# -H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \
# -H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \
# -H "Content-Type: application/json" \
# -d "{\"query\": $(jq -Rs . <<< "$MIGRATION_SQL")}"
echo "✅ Script completed. Please apply the migration manually as described above."

View File

@@ -0,0 +1,165 @@
/**
* ============================================================================
* Seed Default Organization
* ============================================================================
* Epic: E3.S1 - Organization seed
* Purpose: Create default GGZ organization for development
* Usage: npx tsx scripts/seed-organization.ts
* ============================================================================
*/
import { createClient } from '@supabase/supabase-js';
// Load environment variables
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;
if (!supabaseUrl || !supabaseServiceKey) {
console.error('❌ Missing Supabase environment variables');
console.error(' NEXT_PUBLIC_SUPABASE_URL:', supabaseUrl ? '✓' : '✗');
console.error(' SUPABASE_SERVICE_ROLE_KEY:', supabaseServiceKey ? '✓' : '✗');
process.exit(1);
}
// Create Supabase admin client (bypasses RLS)
const supabase = createClient(supabaseUrl, supabaseServiceKey, {
auth: {
autoRefreshToken: false,
persistSession: false
}
});
interface Organization {
id: string;
identifier_agb: string;
identifier_kvk: string;
name: string;
alias: string[];
type_code: string;
type_display: string;
telecom_phone: string;
telecom_email: string;
telecom_website: string;
address_line: string[];
address_city: string;
address_postal_code: string;
address_country: string;
active: boolean;
}
const defaultOrganization: Organization = {
id: '00000000-0000-0000-0000-000000000001',
identifier_agb: 'AGB-DEMO-001',
identifier_kvk: '12345678',
name: 'Demo GGZ Instelling',
alias: ['Demo GGZ', 'DGGZ'],
type_code: 'prov',
type_display: 'Healthcare Provider',
telecom_phone: '030-1234567',
telecom_email: 'info@demo-ggz.nl',
telecom_website: 'https://demo-ggz.nl',
address_line: ['Demonstratiestraat 1'],
address_city: 'Utrecht',
address_postal_code: '3511 AB',
address_country: 'NL',
active: true
};
async function seedOrganization() {
console.log('🚀 Seeding default organization...\n');
try {
// Check if organization already exists
const { data: existing, error: checkError } = await supabase
.from('organizations')
.select('id, name, identifier_agb')
.eq('identifier_agb', 'AGB-DEMO-001')
.maybeSingle();
if (checkError) {
throw new Error(`Error checking existing organization: ${checkError.message}`);
}
if (existing) {
console.log(' Organization already exists:');
console.log(` ID: ${existing.id}`);
console.log(` Name: ${existing.name}`);
console.log(` AGB: ${existing.identifier_agb}`);
console.log('\n🔄 Updating organization...\n');
// Update existing organization
const { error: updateError } = await supabase
.from('organizations')
.update({
identifier_kvk: defaultOrganization.identifier_kvk,
name: defaultOrganization.name,
alias: defaultOrganization.alias,
type_code: defaultOrganization.type_code,
type_display: defaultOrganization.type_display,
telecom_phone: defaultOrganization.telecom_phone,
telecom_email: defaultOrganization.telecom_email,
telecom_website: defaultOrganization.telecom_website,
address_line: defaultOrganization.address_line,
address_city: defaultOrganization.address_city,
address_postal_code: defaultOrganization.address_postal_code,
address_country: defaultOrganization.address_country,
active: defaultOrganization.active,
updated_at: new Date().toISOString()
})
.eq('id', existing.id);
if (updateError) {
throw new Error(`Error updating organization: ${updateError.message}`);
}
console.log('✅ Organization updated successfully');
} else {
console.log(' Creating new organization...\n');
// Insert new organization
const { error: insertError } = await supabase
.from('organizations')
.insert([defaultOrganization]);
if (insertError) {
throw new Error(`Error inserting organization: ${insertError.message}`);
}
console.log('✅ Organization created successfully');
}
// Verify the organization exists
const { data: verified, error: verifyError } = await supabase
.from('organizations')
.select('*')
.eq('identifier_agb', 'AGB-DEMO-001')
.single();
if (verifyError) {
throw new Error(`Error verifying organization: ${verifyError.message}`);
}
console.log('\n✅ Verification successful:');
console.log(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log(` ID: ${verified.id}`);
console.log(` Name: ${verified.name}`);
console.log(` AGB: ${verified.identifier_agb}`);
console.log(` KVK: ${verified.identifier_kvk}`);
console.log(` Email: ${verified.telecom_email}`);
console.log(` Website: ${verified.telecom_website}`);
console.log(` Address: ${verified.address_line.join(', ')}`);
console.log(` City: ${verified.address_city} ${verified.address_postal_code}`);
console.log(` Active: ${verified.active ? 'Yes' : 'No'}`);
console.log(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
console.log('🎉 E3.S1 - Organization seed completed!\n');
} catch (error) {
console.error('\n❌ Error seeding organization:');
console.error(error instanceof Error ? error.message : error);
process.exit(1);
}
}
// Run the seed function
seedOrganization();