Fix db, keyclaok .env.example e docker compose

This commit is contained in:
Lorenzo Sanesi
2026-07-25 12:10:54 +02:00
parent 5b7c82d359
commit 7cd0a1ff1b
7 changed files with 198 additions and 34 deletions
+28 -13
View File
@@ -2,26 +2,41 @@
POSTGRES_USER=postgres POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres POSTGRES_PASSWORD=postgres
# Database di scouthub-attivita-be. Sulla stessa istanza vivono anche
# scouthub_home / scouthub_magazzino / scouthub_eventi (creati da db-init/
# al primo avvio), usati rispettivamente da home-backend/magazzino-backend/
# eventi-backend con le stesse credenziali POSTGRES_USER/POSTGRES_PASSWORD.
POSTGRES_DB=scouthub POSTGRES_DB=scouthub
POSTGRES_PORT=5432 POSTGRES_PORT=5432
ATTIVITA_BACKEND_PORT=8080
# Deve restare 8080: il frontend Angular ha l'URL dell'API hardcoded
# in src/environments/environment.ts (apiUrl: 'http://localhost:8080')
ATTIVITA_FRONTEND_PORT=4200
KEYCLOAK_DB_PASSWORD=keycloak_change_me KEYCLOAK_DB_PASSWORD=keycloak_change_me
KEYCLOAK_ADMIN_PASSWORD=admin_change_me KEYCLOAK_ADMIN_PASSWORD=admin_change_me
# Se in locale esegui anche scouthub-home-be fuori da Docker (npm run dev), # Keycloak ha una porta tutta sua, separata dai range frontend/backend qui sotto.
# il suo PORT di default (8082) è già scelto per non collidere con questo. KEYCLOAK_PORT=6999
KEYCLOAK_PORT=8081
# Deve restare 8082: scouthub-home-fe ha l'URL dell'org-service hardcoded # Porte frontend, a partire da 7000, in ordine home/attivita/magazzino/calendario.
# in src/environments/environment.ts (orgServiceApiBaseUrl: 'http://localhost:8082') # Nessuna e' hardcoded nel codice: i frontend Angular ricevono gli URL (Keycloak,
HOME_BACKEND_PORT=8082 # API, cross-frontend) come build ARG Docker valorizzati da queste variabili
HOME_FRONTEND_PORT=4201 # (vedi build.args dei rispettivi servizi in docker-compose.yml).
HOME_FRONTEND_PORT=7000
ATTIVITA_FRONTEND_PORT=7001
MAGAZZINO_FRONTEND_PORT=7002
EVENTI_FRONTEND_PORT=7003
# Porte backend, a partire da 8000, stesso ordine home/attivita/magazzino/calendario.
HOME_BACKEND_PORT=8000
ATTIVITA_BACKEND_PORT=8001
MAGAZZINO_BACKEND_PORT=8002
EVENTI_BACKEND_PORT=8003
# Deve coincidere con il secret del client "scouthub-home-be" in keycloak/realm-export.json # Deve coincidere con il secret del client "scouthub-home-be" in keycloak/realm-export.json
KEYCLOAK_ORG_SERVICE_CLIENT_SECRET=change_me KEYCLOAK_ORG_SERVICE_CLIENT_SECRET=change_me
# Deve coincidere con il secret del client "scouthub-magazzino-be" in keycloak/realm-export.json
KEYCLOAK_MAGAZZINO_CLIENT_SECRET=change_me
# Deve coincidere con il secret del client "scouthub-eventi-be" in keycloak/realm-export.json
# (secret condiviso anche con scouthub-attivita-be e scouthub-magazzino-be, che lo usano per
# chiamare POST /eventi/:id/risorse su scouthub-eventi-be)
KEYCLOAK_EVENTI_CLIENT_SECRET=change_me
+5
View File
@@ -0,0 +1,5 @@
-- scouthub-eventi-be usa un database separato sulla stessa istanza Postgres di "db".
-- Eseguito solo al primo avvio del container (volume dati vuoto).
SELECT 'CREATE DATABASE scouthub_eventi'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'scouthub_eventi')
\gexec
+5
View File
@@ -0,0 +1,5 @@
-- scouthub-magazzino-be usa un database separato sulla stessa istanza Postgres di "db".
-- Eseguito solo al primo avvio del container (volume dati vuoto).
SELECT 'CREATE DATABASE scouthub_magazzino'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'scouthub_magazzino')
\gexec
+72 -1
View File
@@ -10,7 +10,8 @@ services:
- "${POSTGRES_PORT}:5432" - "${POSTGRES_PORT}:5432"
volumes: volumes:
- scouthub_db_data:/var/lib/postgresql/data - scouthub_db_data:/var/lib/postgresql/data
# Crea anche il DB scouthub_home usato da scouthub-home-be (solo al primo init). # Crea anche i DB scouthub_home / scouthub_magazzino / scouthub_eventi
# usati dagli altri backend, sulla stessa istanza (solo al primo init).
- ./db-init:/docker-entrypoint-initdb.d:ro - ./db-init:/docker-entrypoint-initdb.d:ro
healthcheck: healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
@@ -39,6 +40,9 @@ services:
attivita-frontend: attivita-frontend:
build: build:
context: ./scouthub-attivita-fe context: ./scouthub-attivita-fe
args:
API_URL: http://localhost:${ATTIVITA_BACKEND_PORT}
KEYCLOAK_BASE_URL: http://localhost:${KEYCLOAK_PORT}
restart: unless-stopped restart: unless-stopped
ports: ports:
- "${ATTIVITA_FRONTEND_PORT}:80" - "${ATTIVITA_FRONTEND_PORT}:80"
@@ -70,12 +74,79 @@ services:
home-frontend: home-frontend:
build: build:
context: ./scouthub-home-fe context: ./scouthub-home-fe
args:
KEYCLOAK_BASE_URL: http://localhost:${KEYCLOAK_PORT}
ORG_SERVICE_API_BASE_URL: http://localhost:${HOME_BACKEND_PORT}
ATTIVITA_FE_BASE_URL: http://localhost:${ATTIVITA_FRONTEND_PORT}
restart: unless-stopped restart: unless-stopped
ports: ports:
- "${HOME_FRONTEND_PORT}:80" - "${HOME_FRONTEND_PORT}:80"
depends_on: depends_on:
- home-backend - home-backend
magazzino-backend:
build:
context: ./scouthub-magazzino-be
restart: unless-stopped
environment:
PORT: ${MAGAZZINO_BACKEND_PORT}
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/scouthub_magazzino?schema=public
KEYCLOAK_BASE_URL: http://keycloak:8080
KEYCLOAK_REALM: scouthub
KEYCLOAK_MAGAZZINO_CLIENT_ID: scouthub-magazzino-be
KEYCLOAK_MAGAZZINO_CLIENT_SECRET: ${KEYCLOAK_MAGAZZINO_CLIENT_SECRET}
ports:
- "${MAGAZZINO_BACKEND_PORT}:${MAGAZZINO_BACKEND_PORT}"
depends_on:
db:
condition: service_healthy
keycloak:
condition: service_started
magazzino-frontend:
build:
context: ./scouthub-magazzino-fe
args:
KEYCLOAK_BASE_URL: http://localhost:${KEYCLOAK_PORT}
MAGAZZINO_API_BASE_URL: http://localhost:${MAGAZZINO_BACKEND_PORT}
restart: unless-stopped
ports:
- "${MAGAZZINO_FRONTEND_PORT}:80"
depends_on:
- magazzino-backend
eventi-backend:
build:
context: ./scouthub-eventi-be
restart: unless-stopped
environment:
PORT: ${EVENTI_BACKEND_PORT}
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/scouthub_eventi?schema=public
KEYCLOAK_BASE_URL: http://keycloak:8080
KEYCLOAK_REALM: scouthub
KEYCLOAK_EVENTI_CLIENT_ID: scouthub-eventi-be
KEYCLOAK_EVENTI_CLIENT_SECRET: ${KEYCLOAK_EVENTI_CLIENT_SECRET}
KEYCLOAK_AUTHORIZED_SERVICE_CLIENTS: scouthub-eventi-be
ports:
- "${EVENTI_BACKEND_PORT}:${EVENTI_BACKEND_PORT}"
depends_on:
db:
condition: service_healthy
keycloak:
condition: service_started
eventi-frontend:
build:
context: ./scouthub-eventi-fe
args:
KEYCLOAK_BASE_URL: http://localhost:${KEYCLOAK_PORT}
EVENTI_API_BASE_URL: http://localhost:${EVENTI_BACKEND_PORT}
restart: unless-stopped
ports:
- "${EVENTI_FRONTEND_PORT}:80"
depends_on:
- eventi-backend
keycloak-db: keycloak-db:
image: postgres:16-alpine image: postgres:16-alpine
restart: unless-stopped restart: unless-stopped
+14 -9
View File
@@ -4,21 +4,26 @@ Realm `scouthub` con feature Organizations abilitata, importato automaticamente
all'avvio di Keycloak (`--import-realm` nel `docker-compose.yml` alla radice). all'avvio di Keycloak (`--import-realm` nel `docker-compose.yml` alla radice).
Basato su `keycloak/realm.json` (bozza di riferimento), con l'aggiunta del Basato su `keycloak/realm.json` (bozza di riferimento), con l'aggiunta del
ruolo `admin-centrale` richiesto da `POST /gruppi` in `scouthub-home-be` ruolo `admin` richiesto da `POST /gruppi` e `GET /gruppi` in
(placeholder temporaneo, vedi il TODO in `src/routes/gruppi.routes.ts`). `scouthub-home-be`: creazione/elenco diretti restano riservati ad `admin`,
mentre un utente normale passa dal flusso self-service di richiesta
creazione gruppo (`POST /richieste-creazione-gruppo`), che alla review
positiva invoca la stessa `createGruppo()` internamente.
Contiene già: Contiene già:
- i realm role usati dal backend: `admin-centrale`, `capo-gruppo`, - i realm role usati dal backend, in gerarchia composite (`admin` include
`capo-unita`, `censito`, più il placeholder `manage-organizations` `capo-gruppo` include `capo-unita` include `capo` include `censito`; `admin`
include anche `moderatore`): `admin`, `capo-gruppo`, `capo-unita`, `capo`,
`censito`, `moderatore`, più il placeholder `manage-organizations`
- il client scope `organization` (aggiunge id/attributi della Organization - il client scope `organization` (aggiunge id/attributi della Organization
nei token OIDC) nei token OIDC)
- il client confidential `scouthub-home-be` (service account abilitato, - il client confidential `scouthub-home-be` (service account abilitato,
usato dal backend per il flow client-credentials verso le Admin REST API — usato dal backend per il flow client-credentials verso le Admin REST API —
il suo `clientId`/`secret` devono corrispondere a il suo `clientId`/`secret` devono corrispondere a
`KEYCLOAK_ORG_SERVICE_CLIENT_ID`/`_SECRET` in `scouthub-home-be/.env.example`) `KEYCLOAK_ORG_SERVICE_CLIENT_ID`/`_SECRET` in `scouthub-home-be/.env.example`)
- il client pubblico `scouthub-frontend` (login utente, redirect su - il client pubblico `scouthub-frontend` (login utente, condiviso da tutti i
`http://localhost:4200/*`) frontend Angular del progetto, redirect su `http://localhost:7000-7003/*`)
Passi manuali ancora da fare dopo l'import (non automatizzabili in un realm Passi manuali ancora da fare dopo l'import (non automatizzabili in un realm
export senza conoscere gli id generati a runtime): export senza conoscere gli id generati a runtime):
@@ -49,15 +54,15 @@ I passaggi da fare sono:
- manage-users - manage-users
- view-users - view-users
9. Clicca Assign. 9. Clicca Assign.
10. Dopo fatto questo bisogna fare un user admin-centrale 10. Dopo fatto questo bisogna fare un user admin
I passaggi da fare per admin-centrale: I passaggi da fare per admin:
1. Apri http://localhost:8081/admin, login admin/admin, cambia realm in scouthub. 1. Apri http://localhost:8081/admin, login admin/admin, cambia realm in scouthub.
2. Menu laterale → Users → clicca su movioletto@yahoo.it. 2. Menu laterale → Users → clicca su movioletto@yahoo.it.
3. Vai sul tab "Role mapping". 3. Vai sul tab "Role mapping".
4. Clicca "Assign role". 4. Clicca "Assign role".
5. Assicurati che il filtro sia su "Filter by realm roles" (dovrebbe esserlo di default per gli utenti normali). 5. Assicurati che il filtro sia su "Filter by realm roles" (dovrebbe esserlo di default per gli utenti normali).
6. Cerca e seleziona admin-centrale. 6. Cerca e seleziona admin.
7. Clicca Assign. 7. Clicca Assign.
⚠️ Il secret del client `scouthub-home-be` (`CAMBIA-QUESTO-SECRET-IN-UN-VAULT`) ⚠️ Il secret del client `scouthub-home-be` (`CAMBIA-QUESTO-SECRET-IN-UN-VAULT`)
+71 -8
View File
@@ -11,11 +11,33 @@
"roles": { "roles": {
"realm": [ "realm": [
{ "name": "admin-centrale", "description": "Placeholder temporaneo: crea nuovi gruppi scout (Organization). Vedi TODO in src/routes/gruppi.routes.ts" }, {
{ "name": "capo-gruppo", "description": "Gestisce il proprio gruppo scout (Organization): membri, inviti, ruoli" }, "name": "admin",
{ "name": "capo-unita", "description": "Gestisce attivita' e materiali della propria branca" }, "description": "Puo' fare tutto su tutte le organizzazioni. Ex admin-centrale. Unico ruolo abilitato a POST/GET /gruppi diretti; gli utenti normali passano dal flusso self-service di richiesta creazione gruppo",
"composite": true,
"composites": { "realm": ["capo-gruppo", "moderatore"] }
},
{
"name": "capo-gruppo",
"description": "Gestisce il proprio gruppo scout (Organization): membri, inviti, ruoli",
"composite": true,
"composites": { "realm": ["capo-unita"] }
},
{
"name": "capo-unita",
"description": "Gestisce attivita' e materiali della propria unita' (branca)",
"composite": true,
"composites": { "realm": ["capo"] }
},
{
"name": "capo",
"description": "Vede e modifica parzialmente le cose della propria unita' (branca). Permessi identici a capo-unita per ora, da differenziare in futuro",
"composite": true,
"composites": { "realm": ["censito"] }
},
{ "name": "censito", "description": "Accesso in sola consultazione" }, { "name": "censito", "description": "Accesso in sola consultazione" },
{ "name": "manage-organizations", "description": "Placeholder locale: il ruolo reale e' il client role manage-organizations su realm-management" } { "name": "manage-organizations", "description": "Placeholder locale: il ruolo reale e' il client role manage-organizations su realm-management" },
{ "name": "moderatore", "description": "Puo' approvare/rifiutare proposte da moderare nei vari servizi (es. catalogo materiali del magazzino, in futuro validazione attivita' prima della pubblicazione). Ex admin-catalogo" }
] ]
}, },
@@ -44,13 +66,22 @@
"standardFlowEnabled": true, "standardFlowEnabled": true,
"directAccessGrantsEnabled": false, "directAccessGrantsEnabled": false,
"redirectUris": [ "redirectUris": [
"http://localhost:4200/*", "http://localhost:7000/*",
"http://localhost:4201/*" "http://localhost:7001/*",
"http://localhost:7002/*",
"http://localhost:7002/silent-check-sso.html",
"http://localhost:7003/*",
"http://localhost:7003/silent-check-sso.html"
], ],
"webOrigins": [ "webOrigins": [
"http://localhost:4200", "http://localhost:7000",
"http://localhost:4201" "http://localhost:7001",
"http://localhost:7002",
"http://localhost:7003"
], ],
"attributes": {
"post.logout.redirect.uris": "http://localhost:7000/*##http://localhost:7001/*##http://localhost:7002/*##http://localhost:7003/*"
},
"defaultClientScopes": [ "defaultClientScopes": [
"openid", "openid",
"basic", "basic",
@@ -59,6 +90,38 @@
"email", "email",
"organization" "organization"
] ]
},
{
"clientId": "scouthub-magazzino-be",
"name": "Servizio di gestione catalogo magazzino (magazzino-be)",
"enabled": true,
"protocol": "openid-connect",
"publicClient": false,
"standardFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": true,
"clientAuthenticatorType": "client-secret",
"secret": "CAMBIA-QUESTO-SECRET-IN-UN-VAULT",
"redirectUris": [],
"attributes": {
"note": "Usato solo server-to-server dal backend scouthub-magazzino-be verso le Admin REST API. Non esporre mai il secret al frontend."
}
},
{
"clientId": "scouthub-eventi-be",
"name": "Servizio di gestione eventi (eventi-be)",
"enabled": true,
"protocol": "openid-connect",
"publicClient": false,
"standardFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": true,
"clientAuthenticatorType": "client-secret",
"secret": "CAMBIA-QUESTO-SECRET-IN-UN-VAULT",
"redirectUris": [],
"attributes": {
"note": "Usato solo server-to-server dal backend scouthub-eventi-be verso le Admin REST API. Il secret va condiviso anche con attivita-be e magazzino-be, che lo usano come client credentials per chiamare POST /eventi/:id/risorse su scouthub-eventi-be. Non esporre mai il secret al frontend."
}
} }
] ]
} }
+3 -3
View File
@@ -1,11 +1,11 @@
PORT=8080 PORT=8001
CORS_ORIGIN=http://localhost:4200 CORS_ORIGIN=http://localhost:7001
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/scouthub?schema=public DATABASE_URL=postgresql://postgres:postgres@localhost:5432/scouthub?schema=public
# Keycloak (realm condiviso con scouthub-home-be/-fe, vedi keycloak/realm-export.json # Keycloak (realm condiviso con scouthub-home-be/-fe, vedi keycloak/realm-export.json
# alla radice del monorepo): usato solo per verificare i token, nessun client # alla radice del monorepo): usato solo per verificare i token, nessun client
# id/secret necessario qui. # id/secret necessario qui.
KEYCLOAK_BASE_URL=http://localhost:8081 KEYCLOAK_BASE_URL=http://localhost:6999
KEYCLOAK_REALM=scouthub KEYCLOAK_REALM=scouthub
# Database dedicato ai test automatici (Jest): tenuto separato dal DB di sviluppo # Database dedicato ai test automatici (Jest): tenuto separato dal DB di sviluppo