#!/bin/bash ############################################################################### # Script de inicialización completa para Anexo76 # # Este script configura automáticamente: # 1. User Profile Attributes en Keycloak (tenant_id) # 2. Clientes de Keycloak (Backend y Frontend) # 3. Mappers de atributos (tenant_id) # 4. Usuario demo en Keycloak (usuario=demo, password=demo123) # 5. Tenant y Company en PostgreSQL # 6. Relación usuario-tenant en tabla user_tenants # 7. Actualización del tenant_id del usuario con el valor real # # Requisitos: # - Keycloak corriendo en http://localhost:8080 # - PostgreSQL corriendo en localhost:5432 # - Base de datos anexo76_core creada # - jq instalado (para procesamiento JSON) # # Nota: El atributo tenant_id se crea con valor inicial "1" y luego # se actualiza con el ID real del tenant creado en PostgreSQL. ############################################################################### # set -e # Comentado para permitir que el script continúe aunque algunos comandos fallen (ej: mapper ya existe) # Colores para output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Variables de configuración KEYCLOAK_URL="${KEYCLOAK_URL:-http://localhost:8080}" KEYCLOAK_ADMIN="${KEYCLOAK_ADMIN:-admin}" KEYCLOAK_ADMIN_PASSWORD="${KEYCLOAK_ADMIN_PASSWORD:-admin}" KEYCLOAK_REALM="${KEYCLOAK_REALM:-master}" KEYCLOACK_ADMIN_URL="${KEYCLOACK_ADMIN_URL:-http://localhost:9000}" POSTGRES_HOST="${POSTGRES_HOST:-localhost}" POSTGRES_PORT="${POSTGRES_PORT:-5432}" POSTGRES_DB="${POSTGRES_DB:-anexo76_core}" POSTGRES_USER="${POSTGRES_USER:-postgres}" POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-postgres}" DEMO_USERNAME="demo" DEMO_PASSWORD="demo123" DEMO_EMAIL="demo@aduanasoft.com" DEMO_FIRSTNAME="Demo" DEMO_LASTNAME="User" TENANT_NAME="Aduanasoft" TENANT_SLUG="aduanasoft" COMPANY_NAME="Aduanasoft S.A. de C.V." COMPANY_RFC="ADS010101AAA" echo -e "${GREEN}════════════════════════════════════════════════════════${NC}" echo -e "${GREEN} Inicialización del Sistema Anexo76${NC}" echo -e "${GREEN}════════════════════════════════════════════════════════${NC}" ############################################################################### # 1. Esperar a que Keycloak esté listo ############################################################################### echo -e "\n${YELLOW}[1/8] Esperando a que Keycloak esté disponible...${NC}" MAX_RETRIES=30 RETRY_COUNT=0 while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do if curl -s -f "${KEYCLOACK_ADMIN_URL}/health/ready" > /dev/null 2>&1; then echo -e "${GREEN}✓ Keycloak está listo${NC}" break fi RETRY_COUNT=$((RETRY_COUNT + 1)) echo "Intento $RETRY_COUNT/$MAX_RETRIES..." sleep 2 done if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then echo -e "${RED}✗ Error: Keycloak no está disponible después de $MAX_RETRIES intentos${NC}" exit 1 fi ############################################################################### # 2. Obtener token de administrador de Keycloak ############################################################################### echo -e "\n${YELLOW}[2/8] Obteniendo token de administrador de Keycloak...${NC}" TOKEN_RESPONSE=$(curl -s -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=${KEYCLOAK_ADMIN}" \ -d "password=${KEYCLOAK_ADMIN_PASSWORD}" \ -d "grant_type=password" \ -d "client_id=admin-cli") ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | grep -o '"access_token":"[^"]*' | sed 's/"access_token":"//') if [ -z "$ACCESS_TOKEN" ]; then echo -e "${RED}✗ Error: No se pudo obtener el token de acceso${NC}" echo "Respuesta: $TOKEN_RESPONSE" exit 1 fi echo -e "${GREEN}✓ Token obtenido exitosamente${NC}" ############################################################################### # 3. Configurar User Profile Attributes con valores por defecto ############################################################################### echo -e "\n${YELLOW}[3/8] Configurando User Profile Attributes...${NC}" # Obtener configuración actual del User Profile USER_PROFILE=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users/profile" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json") # Verificar si tenant_id existe TENANT_ID_EXISTS=$(echo "$USER_PROFILE" | grep -q "\"name\":\"tenant_id\"" && echo "true" || echo "false") if [ "$TENANT_ID_EXISTS" = "false" ]; then echo "Agregando atributo tenant_id al User Profile..." # Crear el atributo tenant_id con valor por defecto UPDATED_PROFILE=$(echo "$USER_PROFILE" | jq '.attributes += [{ "name": "tenant_id", "displayName": "Tenant ID", "validations": {}, "annotations": { "inputType": "text" }, "required": { "roles": [], "scopes": [] }, "permissions": { "view": ["admin", "user"], "edit": ["admin"] }, "multivalued": false, "group": null }]') # Actualizar el User Profile curl -s -X PUT "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users/profile" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "$UPDATED_PROFILE" echo -e "${GREEN}✓ Atributo tenant_id agregado al User Profile${NC}" else echo -e "${YELLOW}⚠ Atributo tenant_id ya existe en User Profile${NC}" fi ############################################################################### # 4. Configurar clientes de Keycloak (Backend y Frontend) ############################################################################### echo -e "\n${YELLOW}[4/8] Configurando clientes de Keycloak...${NC}" # 3.1 Crear cliente Backend echo "Configurando cliente Backend..." BACKEND_CLIENT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=anexo76-backend" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json") if echo "$BACKEND_CLIENT_EXISTS" | grep -q "\"clientId\":\"anexo76-backend\""; then echo -e "${YELLOW}⚠ Cliente Backend ya existe${NC}" BACKEND_CLIENT_ID=$(echo "$BACKEND_CLIENT_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//') else CREATE_BACKEND=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "clientId": "anexo76-backend", "name": "Anexo76 Backend API", "description": "Backend API para el sistema Anexo76", "enabled": true, "protocol": "openid-connect", "publicClient": false, "serviceAccountsEnabled": true, "directAccessGrantsEnabled": true, "standardFlowEnabled": true, "implicitFlowEnabled": false, "rootUrl": "http://localhost:8000/api", "baseUrl": "http://localhost:8000/api", "redirectUris": [ "http://localhost:8000/*", "http://localhost:5173/*" ], "webOrigins": ["http://localhost:8000/api"], "attributes": { "access.token.lifespan": "3600", "client.secret.creation.time": "0" } }') HTTP_CODE=$(echo "$CREATE_BACKEND" | tail -n1) if [ "$HTTP_CODE" = "201" ]; then echo -e "${GREEN}✓ Cliente Backend creado${NC}" # Obtener ID del cliente recién creado BACKEND_CLIENT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=anexo76-backend" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json") BACKEND_CLIENT_ID=$(echo "$BACKEND_CLIENT_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//') else echo -e "${RED}✗ Error al crear cliente Backend (HTTP ${HTTP_CODE})${NC}" fi fi # Obtener y mostrar el secret del cliente Backend if [ -n "$BACKEND_CLIENT_ID" ]; then BACKEND_SECRET=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${BACKEND_CLIENT_ID}/client-secret" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" | grep -o '"value":"[^"]*' | sed 's/"value":"//') echo -e "${GREEN}✓ Backend Client ID: anexo76-backend${NC}" echo -e "${GREEN}✓ Backend Client Secret: ${BACKEND_SECRET}${NC}" # Actualizar archivo .env con el client secret if [ -n "$BACKEND_SECRET" ]; then ENV_FILE="" # Buscar archivo .env en el directorio actual o en el directorio padre if [ -f ".env" ]; then ENV_FILE=".env" elif [ -f "../.env" ]; then ENV_FILE="../.env" fi if [ -n "$ENV_FILE" ]; then # Verificar si la variable ya existe en el archivo if grep -q "^KEYCLOAK_CLIENT_SECRET=" "$ENV_FILE"; then # Actualizar el valor existente if [[ "$OSTYPE" == "darwin"* ]]; then # macOS sed -i '' "s|^KEYCLOAK_CLIENT_SECRET=.*|KEYCLOAK_CLIENT_SECRET=${BACKEND_SECRET}|" "$ENV_FILE" else # Linux sed -i "s|^KEYCLOAK_CLIENT_SECRET=.*|KEYCLOAK_CLIENT_SECRET=${BACKEND_SECRET}|" "$ENV_FILE" fi echo -e "${GREEN}✓ KEYCLOAK_CLIENT_SECRET actualizado en ${ENV_FILE}${NC}" else # Agregar la variable si no existe echo "KEYCLOAK_CLIENT_SECRET=${BACKEND_SECRET}" >> "$ENV_FILE" echo -e "${GREEN}✓ KEYCLOAK_CLIENT_SECRET agregado a ${ENV_FILE}${NC}" fi else echo -e "${YELLOW}⚠ No se encontró archivo .env, el secret debe agregarse manualmente${NC}" fi fi fi # 3.2 Crear cliente Frontend echo "Configurando cliente Frontend..." FRONTEND_CLIENT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=anexo76-frontend" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json") if echo "$FRONTEND_CLIENT_EXISTS" | grep -q "\"clientId\":\"anexo76-frontend\""; then echo -e "${YELLOW}⚠ Cliente Frontend ya existe${NC}" FRONTEND_CLIENT_ID=$(echo "$FRONTEND_CLIENT_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//') else CREATE_FRONTEND=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "clientId": "anexo76-frontend", "name": "Anexo76 Frontend", "description": "Aplicación web frontend para el sistema Anexo76", "enabled": true, "protocol": "openid-connect", "publicClient": true, "directAccessGrantsEnabled": false, "standardFlowEnabled": true, "implicitFlowEnabled": false, "rootUrl": "http://localhost:5173", "baseUrl": "http://localhost:5173", "redirectUris": [ "http://localhost:5173/*", "http://localhost:3000/*" ], "webOrigins": [ "http://localhost:5173", "http://localhost:3000" ], "attributes": { "pkce.code.challenge.method": "S256" } }') HTTP_CODE=$(echo "$CREATE_FRONTEND" | tail -n1) RESPONSE_BODY=$(echo "$CREATE_FRONTEND" | head -n -1) if [ "$HTTP_CODE" = "201" ]; then echo -e "${GREEN}✓ Cliente Frontend creado${NC}" # Obtener ID del cliente recién creado FRONTEND_CLIENT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=anexo76-frontend" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json") FRONTEND_CLIENT_ID=$(echo "$FRONTEND_CLIENT_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//') else echo -e "${RED}✗ Error al crear cliente Frontend (HTTP ${HTTP_CODE})${NC}" echo "Respuesta del servidor: $RESPONSE_BODY" fi fi ############################################################################### # 5. Configurar Mappers para tenant_id ############################################################################### echo -e "\n${YELLOW}[5/8] Configurando mappers para tenant_id...${NC}" # 4.1 Configurar mapper para Backend if [ -n "$BACKEND_CLIENT_ID" ]; then echo "Configurando mapper para Backend..." # Verificar si el mapper tenant_id ya existe en el cliente MAPPER_TENANT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${BACKEND_CLIENT_ID}/protocol-mappers/models" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" | grep -o "\"name\":\"tenant-id-mapper\"") if [ -z "$MAPPER_TENANT_EXISTS" ]; then # Crear mapper para tenant_id directamente en el cliente CREATE_MAPPER_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${BACKEND_CLIENT_ID}/protocol-mappers/models" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "tenant-id-mapper", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "config": { "user.attribute": "tenant_id", "claim.name": "tenant_id", "jsonType.label": "String", "id.token.claim": "true", "access.token.claim": "true", "userinfo.token.claim": "true" } }') HTTP_CODE=$(echo "$CREATE_MAPPER_RESPONSE" | tail -n1) if [ "$HTTP_CODE" = "201" ]; then echo -e "${GREEN}✓ Mapper tenant_id creado para Backend${NC}" else echo -e "${YELLOW}⚠ Error al crear mapper para Backend (HTTP ${HTTP_CODE})${NC}" echo "Respuesta: $(echo "$CREATE_MAPPER_RESPONSE" | head -n -1)" fi else echo -e "${YELLOW}⚠ Mapper tenant_id ya existe para Backend${NC}" fi fi # 4.2 Configurar mapper para Frontend if [ -n "$FRONTEND_CLIENT_ID" ]; then echo "Configurando mapper para Frontend..." # Verificar si el mapper tenant_id ya existe en el cliente MAPPER_TENANT_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${FRONTEND_CLIENT_ID}/protocol-mappers/models" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" | grep -o "\"name\":\"tenant-id-mapper\"") if [ -z "$MAPPER_TENANT_EXISTS" ]; then # Crear mapper para tenant_id directamente en el cliente CREATE_MAPPER_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${FRONTEND_CLIENT_ID}/protocol-mappers/models" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "name": "tenant-id-mapper", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "config": { "user.attribute": "tenant_id", "claim.name": "tenant_id", "jsonType.label": "String", "id.token.claim": "true", "access.token.claim": "true", "userinfo.token.claim": "true" } }') HTTP_CODE=$(echo "$CREATE_MAPPER_RESPONSE" | tail -n1) if [ "$HTTP_CODE" = "201" ]; then echo -e "${GREEN}✓ Mapper tenant_id creado para Frontend${NC}" else echo -e "${YELLOW}⚠ Error al crear mapper para Frontend (HTTP ${HTTP_CODE})${NC}" echo "Respuesta: $(echo "$CREATE_MAPPER_RESPONSE" | head -n -1)" fi else echo -e "${YELLOW}⚠ Mapper tenant_id ya existe para Frontend${NC}" fi fi ############################################################################### # 6. Crear usuario demo en Keycloak ############################################################################### echo -e "\n${YELLOW}[6/8] Creando usuario demo en Keycloak...${NC}" # Verificar si el usuario ya existe USER_EXISTS=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users?username=${DEMO_USERNAME}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json") if echo "$USER_EXISTS" | grep -q "\"username\":\"${DEMO_USERNAME}\""; then echo -e "${YELLOW}⚠ Usuario demo ya existe, actualizando...${NC}" USER_ID=$(echo "$USER_EXISTS" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//') # Actualizar usuario existente curl -s -X PUT "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users/${USER_ID}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"enabled\": true, \"firstName\": \"${DEMO_FIRSTNAME}\", \"lastName\": \"${DEMO_LASTNAME}\", \"email\": \"${DEMO_EMAIL}\", \"emailVerified\": true }" # Resetear contraseña curl -s -X PUT "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users/${USER_ID}/reset-password" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"type\": \"password\", \"value\": \"${DEMO_PASSWORD}\", \"temporary\": false }" echo -e "${GREEN}✓ Usuario demo actualizado${NC}" else # Crear nuevo usuario con tenant_id por defecto CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"username\": \"${DEMO_USERNAME}\", \"enabled\": true, \"firstName\": \"${DEMO_FIRSTNAME}\", \"lastName\": \"${DEMO_LASTNAME}\", \"email\": \"${DEMO_EMAIL}\", \"emailVerified\": true, \"attributes\": { \"tenant_id\": [\"1\"] }, \"credentials\": [{ \"type\": \"password\", \"value\": \"${DEMO_PASSWORD}\", \"temporary\": false }] }") HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1) if [ "$HTTP_CODE" = "201" ]; then echo -e "${GREEN}✓ Usuario demo creado exitosamente${NC}" # Obtener el ID del usuario recién creado USER_RESPONSE=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users?username=${DEMO_USERNAME}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json") USER_ID=$(echo "$USER_RESPONSE" | grep -o '"id":"[^"]*' | head -1 | sed 's/"id":"//') else echo -e "${RED}✗ Error al crear usuario (HTTP ${HTTP_CODE})${NC}" echo "Respuesta: $CREATE_RESPONSE" exit 1 fi fi echo -e "${GREEN}✓ Usuario: ${DEMO_USERNAME}${NC}" echo -e "${GREEN}✓ Password: ${DEMO_PASSWORD}${NC}" echo -e "${GREEN}✓ Keycloak User ID: ${USER_ID}${NC}" ############################################################################### # 7. Agregar atributo tenant_id al usuario ############################################################################### echo -e "\n${YELLOW}[7/8] Configurando atributo tenant_id para usuario demo...${NC}" # Nota: El tenant_id se agregará después de crear el tenant en PostgreSQL ############################################################################### # 8. Crear tenant y company en PostgreSQL ############################################################################### echo -e "\n${YELLOW}[8/8] Creando tenant y company en PostgreSQL...${NC}" # Esperar a que PostgreSQL esté listo echo "Esperando a que PostgreSQL esté disponible..." MAX_PG_RETRIES=60 PG_RETRY_COUNT=0 while [ $PG_RETRY_COUNT -lt $MAX_PG_RETRIES ]; do # Usar docker exec para verificar pg_isready directamente if docker exec anexo76-postgres-a76 pg_isready -h localhost -U "${POSTGRES_USER}" > /dev/null 2>&1; then echo -e "${GREEN}✓ PostgreSQL está listo${NC}" break fi PG_RETRY_COUNT=$((PG_RETRY_COUNT + 1)) echo "Intento $PG_RETRY_COUNT/$MAX_PG_RETRIES..." sleep 1 done if [ $PG_RETRY_COUNT -eq $MAX_PG_RETRIES ]; then echo -e "${RED}✗ Error: PostgreSQL no está disponible después de $MAX_PG_RETRIES intentos${NC}" exit 1 fi # Insertar o actualizar tenant echo "Insertando tenant en PostgreSQL..." docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -c "INSERT INTO a76.tenants (name, slug, type, keycloak_realm, contact_email, is_active, created_at, updated_at) VALUES ('${TENANT_NAME}', '${TENANT_SLUG}', 'SHARED'::tenanttype, '${KEYCLOAK_REALM}', '${DEMO_EMAIL}', true, now(), now()) ON CONFLICT (slug) DO UPDATE SET name = EXCLUDED.name, contact_email = EXCLUDED.contact_email, updated_at = CURRENT_TIMESTAMP;" 2>&1 # Obtener el ID del tenant con mejor manejo de errores echo "Obteniendo ID del tenant..." TENANT_ID_RESULT=$(docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -t -c "SELECT id FROM a76.tenants WHERE slug = '${TENANT_SLUG}';" 2>&1) if [ $? -ne 0 ]; then echo -e "${RED}✗ Error al consultar el tenant:${NC}" echo "$TENANT_ID_RESULT" echo -e "${YELLOW}Verificando si la tabla existe...${NC}" docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -c "\dt a76.tenants;" exit 1 fi TENANT_ID=$(echo "$TENANT_ID_RESULT" | xargs) # Trim whitespace if [ -z "$TENANT_ID" ]; then echo -e "${RED}✗ Error: No se pudo obtener el ID del tenant${NC}" echo "Resultado de la consulta: '$TENANT_ID_RESULT'" echo -e "${YELLOW}Intentando ver todos los tenants...${NC}" docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -c "SELECT id, slug FROM a76.tenants LIMIT 10;" exit 1 fi echo -e "${GREEN}✓ Tenant ID: ${TENANT_ID}${NC}" # Insertar company si no existe COMPANY_EXISTS=$(docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -t -c "SELECT COUNT(*) FROM a76.company WHERE tenant_id = ${TENANT_ID};") COMPANY_EXISTS=$(echo "$COMPANY_EXISTS" | xargs) if [ "$COMPANY_EXISTS" = "0" ]; then docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -c "INSERT INTO a76.company (tenant_id, name, rfc, is_service_company, created_at, updated_at) VALUES (${TENANT_ID}, '${COMPANY_NAME}', '${COMPANY_RFC}', false, now(), now());" 2>&1 echo -e "${GREEN}✓ Company creada${NC}" else echo -e "${YELLOW}⚠ Company ya existe para este tenant${NC}" fi # Obtener información de la company COMPANY_INFO=$(docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -t -c "SELECT id, name FROM a76.company WHERE tenant_id = ${TENANT_ID} LIMIT 1;") echo -e "${GREEN}✓ Company: ${COMPANY_INFO}${NC}" # Agregar tenant_id al usuario demo en Keycloak echo -e "\n${YELLOW}Asignando tenant_id al usuario demo...${NC}" curl -s -X PUT "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users/${USER_ID}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"attributes\": { \"tenant_id\": [\"${TENANT_ID}\"] } }" echo -e "${GREEN}✓ Atributo tenant_id asignado al usuario${NC}" # Agregar relación usuario-tenant en la base de datos echo -e "\n${YELLOW}Creando relación usuario-tenant en la base de datos...${NC}" docker exec -e PGPASSWORD="${POSTGRES_PASSWORD}" anexo76-postgres-a76 psql -h localhost -p 5432 -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" -c "INSERT INTO a76.user_tenants (keycloak_user_id, tenant_id, company_id, role, is_active, created_at, updated_at) VALUES ('${USER_ID}', ${TENANT_ID}, 1, 'admin', true, now(), now()) ON CONFLICT (keycloak_user_id, tenant_id, company_id) DO UPDATE SET is_active = true, updated_at = CURRENT_TIMESTAMP;" 2>&1 echo -e "${GREEN}✓ Relación usuario-tenant creada en la base de datos${NC}" ############################################################################### # Resumen final ############################################################################### echo -e "\n${GREEN}════════════════════════════════════════════════════════${NC}" echo -e "${GREEN} ✓ Inicialización completada exitosamente${NC}" echo -e "${GREEN}════════════════════════════════════════════════════════${NC}" echo -e "\n${YELLOW}Credenciales de acceso:${NC}" echo -e " Usuario: ${GREEN}${DEMO_USERNAME}${NC}" echo -e " Password: ${GREEN}${DEMO_PASSWORD}${NC}" echo -e " Email: ${GREEN}${DEMO_EMAIL}${NC}" echo -e "\n${YELLOW}Información del sistema:${NC}" echo -e " Tenant: ${GREEN}${TENANT_NAME} (ID: ${TENANT_ID})${NC}" echo -e " Realm: ${GREEN}${KEYCLOAK_REALM}${NC}" echo -e " Keycloak URL: ${GREEN}${KEYCLOAK_URL}${NC}" echo -e "\n${YELLOW}Clientes Keycloak configurados:${NC}" echo -e " Backend Client ID: ${GREEN}anexo76-backend${NC}" if [ -n "$BACKEND_SECRET" ]; then echo -e " Backend Secret: ${GREEN}${BACKEND_SECRET}${NC}" if [ -n "$ENV_FILE" ]; then echo -e " ${GREEN}✓${NC} KEYCLOAK_CLIENT_SECRET actualizado en ${ENV_FILE}" else echo -e " ${YELLOW}⚠${NC} Agregar manualmente al archivo .env como KEYCLOAK_CLIENT_SECRET" fi fi echo -e " Frontend Client ID: ${GREEN}anexo76-frontend${NC}" echo -e "\n${YELLOW}User Profile Attributes configurados:${NC}" echo -e " ${GREEN}✓${NC} tenant_id (opcional, valor inicial: 1)" echo -e "\n${YELLOW}Mappers configurados:${NC}" echo -e " ${GREEN}✓${NC} tenant_id mapper para Backend" echo -e " ${GREEN}✓${NC} tenant_id mapper para Frontend" echo -e "\n${YELLOW}Configuración del usuario demo:${NC}" echo -e " ${GREEN}✓${NC} tenant_id actualizado al ID real: ${TENANT_ID}" echo -e " ${GREEN}✓${NC} Relación usuario-tenant creada (rol: admin)" echo -e "\n${YELLOW}Puedes acceder al sistema en:${NC}" echo -e " ${GREEN}http://localhost:5173${NC}" echo -e "\n${GREEN}════════════════════════════════════════════════════════${NC}\n"