trading-platform-database-v2/scripts/create-database.sh
rckrdmrd 45e77e9a9c feat: Initial commit - Database schemas and scripts
DDL schemas for Trading Platform:
- User management
- Authentication
- Payments
- Education
- ML predictions
- Trading data

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 04:30:23 -06:00

323 lines
9.1 KiB
Bash
Executable File

#!/bin/bash
# ============================================================================
# CREATE DATABASE SCRIPT - Trading Platform
# ============================================================================
#
# Script de carga limpia para crear la base de datos desde DDL.
# Cumple con DIRECTIVA-POLITICA-CARGA-LIMPIA.md
#
# USO:
# ./create-database.sh # Crear BD (si no existe)
# ./create-database.sh --drop-first # Drop y recrear
# ./create-database.sh --seeds-only # Solo ejecutar seeds
#
# ============================================================================
set -e
# Colores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuración
# Valores según DEVENV-PORTS-INVENTORY.yml (instancia nativa compartida)
# IMPORTANTE: Puerto 5432 = instancia nativa PostgreSQL (NO Docker)
# Nombres homologados: trading_platform / trading_user (2026-01-07)
DB_NAME="${DB_NAME:-trading_platform}"
DB_USER="${DB_USER:-trading_user}"
DB_PASSWORD="${DB_PASSWORD:-trading_dev_2025}"
DB_HOST="${DB_HOST:-localhost}"
DB_PORT="${DB_PORT:-5432}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DDL_DIR="$SCRIPT_DIR/../ddl"
SEEDS_DIR="$SCRIPT_DIR/../seeds"
# Función de logging
log() {
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
}
log_success() {
echo -e "${GREEN}[✓]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[!]${NC} $1"
}
log_error() {
echo -e "${RED}[✗]${NC} $1"
}
# Función para ejecutar SQL
run_sql() {
local file=$1
local description=$2
if [ -f "$file" ]; then
log "Ejecutando: $description"
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -f "$file" -q
log_success "$description"
else
log_warning "Archivo no encontrado: $file"
fi
}
# Función para ejecutar SQL en orden
run_sql_dir() {
local dir=$1
local description=$2
if [ -d "$dir" ]; then
log "Procesando directorio: $description"
for file in "$dir"/*.sql; do
if [ -f "$file" ]; then
local filename=$(basename "$file")
run_sql "$file" "$filename"
fi
done
else
log_warning "Directorio no encontrado: $dir"
fi
}
# Verificar conexión
check_connection() {
log "Verificando conexión a PostgreSQL..."
if PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d postgres -c '\q' 2>/dev/null; then
log_success "Conexión exitosa"
else
log_error "No se puede conectar a PostgreSQL"
exit 1
fi
}
# Drop database si existe
drop_database() {
log "Eliminando base de datos $DB_NAME si existe..."
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d postgres -c "DROP DATABASE IF EXISTS $DB_NAME;" -q
log_success "Base de datos eliminada"
}
# Crear database
create_database() {
log "Creando base de datos $DB_NAME..."
# Intentar con locale explícito, si falla usar default
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d postgres -c "CREATE DATABASE $DB_NAME WITH ENCODING 'UTF8' LC_COLLATE='en_US.UTF-8' LC_CTYPE='en_US.UTF-8' TEMPLATE=template0;" -q 2>/dev/null || \
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d postgres -c "CREATE DATABASE $DB_NAME WITH ENCODING 'UTF8';" -q 2>/dev/null || true
log_success "Base de datos creada"
}
# Crear schemas
create_schemas() {
log "Creando schemas..."
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -q << EOF
-- Schemas principales
CREATE SCHEMA IF NOT EXISTS auth;
CREATE SCHEMA IF NOT EXISTS education;
CREATE SCHEMA IF NOT EXISTS trading;
CREATE SCHEMA IF NOT EXISTS investment;
CREATE SCHEMA IF NOT EXISTS financial;
CREATE SCHEMA IF NOT EXISTS ml;
CREATE SCHEMA IF NOT EXISTS llm;
CREATE SCHEMA IF NOT EXISTS audit;
CREATE SCHEMA IF NOT EXISTS market_data;
-- Comentarios
COMMENT ON SCHEMA auth IS 'Autenticación y usuarios';
COMMENT ON SCHEMA education IS 'Plataforma educativa';
COMMENT ON SCHEMA trading IS 'Trading y paper engine';
COMMENT ON SCHEMA investment IS 'Cuentas PAMM';
COMMENT ON SCHEMA financial IS 'Pagos, suscripciones, wallets';
COMMENT ON SCHEMA ml IS 'Machine Learning signals';
COMMENT ON SCHEMA llm IS 'LLM Agent';
COMMENT ON SCHEMA audit IS 'Auditoría y logs';
COMMENT ON SCHEMA market_data IS 'Datos de mercado OHLCV (5m, 15m)';
-- Search path
ALTER DATABASE $DB_NAME SET search_path TO auth, public;
EOF
log_success "Schemas creados"
}
# Cargar extensiones
load_extensions() {
log "Cargando extensiones..."
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -q << EOF
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
CREATE EXTENSION IF NOT EXISTS "btree_gin";
CREATE EXTENSION IF NOT EXISTS "vector"; -- pgvector para embeddings LLM
EOF
log_success "Extensiones cargadas"
}
# Cargar DDL por schema
load_ddl() {
local schema=$1
local schema_dir="$DDL_DIR/schemas/$schema"
log "Cargando DDL para schema: $schema"
# 0. Extensiones primero (si existen)
if [ -f "$schema_dir/00-extensions.sql" ]; then
run_sql "$schema_dir/00-extensions.sql" "$schema: Extensions"
fi
# 1. Enums (busca 00-enums.sql o 01-enums.sql)
if [ -f "$schema_dir/00-enums.sql" ]; then
run_sql "$schema_dir/00-enums.sql" "$schema: ENUMs"
elif [ -f "$schema_dir/01-enums.sql" ]; then
run_sql "$schema_dir/01-enums.sql" "$schema: ENUMs"
fi
# 2. Tablas en orden
run_sql_dir "$schema_dir/tables" "$schema: Tables"
# 3. Funciones
run_sql_dir "$schema_dir/functions" "$schema: Functions"
# 4. Triggers
run_sql_dir "$schema_dir/triggers" "$schema: Triggers"
# 5. Views
run_sql_dir "$schema_dir/views" "$schema: Views"
# 6. Indexes adicionales
if [ -f "$schema_dir/99-indexes.sql" ]; then
run_sql "$schema_dir/99-indexes.sql" "$schema: Indexes"
fi
log_success "Schema $schema cargado"
}
# Cargar todos los DDL
load_all_ddl() {
log "Cargando todos los DDL..."
# Orden de carga (respeta dependencias)
local schemas=("auth" "education" "financial" "trading" "investment" "ml" "llm" "audit" "market_data")
for schema in "${schemas[@]}"; do
if [ -d "$DDL_DIR/schemas/$schema" ]; then
load_ddl "$schema"
else
log_warning "Schema $schema no tiene DDL definido"
fi
done
log_success "Todos los DDL cargados"
}
# Cargar seeds
load_seeds() {
local env=${1:-prod}
local seeds_path="$SEEDS_DIR/$env"
log "Cargando seeds ($env)..."
if [ -d "$seeds_path" ]; then
for schema_dir in "$seeds_path"/*/; do
if [ -d "$schema_dir" ]; then
local schema=$(basename "$schema_dir")
run_sql_dir "$schema_dir" "Seeds: $schema"
fi
done
log_success "Seeds cargados"
else
log_warning "No hay seeds para ambiente: $env"
fi
}
# Validar integridad
validate_database() {
log "Validando integridad de la base de datos..."
# Contar tablas por schema
local result=$(PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -t -c "
SELECT schemaname, COUNT(*)
FROM pg_tables
WHERE schemaname IN ('auth', 'education', 'trading', 'investment', 'financial', 'ml', 'llm', 'audit', 'market_data')
GROUP BY schemaname
ORDER BY schemaname;
")
echo ""
echo "=== Resumen de Tablas por Schema ==="
echo "$result"
echo ""
# Verificar FKs
local fk_count=$(PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -t -c "
SELECT COUNT(*) FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY';
")
log_success "Foreign Keys: $fk_count"
log_success "Validación completada"
}
# Main
main() {
echo ""
echo "=============================================="
echo " Trading Platform - Database Setup"
echo " Política de Carga Limpia (DDL-First)"
echo "=============================================="
echo ""
local drop_first=false
local seeds_only=false
local seed_env="prod"
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--drop-first)
drop_first=true
shift
;;
--seeds-only)
seeds_only=true
shift
;;
--env)
seed_env=$2
shift 2
;;
*)
log_error "Argumento desconocido: $1"
exit 1
;;
esac
done
check_connection
if [ "$seeds_only" = true ]; then
load_seeds "$seed_env"
exit 0
fi
if [ "$drop_first" = true ]; then
drop_database
fi
create_database
create_schemas
load_extensions
load_all_ddl
load_seeds "$seed_env"
validate_database
echo ""
log_success "Base de datos creada exitosamente!"
echo ""
}
main "$@"