feat: normaliser les URL production par entité
All checks were successful
Validation Dashboard / Tests backend et build frontend (push) Successful in 58s
All checks were successful
Validation Dashboard / Tests backend et build frontend (push) Successful in 58s
This commit is contained in:
@@ -32,8 +32,8 @@ Le dashboard et le portail applicatif utilisent exclusivement le manifeste plac
|
||||
"activeConfigurationPath": "/api/ai/active-configuration"
|
||||
},
|
||||
"urls": {
|
||||
"recette": "https://contacts.recette.santinova-soft.org",
|
||||
"prod": "https://contacts.santinova-soft.org"
|
||||
"recette": "https://contacts-itinova.recette.santinova-soft.org",
|
||||
"prod": "https://contacts-itinova.santinova-soft.org"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
31
Dockerfile
31
Dockerfile
@@ -1,43 +1,34 @@
|
||||
# Stage 1: Build frontend
|
||||
# Stage 1: Build frontend from Git-tracked sources
|
||||
FROM node:20-alpine AS frontend-builder
|
||||
|
||||
WORKDIR /app/frontend
|
||||
|
||||
# Copy frontend package files
|
||||
COPY frontend/package.json frontend/pnpm-lock.yaml* ./
|
||||
# Copy frontend package files and source from the versioned src tree.
|
||||
COPY src/frontend/package.json src/frontend/pnpm-lock.yaml* ./
|
||||
RUN npm install
|
||||
|
||||
# Copy frontend source
|
||||
COPY frontend/ ./
|
||||
|
||||
# Build frontend
|
||||
COPY src/frontend/ ./
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Production
|
||||
# Stage 2: Production runtime
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install docker CLI for docker compose commands
|
||||
# Docker controls are required by the dashboard runtime.
|
||||
RUN apk add --no-cache docker-cli docker-cli-compose git curl unzip bash openssh-client
|
||||
|
||||
# Configure git global identity to avoid "Author identity unknown" errors
|
||||
RUN git config --global user.email "admin@santinova-soft.org" && \
|
||||
git config --global user.name "Manus Dashboard"
|
||||
|
||||
# Copy backend
|
||||
COPY backend/package.json ./backend/
|
||||
# Copy backend dependencies and source from the versioned src tree.
|
||||
COPY src/backend/package.json src/backend/package-lock.json ./backend/
|
||||
WORKDIR /app/backend
|
||||
RUN npm install --production
|
||||
RUN npm ci --omit=dev
|
||||
COPY src/backend/ ./
|
||||
|
||||
COPY backend/ ./
|
||||
|
||||
# Copy built frontend
|
||||
# Copy the frontend built from the same Git revision.
|
||||
WORKDIR /app
|
||||
COPY --from=frontend-builder /app/frontend/dist ./frontend/dist
|
||||
|
||||
WORKDIR /app/backend
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
CMD ["node", "src/index.js"]
|
||||
|
||||
@@ -28,5 +28,5 @@ docker compose build --no-cache && docker compose up -d
|
||||
|
||||
## Accès
|
||||
|
||||
- URL : https://dashboard.santinova-soft.org
|
||||
- URL : https://dashboard-santinova.santinova-soft.org
|
||||
- Login : adminItinova / Itinova69!
|
||||
|
||||
4
app.json
4
app.json
@@ -3,8 +3,8 @@
|
||||
"name": "Dashboard Production",
|
||||
"category": "INFRA",
|
||||
"urls": {
|
||||
"recette": "https://dashboard.recette.santinova-soft.org",
|
||||
"prod": "https://dashboard.santinova-soft.org"
|
||||
"recette": "https://dashboard-santinova.recette.santinova-soft.org",
|
||||
"prod": "https://dashboard-santinova.santinova-soft.org"
|
||||
},
|
||||
"containerName": "manus-dashboard",
|
||||
"image": "images/dashboard.png",
|
||||
|
||||
@@ -36,7 +36,7 @@ services:
|
||||
- web
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.manus-dashboard.rule=Host(`dashboard.santinova-soft.org`)"
|
||||
- "traefik.http.routers.manus-dashboard.rule=Host(`dashboard.santinova-soft.org`) || Host(`dashboard-santinova.santinova-soft.org`)"
|
||||
- "traefik.http.routers.manus-dashboard.entrypoints=websecure"
|
||||
- "traefik.http.routers.manus-dashboard.tls=true"
|
||||
- "traefik.http.routers.manus-dashboard.tls.certresolver=letsencrypt"
|
||||
|
||||
@@ -4,7 +4,7 @@ set -Eeuo pipefail
|
||||
readonly DASHBOARD_APP_DIR="${DASHBOARD_APP_DIR:-/opt/manus-deploy/apps/manus-dashboard}"
|
||||
readonly DASHBOARD_ENV_FILE="${DASHBOARD_ENV_FILE:-${DASHBOARD_APP_DIR}/.env}"
|
||||
readonly REFERENTIEL_CONTAINER="${REFERENTIEL_CONTAINER:-referentiel-ia}"
|
||||
readonly REFERENTIEL_URL="${IA_REFERENTIEL_URL:-https://referentiel-ia.recette.santinova-soft.org}"
|
||||
readonly REFERENTIEL_URL="${IA_REFERENTIEL_URL:-https://referentiel-ia-santinova.recette.santinova-soft.org}"
|
||||
|
||||
backup="$(mktemp /tmp/manus-dashboard-env-backup.XXXXXX)"
|
||||
temporary="$(mktemp /tmp/manus-dashboard-env-next.XXXXXX)"
|
||||
|
||||
@@ -12,7 +12,7 @@ from pathlib import Path
|
||||
|
||||
GITEA_URL = os.environ.get("GITEA_URL", "https://git.recette.santinova-soft.org").rstrip("/")
|
||||
GITEA_USER = os.environ.get("GITEA_USERNAME", "manus-admin")
|
||||
DASHBOARD_URL = os.environ.get("DASHBOARD_URL", "https://dashboard.recette.santinova-soft.org").rstrip("/")
|
||||
DASHBOARD_URL = os.environ.get("DASHBOARD_URL", "https://dashboard-santinova.recette.santinova-soft.org").rstrip("/")
|
||||
DASHBOARD_APP_DIR = Path(os.environ.get("DASHBOARD_APP_DIR", "/opt/manus-deploy/apps/manus-dashboard"))
|
||||
ENV_FILE = DASHBOARD_APP_DIR / ".env"
|
||||
WEBHOOK_ENDPOINT = f"{DASHBOARD_URL}/api/webhook/gitea"
|
||||
|
||||
@@ -28,5 +28,5 @@ docker compose build --no-cache && docker compose up -d
|
||||
|
||||
## Accès
|
||||
|
||||
- URL : https://dashboard.santinova-soft.org
|
||||
- URL : https://dashboard-santinova.santinova-soft.org
|
||||
- Login : adminItinova / Itinova69!
|
||||
|
||||
@@ -31,7 +31,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
dsiAlerts: {
|
||||
url: process.env.IA_REFERENTIEL_URL || 'https://referentiel-ia.recette.santinova-soft.org',
|
||||
url: process.env.IA_REFERENTIEL_URL || 'https://referentiel-ia-santinova.recette.santinova-soft.org',
|
||||
token: process.env.IA_REFERENTIEL_TOKEN || null,
|
||||
email: process.env.DSI_ALERT_EMAIL || null,
|
||||
emailQueue: process.env.CI_ALERT_EMAIL_QUEUE || '/opt/manus-deploy/secrets/ci-alerts/outbox',
|
||||
|
||||
@@ -25,9 +25,9 @@ const { getActiveAiConfiguration } = require('../src/healthcheck');
|
||||
|
||||
const result = await getActiveAiConfiguration({
|
||||
ai: { activeConfigurationPath: '/api/ai/active-configuration' },
|
||||
}, 'https://contacts.recette.santinova-soft.org');
|
||||
}, 'https://contacts-itinova.recette.santinova-soft.org');
|
||||
|
||||
assert.equal(requestedUrl, 'https://contacts.recette.santinova-soft.org/api/ai/active-configuration');
|
||||
assert.equal(requestedUrl, 'https://contacts-itinova.recette.santinova-soft.org/api/ai/active-configuration');
|
||||
assert.deepEqual(result, {
|
||||
active: true,
|
||||
runtimeStatus: 'active',
|
||||
|
||||
@@ -29,8 +29,8 @@ try {
|
||||
activeConfigurationPath: '/api/ai/active-configuration',
|
||||
},
|
||||
urls: {
|
||||
recette: 'https://contacts.recette.santinova-soft.org',
|
||||
prod: 'https://contacts.santinova-soft.org',
|
||||
recette: 'https://contacts-itinova.recette.santinova-soft.org',
|
||||
prod: 'https://contacts-itinova.santinova-soft.org',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -39,8 +39,8 @@ try {
|
||||
name: 'Dashboard',
|
||||
category: 'INFRA',
|
||||
urls: {
|
||||
recette: 'https://dashboard.recette.santinova-soft.org',
|
||||
prod: 'https://dashboard.santinova-soft.org',
|
||||
recette: 'https://dashboard-santinova.recette.santinova-soft.org',
|
||||
prod: 'https://dashboard-santinova.santinova-soft.org',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -48,7 +48,7 @@ try {
|
||||
id: 'falc-generator',
|
||||
name: 'FALC Generator',
|
||||
category: 'ITINOVA',
|
||||
urls: { recette: 'https://falc.recette.santinova-soft.org' },
|
||||
urls: { recette: 'https://falc-itinova.recette.santinova-soft.org' },
|
||||
});
|
||||
|
||||
writeManifest(sandbox, 'invalide', {
|
||||
|
||||
14
src/backend/test/dockerfile-source-path.test.js
Normal file
14
src/backend/test/dockerfile-source-path.test.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const dockerfile = fs.readFileSync(path.resolve(__dirname, '../../../Dockerfile'), 'utf8');
|
||||
|
||||
assert.match(dockerfile, /COPY src\/frontend\/package\.json src\/frontend\/pnpm-lock\.yaml\* \.\//);
|
||||
assert.match(dockerfile, /COPY src\/frontend\/ \.\//);
|
||||
assert.match(dockerfile, /COPY src\/backend\/package\.json src\/backend\/package-lock\.json \.\/backend\//);
|
||||
assert.match(dockerfile, /COPY src\/backend\/ \.\//);
|
||||
assert.doesNotMatch(dockerfile, /COPY frontend\//);
|
||||
assert.doesNotMatch(dockerfile, /COPY backend\//);
|
||||
|
||||
console.log('OK dockerfile source paths');
|
||||
@@ -17,7 +17,7 @@ services:
|
||||
- GITEA_RECETTE_URL=http://gitea:3000
|
||||
- GITEA_TOKEN_PROD=${GITEA_TOKEN_PROD:-}
|
||||
- WEBHOOK_SECRET=${WEBHOOK_SECRET:?WEBHOOK_SECRET requis dans le fichier .env serveur}
|
||||
- IA_REFERENTIEL_URL=${IA_REFERENTIEL_URL:-https://referentiel-ia.recette.santinova-soft.org}
|
||||
- IA_REFERENTIEL_URL=https://referentiel-ia-santinova.santinova-soft.org
|
||||
- IA_REFERENTIEL_TOKEN=${IA_REFERENTIEL_TOKEN:-}
|
||||
- DSI_ALERT_EMAIL=${DSI_ALERT_EMAIL:-}
|
||||
- CI_ALERT_EMAIL_QUEUE=/opt/manus-deploy/secrets/ci-alerts/outbox
|
||||
|
||||
@@ -55,9 +55,9 @@ const RECETTE = {
|
||||
icon: LayoutDashboard,
|
||||
color: 'blue',
|
||||
name: 'Dashboard',
|
||||
url: 'dashboard.recette.santinova-soft.org',
|
||||
url: 'dashboard-santinova.recette.santinova-soft.org',
|
||||
desc: 'Monitoring CPU / RAM / Disque',
|
||||
href: 'https://dashboard.recette.santinova-soft.org',
|
||||
href: 'https://dashboard-santinova.recette.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
icon: Globe,
|
||||
@@ -80,38 +80,38 @@ const RECETTE = {
|
||||
icon: '🧾',
|
||||
color: 'green',
|
||||
name: 'Démat. Facturation DSI',
|
||||
url: 'demat-facturation.recette.santinova-soft.org',
|
||||
href: 'https://demat-facturation.recette.santinova-soft.org',
|
||||
url: 'demat-facturation-santinova.recette.santinova-soft.org',
|
||||
href: 'https://demat-facturation-santinova.recette.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
icon: '👁️',
|
||||
color: 'indigo',
|
||||
name: 'Veille Réglementaire',
|
||||
url: 'veille.recette.santinova-soft.org',
|
||||
href: 'https://veille.recette.santinova-soft.org',
|
||||
url: 'veille-itinova.recette.santinova-soft.org',
|
||||
href: 'https://veille-itinova.recette.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
icon: '🗺️',
|
||||
color: 'cyan',
|
||||
name: 'SONUM',
|
||||
url: 'sonum.recette.santinova-soft.org',
|
||||
url: 'sonum-santinova.recette.santinova-soft.org',
|
||||
desc: 'Cartographie solutions numériques FEHAP',
|
||||
href: 'https://sonum.recette.santinova-soft.org',
|
||||
href: 'https://sonum-santinova.recette.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
icon: '👤',
|
||||
color: 'pink',
|
||||
name: 'Itinova Contacts',
|
||||
url: 'contacts.recette.santinova-soft.org',
|
||||
href: 'https://contacts.recette.santinova-soft.org',
|
||||
url: 'contacts-itinova.recette.santinova-soft.org',
|
||||
href: 'https://contacts-itinova.recette.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
icon: BrainCircuit,
|
||||
color: 'purple',
|
||||
name: 'Référentiel IA Santinova',
|
||||
url: 'referentiel-ia.recette.santinova-soft.org',
|
||||
url: 'referentiel-ia-santinova.recette.santinova-soft.org',
|
||||
desc: 'Décisions, contrats sécurisés et budgets IA',
|
||||
href: 'https://referentiel-ia.recette.santinova-soft.org',
|
||||
href: 'https://referentiel-ia-santinova.recette.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
icon: ServerCog,
|
||||
@@ -125,15 +125,15 @@ const RECETTE = {
|
||||
icon: '🚗',
|
||||
color: 'yellow',
|
||||
name: 'Flotte Véhicules',
|
||||
url: 'flotte.recette.santinova-soft.org',
|
||||
href: 'https://flotte.recette.santinova-soft.org',
|
||||
url: 'flotte-itinova.recette.santinova-soft.org',
|
||||
href: 'https://flotte-itinova.recette.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
icon: '🎧',
|
||||
color: 'orange',
|
||||
name: 'Podcasts Itinova',
|
||||
url: 'podcasts.recette.santinova-soft.org',
|
||||
href: 'https://podcasts.recette.santinova-soft.org',
|
||||
url: 'podcasts-itinova.recette.santinova-soft.org',
|
||||
href: 'https://podcasts-itinova.recette.santinova-soft.org',
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -159,9 +159,9 @@ const PRODUCTION = {
|
||||
icon: LayoutDashboard,
|
||||
color: 'blue',
|
||||
name: 'Dashboard',
|
||||
url: 'dashboard.santinova-soft.org',
|
||||
url: 'dashboard-santinova.santinova-soft.org',
|
||||
desc: 'Monitoring temps réel',
|
||||
href: 'https://dashboard.santinova-soft.org',
|
||||
href: 'https://dashboard-santinova.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
icon: Globe,
|
||||
|
||||
@@ -7,49 +7,49 @@ const APPS_CONFIG = [
|
||||
id: 'itinova-contacts',
|
||||
name: 'Itinova Contacts',
|
||||
repoName: 'itinova-contacts',
|
||||
urlRecette: 'https://contacts.recette.santinova-soft.org',
|
||||
urlProd: 'https://contacts.santinova-soft.org',
|
||||
urlRecette: 'https://contacts-itinova.recette.santinova-soft.org',
|
||||
urlProd: 'https://contacts-itinova.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
id: 'itinova-podcasts',
|
||||
name: 'Itinova Podcasts',
|
||||
repoName: 'itinova-podcasts',
|
||||
urlRecette: 'https://podcasts.recette.santinova-soft.org',
|
||||
urlProd: 'https://podcasts.santinova-soft.org',
|
||||
urlRecette: 'https://podcasts-itinova.recette.santinova-soft.org',
|
||||
urlProd: 'https://podcasts-itinova.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
id: 'veille-reglementaire',
|
||||
name: 'Veille Réglementaire',
|
||||
repoName: 'veille-reglementaire',
|
||||
urlRecette: 'https://veille.recette.santinova-soft.org',
|
||||
urlProd: 'https://veille.santinova-soft.org',
|
||||
urlRecette: 'https://veille-itinova.recette.santinova-soft.org',
|
||||
urlProd: 'https://veille-itinova.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
id: 'itinova-vehicle-exchange',
|
||||
name: 'Itinova Gestion de Flotte',
|
||||
repoName: 'itinova-vehicle-exchange',
|
||||
urlRecette: 'https://flotte.recette.santinova-soft.org',
|
||||
urlProd: 'https://flotte.santinova-soft.org',
|
||||
urlRecette: 'https://flotte-itinova.recette.santinova-soft.org',
|
||||
urlProd: 'https://flotte-itinova.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
id: 'sonum',
|
||||
name: 'SONUM',
|
||||
repoName: 'sonum',
|
||||
urlRecette: 'https://sonum.recette.santinova-soft.org',
|
||||
urlProd: 'https://sonum.santinova-soft.org',
|
||||
urlRecette: 'https://sonum-santinova.recette.santinova-soft.org',
|
||||
urlProd: 'https://sonum-santinova.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
id: 'demat-facturation-dsi',
|
||||
name: 'Démat. Facturation DSI',
|
||||
repoName: 'demat-facturation-dsi',
|
||||
urlRecette: 'https://demat-facturation.recette.santinova-soft.org',
|
||||
urlProd: 'https://demat-facturation.santinova-soft.org',
|
||||
urlRecette: 'https://demat-facturation-santinova.recette.santinova-soft.org',
|
||||
urlProd: 'https://demat-facturation-santinova.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
id: 'facturation-santinova',
|
||||
name: 'Facturation Santinova',
|
||||
repoName: 'facturation-santinova',
|
||||
urlRecette: 'https://facturation.recette.santinova-soft.org',
|
||||
urlRecette: 'https://facturation-santinova.recette.santinova-soft.org',
|
||||
urlProd: null,
|
||||
},
|
||||
{
|
||||
@@ -57,28 +57,28 @@ const APPS_CONFIG = [
|
||||
name: 'Formation Manager',
|
||||
repoName: 'formation-manager-itinova',
|
||||
urlRecette: 'https://formation.recette.santinova-soft.org',
|
||||
urlProd: 'https://formations.itinova.org',
|
||||
urlProd: 'https://formations-itinova.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
id: 'pilotage-masse-salariale',
|
||||
name: 'Pilotage Masse Salariale',
|
||||
repoName: 'pilotage-masse-salariale',
|
||||
urlRecette: 'https://pilotage-ms.recette.santinova-soft.org',
|
||||
urlRecette: 'https://pilotage-ms-itinova.recette.santinova-soft.org',
|
||||
urlProd: null,
|
||||
},
|
||||
{
|
||||
id: 'itinova-budget-si',
|
||||
name: 'Gestion Budget Informatique',
|
||||
repoName: 'itinova-budget-si',
|
||||
urlRecette: 'https://budget-si.recette.santinova-soft.org',
|
||||
urlRecette: 'https://budget-si-santinova.recette.santinova-soft.org',
|
||||
urlProd: null,
|
||||
},
|
||||
{
|
||||
id: 'falc-generator',
|
||||
name: 'FALC Generator',
|
||||
repoName: 'falc-generator',
|
||||
urlRecette: 'https://falc.recette.santinova-soft.org',
|
||||
urlProd: 'https://falc.santinova-soft.org',
|
||||
urlRecette: 'https://falc-itinova.recette.santinova-soft.org',
|
||||
urlProd: 'https://falc-itinova.santinova-soft.org',
|
||||
},
|
||||
{
|
||||
id: 'portail-santinova',
|
||||
@@ -91,8 +91,8 @@ const APPS_CONFIG = [
|
||||
id: 'manus-dashboard',
|
||||
name: 'Dashboard Production',
|
||||
repoName: 'manus-dashboard',
|
||||
urlRecette: 'https://dashboard.recette.santinova-soft.org',
|
||||
urlProd: 'https://dashboard.santinova-soft.org',
|
||||
urlRecette: 'https://dashboard-santinova.recette.santinova-soft.org',
|
||||
urlProd: 'https://dashboard-santinova.santinova-soft.org',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ test('le workflow rappelle la séparation des budgets et des accès internes', a
|
||||
assert.match(source, /Aucune clé fournisseur ni URL Ollama privée/);
|
||||
assert.match(source, /aria-labelledby="ia-workflow-title"/);
|
||||
assert.match(source, /aria-label="Modes de décision du moteur IA"/);
|
||||
assert.match(source, /referentiel-ia\.recette\.santinova-soft\.org/);
|
||||
assert.match(source, /referentiel-ia-santinova\.recette\.santinova-soft\.org/);
|
||||
assert.match(source, /llm-local\.recette\.santinova-soft\.org/);
|
||||
assert.doesNotMatch(source, /http:\/\/ollama:11434/);
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import test from 'node:test';
|
||||
import { getEnvironmentConfig } from '../src/utils/environment.js';
|
||||
|
||||
test('détecte le dashboard de recette depuis son domaine public', () => {
|
||||
const config = getEnvironmentConfig('dashboard.recette.santinova-soft.org');
|
||||
const config = getEnvironmentConfig('dashboard-santinova.recette.santinova-soft.org');
|
||||
assert.equal(config.isRecette, true);
|
||||
assert.equal(config.label, 'Recette');
|
||||
assert.equal(config.serverPublicIp, '78.138.58.109');
|
||||
@@ -13,7 +13,7 @@ test('détecte le dashboard de recette depuis son domaine public', () => {
|
||||
});
|
||||
|
||||
test('détecte le dashboard de production depuis son domaine public', () => {
|
||||
const config = getEnvironmentConfig('dashboard.santinova-soft.org');
|
||||
const config = getEnvironmentConfig('dashboard-santinova.santinova-soft.org');
|
||||
assert.equal(config.isRecette, false);
|
||||
assert.equal(config.label, 'Production');
|
||||
assert.equal(config.serverPublicIp, '180.149.196.138');
|
||||
|
||||
Reference in New Issue
Block a user