feat: Update default admin credentials and organization branding, refactor admin creation in install script to direct database insertion, disable rate limiting, and update documentation.
This commit is contained in:
+3
-3
@@ -7,7 +7,7 @@ LMS_DATABASE_URL=postgresql://user:password@localhost:5433/openccb_lms
|
|||||||
# General fallback
|
# General fallback
|
||||||
DATABASE_URL=postgresql://user:password@localhost:5433/openccb_cms
|
DATABASE_URL=postgresql://user:password@localhost:5433/openccb_cms
|
||||||
|
|
||||||
# JWT Secret
|
# JWT Secret (generate with ./generate_jwt_secret.sh)
|
||||||
JWT_SECRET=supersecret
|
JWT_SECRET=supersecret
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
@@ -37,8 +37,8 @@ EXTERNAL_TABLE_GRADES=notas
|
|||||||
EXTERNAL_ID_TIPO_NOTA=1
|
EXTERNAL_ID_TIPO_NOTA=1
|
||||||
|
|
||||||
# Branding Defaults
|
# Branding Defaults
|
||||||
DEFAULT_ORG_NAME="OpenCCB"
|
DEFAULT_ORG_NAME="Norteamericano"
|
||||||
DEFAULT_PLATFORM_NAME="OpenCCB Learning"
|
DEFAULT_PLATFORM_NAME="Norteamericano Learning"
|
||||||
DEFAULT_LOGO_URL=""
|
DEFAULT_LOGO_URL=""
|
||||||
DEFAULT_FAVICON_URL=""
|
DEFAULT_FAVICON_URL=""
|
||||||
DEFAULT_PRIMARY_COLOR="#3B82F6"
|
DEFAULT_PRIMARY_COLOR="#3B82F6"
|
||||||
|
|||||||
@@ -278,6 +278,14 @@ NEXT_PUBLIC_CMS_API_URL=http://localhost:3001
|
|||||||
NEXT_PUBLIC_LMS_API_URL=http://localhost:3002
|
NEXT_PUBLIC_LMS_API_URL=http://localhost:3002
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Default Credentials
|
||||||
|
|
||||||
|
After running `./install.sh`, the default admin user is:
|
||||||
|
- **Email**: `admin@norteamericano.cl`
|
||||||
|
- **Password**: `Admin123!`
|
||||||
|
|
||||||
|
You can customize these during installation.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
### E2E Tests (Playwright)
|
### E2E Tests (Playwright)
|
||||||
@@ -340,6 +348,37 @@ cargo test -p common
|
|||||||
|
|
||||||
## Common Issues
|
## Common Issues
|
||||||
|
|
||||||
|
### CORS Errors (Login/Registro)
|
||||||
|
|
||||||
|
Si ves errores de CORS al intentar loguearte:
|
||||||
|
|
||||||
|
```
|
||||||
|
Access to fetch at 'http://localhost:3001/auth/login' from origin 'http://localhost:3000'
|
||||||
|
has been blocked by CORS policy
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solución**: Asegúrate de que el rate limiter NO esté aplicado a las rutas de autenticación.
|
||||||
|
En `services/cms-service/src/main.rs`, el `GovernorLayer` debe estar solo en `protected_routes`,
|
||||||
|
no en `public_routes`.
|
||||||
|
|
||||||
|
### Rate Limiter Bloqueando Peticiones
|
||||||
|
|
||||||
|
**Estado actual**: El rate limiter (`tower_governor`) está **deshabilitado** debido a problemas de compatibilidad con el middleware de autenticación.
|
||||||
|
|
||||||
|
Si quieres habilitarlo en producción:
|
||||||
|
|
||||||
|
1. Agrega `GovernorLayer` solo a rutas protegidas usando `.route_layer()`
|
||||||
|
2. Configúralo después del middleware de autenticación
|
||||||
|
3. Ajusta los límites (por defecto: 10 req/s, burst 50)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
.protected_routes
|
||||||
|
.route_layer(middleware::from_fn(org_extractor_middleware))
|
||||||
|
.route_layer(GovernorLayer { config: governor_conf })
|
||||||
|
```
|
||||||
|
|
||||||
|
**Advertencia**: Si el rate limiter está mal configurado, las peticiones a `/courses`, `/auth/login`, etc. pueden fallar con error 500 sin logs.
|
||||||
|
|
||||||
### Port Conflicts
|
### Port Conflicts
|
||||||
|
|
||||||
If port 5432 is occupied, the setup uses 5433:
|
If port 5432 is occupied, the setup uses 5433:
|
||||||
|
|||||||
+50
-19
@@ -241,13 +241,13 @@ if [ "$ADMIN_EXISTS" != "t" ]; then
|
|||||||
echo "👤 Configurar Administrador Inicial"
|
echo "👤 Configurar Administrador Inicial"
|
||||||
read -p "Nombre Completo [Administrador del Sistema]: " ADMIN_NAME
|
read -p "Nombre Completo [Administrador del Sistema]: " ADMIN_NAME
|
||||||
ADMIN_NAME=${ADMIN_NAME:-Administrador del Sistema}
|
ADMIN_NAME=${ADMIN_NAME:-Administrador del Sistema}
|
||||||
read -p "Email del Administrador [admin@example.com]: " ADMIN_EMAIL
|
read -p "Email del Administrador [admin@norteamericano.cl]: " ADMIN_EMAIL
|
||||||
ADMIN_EMAIL=${ADMIN_EMAIL:-admin@example.com}
|
ADMIN_EMAIL=${ADMIN_EMAIL:-admin@norteamericano.cl}
|
||||||
read -s -p "Contraseña del Administrador [password123]: " ADMIN_PASS
|
read -s -p "Contraseña del Administrador [Admin123!]: " ADMIN_PASS
|
||||||
ADMIN_PASS=${ADMIN_PASS:-password123}
|
ADMIN_PASS=${ADMIN_PASS:-Admin123!}
|
||||||
echo ""
|
echo ""
|
||||||
read -p "Nombre de la Organización [OpenCCB]: " ORG_NAME
|
read -p "Nombre de la Organización [Norteamericano]: " ORG_NAME
|
||||||
ORG_NAME=${ORG_NAME:-OpenCCB}
|
ORG_NAME=${ORG_NAME:-Norteamericano}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Selective Build/Rebuild
|
# Selective Build/Rebuild
|
||||||
@@ -269,22 +269,12 @@ fi
|
|||||||
if [ "$ADMIN_EXISTS" != "t" ]; then
|
if [ "$ADMIN_EXISTS" != "t" ]; then
|
||||||
echo "⏳ Esperando a que el API CMS esté listo..."
|
echo "⏳ Esperando a que el API CMS esté listo..."
|
||||||
API_URL="http://localhost:3001"
|
API_URL="http://localhost:3001"
|
||||||
PAYLOAD=$(cat <<EOF
|
|
||||||
{
|
|
||||||
"email": "$ADMIN_EMAIL",
|
|
||||||
"password": "$ADMIN_PASS",
|
|
||||||
"full_name": "$ADMIN_NAME",
|
|
||||||
"organization_name": "$ORG_NAME",
|
|
||||||
"role": "admin"
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
# Wait until the API actually responds (not just the port being open)
|
# Wait until the API actually responds (not just the port being open)
|
||||||
MAX_RETRIES=30
|
MAX_RETRIES=30
|
||||||
count=0
|
count=0
|
||||||
echo -n "Esperando API"
|
echo -n "Esperando API"
|
||||||
until curl -s -o /dev/null "$API_URL/auth/login" -H "Content-Type: application/json" -d '{}' 2>/dev/null; do
|
until curl -s -o /dev/null "$API_URL/health" 2>/dev/null; do
|
||||||
echo -n "."
|
echo -n "."
|
||||||
sleep 2
|
sleep 2
|
||||||
count=$((count+1))
|
count=$((count+1))
|
||||||
@@ -296,15 +286,51 @@ EOF
|
|||||||
done
|
done
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# Create admin user directly in database using pgcrypto
|
||||||
|
echo "🔐 Creando administrador en la base de datos..."
|
||||||
|
docker exec openccb-db-1 psql -U user -d openccb_cms -c "
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
|
SELECT * FROM fn_register_user(
|
||||||
|
'$ADMIN_EMAIL',
|
||||||
|
crypt('$ADMIN_PASS', gen_salt('bf', 12)),
|
||||||
|
'$ADMIN_NAME',
|
||||||
|
'admin',
|
||||||
|
'$ORG_NAME'
|
||||||
|
);
|
||||||
|
" 2>/dev/null
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "✅ ¡Éxito! Administrador creado."
|
||||||
|
API_KEY=$(docker exec openccb-db-1 psql -U user -d openccb_cms -t -c "SELECT api_key FROM organizations LIMIT 1;" | xargs 2>/dev/null)
|
||||||
|
echo "🔑 API Key Inicial: $API_KEY"
|
||||||
|
echo ""
|
||||||
|
echo "📋 Credenciales de acceso:"
|
||||||
|
echo " Email: $ADMIN_EMAIL"
|
||||||
|
echo " Contraseña: $ADMIN_PASS"
|
||||||
|
else
|
||||||
|
echo "⚠️ Fallo al crear el administrador. Intentando con método alternativo..."
|
||||||
|
|
||||||
|
# Fallback: Try API endpoint
|
||||||
|
PAYLOAD=$(cat <<EOF
|
||||||
|
{
|
||||||
|
"email": "$ADMIN_EMAIL",
|
||||||
|
"password": "$ADMIN_PASS",
|
||||||
|
"full_name": "$ADMIN_NAME",
|
||||||
|
"organization_name": "$ORG_NAME",
|
||||||
|
"role": "admin"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
)
|
||||||
RESPONSE=$(curl -s -X POST "$API_URL/auth/register" -H "Content-Type: application/json" -d "$PAYLOAD")
|
RESPONSE=$(curl -s -X POST "$API_URL/auth/register" -H "Content-Type: application/json" -d "$PAYLOAD")
|
||||||
|
|
||||||
if echo "$RESPONSE" | grep -q "token"; then
|
if echo "$RESPONSE" | grep -q "token"; then
|
||||||
echo "✅ ¡Éxito! Administrador creado."
|
echo "✅ ¡Éxito! Administrador creado vía API."
|
||||||
API_KEY=$(docker exec openccb-db-1 psql -U user -d openccb_cms -t -c "SELECT api_key FROM organizations LIMIT 1;" | xargs)
|
API_KEY=$(docker exec openccb-db-1 psql -U user -d openccb_cms -t -c "SELECT api_key FROM organizations LIMIT 1;" | xargs 2>/dev/null)
|
||||||
echo "🔑 API Key Inicial: $API_KEY"
|
echo "🔑 API Key Inicial: $API_KEY"
|
||||||
else
|
else
|
||||||
echo "⚠️ Fallo al crear el administrador. Respuesta: $RESPONSE"
|
echo "⚠️ Fallo al crear el administrador. Respuesta: $RESPONSE"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "✅ El administrador ya existe. Saltando registro."
|
echo "✅ El administrador ya existe. Saltando registro."
|
||||||
fi
|
fi
|
||||||
@@ -316,3 +342,8 @@ echo "===================================================="
|
|||||||
echo "Studio (Admin/CMS): http://localhost:3000"
|
echo "Studio (Admin/CMS): http://localhost:3000"
|
||||||
echo "Experience (LMS): http://localhost:3003"
|
echo "Experience (LMS): http://localhost:3003"
|
||||||
echo "===================================================="
|
echo "===================================================="
|
||||||
|
echo ""
|
||||||
|
echo "📋 Notas:"
|
||||||
|
echo " - Rate limiter: DESHABILITADO (problemas de compatibilidad)"
|
||||||
|
echo " - Para producción, configura tower_governor en services/cms-service/src/main.rs"
|
||||||
|
echo "===================================================="
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ use dotenvy::dotenv;
|
|||||||
use sqlx::postgres::PgPoolOptions;
|
use sqlx::postgres::PgPoolOptions;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tower_governor::governor::GovernorConfigBuilder;
|
|
||||||
use tower_governor::GovernorLayer;
|
|
||||||
use tower_http::cors::{Any, CorsLayer};
|
use tower_http::cors::{Any, CorsLayer};
|
||||||
use tower_http::set_header::SetResponseHeaderLayer;
|
use tower_http::set_header::SetResponseHeaderLayer;
|
||||||
use tower_http::trace::TraceLayer;
|
use tower_http::trace::TraceLayer;
|
||||||
@@ -99,14 +96,8 @@ async fn main() {
|
|||||||
.allow_methods(Any)
|
.allow_methods(Any)
|
||||||
.allow_headers(Any);
|
.allow_headers(Any);
|
||||||
|
|
||||||
// Rate limiting configuration
|
// Rate limiting: Deshabilitado temporalmente por problemas de compatibilidad con tower-governor
|
||||||
let governor_conf = Arc::new(
|
// Para habilitar en producción, configurar con GovernorLayer y ajustar los límites apropiadamente
|
||||||
GovernorConfigBuilder::default()
|
|
||||||
.per_second(10)
|
|
||||||
.burst_size(50)
|
|
||||||
.finish()
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Rutas protegidas que requieren autenticación y contexto de organización
|
// Rutas protegidas que requieren autenticación y contexto de organización
|
||||||
let protected_routes = Router::new()
|
let protected_routes = Router::new()
|
||||||
|
|||||||
Reference in New Issue
Block a user