Refactoring

This commit is contained in:
dahoud
2026-02-05 18:09:30 +00:00
parent 2a794523b6
commit 806efeb074
24 changed files with 2261 additions and 123 deletions

View File

@@ -1,12 +1,2 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: afterwork-config
namespace: applications
data:
DB_HOST: "postgresql"
DB_PORT: "5432"
DB_NAME: "afterwork_db"
DB_USERNAME: "afterwork"
QUARKUS_PROFILE: "prod"
TZ: "Africa/Douala"
# ConfigMap déplacé dans afterwork-secrets.yaml pour cohérence
# Voir afterwork-secrets.yaml pour la configuration complète

View File

@@ -1,14 +1,20 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: afterwork-api
name: mic-after-work-server-impl-quarkus-main
namespace: applications
labels:
app: afterwork-api
app: mic-after-work-server-impl-quarkus-main
version: "1.0.0"
environment: production
component: application
project: lions-infrastructure-2025
annotations:
description: "AfterWork API - Application sociale déployée via lionsctl"
lionsctl.lions.dev/deployed-by: "lionsctl"
spec:
replicas: 2
replicas: 1
revisionHistoryLimit: 3
strategy:
type: RollingUpdate
rollingUpdate:
@@ -16,37 +22,86 @@ spec:
maxUnavailable: 0
selector:
matchLabels:
app: afterwork-api
app: mic-after-work-server-impl-quarkus-main
template:
metadata:
labels:
app: afterwork-api
app: mic-after-work-server-impl-quarkus-main
version: "1.0.0"
component: application
project: lions-infrastructure-2025
annotations:
# Prometheus scraping - Lions Prometheus auto-découvre via ces annotations
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/afterwork/q/metrics"
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1001
runAsGroup: 1001
fsGroup: 1001
seccompProfile:
type: RuntimeDefault
terminationGracePeriodSeconds: 30
containers:
- name: afterwork-api
image: registry.lions.dev/lionsdev/mic-after-work-server-impl-quarkus-main:d659416
- name: mic-after-work-server-impl-quarkus-main
image: registry.lions.dev/lionsdev/mic-after-work-server-impl-quarkus-main:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
protocol: TCP
# Variables d'environnement depuis ConfigMap et Secrets
envFrom:
- configMapRef:
name: afterwork-config
- secretRef:
name: afterwork-secrets
env:
# Override explicites pour Quarkus
- name: QUARKUS_DATASOURCE_DB_KIND
value: "postgresql"
- name: QUARKUS_DATASOURCE_USERNAME
valueFrom:
configMapKeyRef:
name: afterwork-config
key: DB_USERNAME
- name: QUARKUS_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: afterwork-secrets
key: DB_PASSWORD
- name: QUARKUS_DATASOURCE_JDBC_URL
value: "jdbc:postgresql://$(DB_HOST):$(DB_PORT)/$(DB_NAME)"
# Kafka - Lions Kafka cluster
- name: KAFKA_BOOTSTRAP_SERVERS
valueFrom:
configMapKeyRef:
name: afterwork-config
key: KAFKA_BOOTSTRAP_SERVERS
# JWT
- name: SMALLRYE_JWT_SIGN_KEY
valueFrom:
secretKeyRef:
name: afterwork-secrets
key: JWT_SECRET
- name: MP_JWT_VERIFY_ISSUER
valueFrom:
configMapKeyRef:
name: afterwork-config
key: JWT_ISSUER
# Java options
- name: JAVA_OPTS
value: "-Xms256m -Xmx512m -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
resources:
requests:
memory: "512Mi"
cpu: "250m"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "1000m"
# Health checks HTTP (utilisent les endpoints SmallRye Health)
livenessProbe:
httpGet:
path: /afterwork/q/health/live
@@ -67,13 +122,35 @@ spec:
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
# Startup probe pour éviter les kills pendant le démarrage
startupProbe:
httpGet:
path: /afterwork/q/health/started
port: 8080
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1001
runAsGroup: 1001
capabilities:
drop:
- ALL
volumeMounts:
- name: temp-uploads
mountPath: /tmp/uploads
- name: tmp-volume
mountPath: /tmp
- name: logs-volume
mountPath: /app/logs
volumes:
- name: temp-uploads
emptyDir:
sizeLimit: 1Gi
- name: tmp-volume
emptyDir: {}
- name: logs-volume
emptyDir: {}
imagePullSecrets:
- name: lionsregistry-secret
restartPolicy: Always

View File

@@ -0,0 +1,408 @@
# ==============================================================================
# AfterWork API - Configuration Monitoring pour Lions Infrastructure
# ==============================================================================
# Cette configuration intègre l'application avec:
# - Prometheus (https://prometheus.lions.dev) - scraping auto via annotations
# - Grafana (https://grafana.lions.dev) - dashboard dédié
# ==============================================================================
---
# ==============================================================================
# ServiceMonitor pour Prometheus Operator (si installé)
# ==============================================================================
# Note: L'infrastructure Lions utilise le scraping via annotations pod, mais
# ce ServiceMonitor peut être utilisé si Prometheus Operator est déployé.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: afterwork-api-monitor
namespace: monitoring
labels:
app: mic-after-work-server-impl-quarkus-main
release: prometheus
project: lions-infrastructure-2025
spec:
selector:
matchLabels:
app: mic-after-work-server-impl-quarkus-main
namespaceSelector:
matchNames:
- applications
endpoints:
- port: http-direct
path: /afterwork/q/metrics
interval: 30s
scrapeTimeout: 10s
scheme: http
---
# ==============================================================================
# PrometheusRule - Alertes pour AfterWork API
# ==============================================================================
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: afterwork-api-alerts
namespace: monitoring
labels:
app: mic-after-work-server-impl-quarkus-main
release: prometheus
project: lions-infrastructure-2025
spec:
groups:
- name: afterwork-api.rules
rules:
# Alerte si l'application est down
- alert: AfterWorkAPIDown
expr: up{job=~".*afterwork.*"} == 0
for: 2m
labels:
severity: critical
application: afterwork-api
annotations:
summary: "AfterWork API is down"
description: "L'API AfterWork n'est pas accessible depuis plus de 2 minutes"
# Alerte si le taux d'erreur HTTP 5xx est élevé
- alert: AfterWorkHighErrorRate
expr: |
sum(rate(http_server_requests_seconds_count{
kubernetes_namespace="applications",
app="mic-after-work-server-impl-quarkus-main",
status=~"5.."
}[5m])) /
sum(rate(http_server_requests_seconds_count{
kubernetes_namespace="applications",
app="mic-after-work-server-impl-quarkus-main"
}[5m])) > 0.05
for: 5m
labels:
severity: warning
application: afterwork-api
annotations:
summary: "High error rate on AfterWork API"
description: "Le taux d'erreur 5xx est supérieur à 5% depuis 5 minutes"
# Alerte si la latence p95 est élevée
- alert: AfterWorkHighLatency
expr: |
histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{
kubernetes_namespace="applications",
app="mic-after-work-server-impl-quarkus-main"
}[5m])) by (le)) > 2
for: 5m
labels:
severity: warning
application: afterwork-api
annotations:
summary: "High latency on AfterWork API"
description: "La latence p95 dépasse 2 secondes depuis 5 minutes"
# Alerte si la mémoire est proche de la limite
- alert: AfterWorkHighMemoryUsage
expr: |
sum(container_memory_working_set_bytes{
namespace="applications",
pod=~"mic-after-work-server-impl-quarkus-main.*"
}) /
sum(container_spec_memory_limit_bytes{
namespace="applications",
pod=~"mic-after-work-server-impl-quarkus-main.*"
}) > 0.85
for: 5m
labels:
severity: warning
application: afterwork-api
annotations:
summary: "High memory usage on AfterWork API"
description: "L'utilisation mémoire dépasse 85% de la limite"
# Alerte si le pod redémarre fréquemment
- alert: AfterWorkPodRestarts
expr: |
increase(kube_pod_container_status_restarts_total{
namespace="applications",
pod=~"mic-after-work-server-impl-quarkus-main.*"
}[1h]) > 3
for: 5m
labels:
severity: warning
application: afterwork-api
annotations:
summary: "AfterWork API pod restarting frequently"
description: "Le pod a redémarré plus de 3 fois dans la dernière heure"
---
# ==============================================================================
# Grafana Dashboard ConfigMap (pour import automatique)
# ==============================================================================
apiVersion: v1
kind: ConfigMap
metadata:
name: afterwork-grafana-dashboard
namespace: monitoring
labels:
grafana_dashboard: "1"
app: mic-after-work-server-impl-quarkus-main
project: lions-infrastructure-2025
data:
afterwork-api-dashboard.json: |
{
"annotations": {
"list": []
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "green", "value": null},
{"color": "yellow", "value": 100},
{"color": "red", "value": 500}
]
},
"unit": "reqps"
}
},
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
"id": 1,
"options": {},
"targets": [
{
"expr": "sum(rate(http_server_requests_seconds_count{kubernetes_namespace=\"applications\",app=\"mic-after-work-server-impl-quarkus-main\"}[5m]))",
"legendFormat": "Requests/s",
"refId": "A"
}
],
"title": "Request Rate",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"unit": "ms"
}
},
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0},
"id": 2,
"options": {},
"targets": [
{
"expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{kubernetes_namespace=\"applications\",app=\"mic-after-work-server-impl-quarkus-main\"}[5m])) by (le)) * 1000",
"legendFormat": "p95 Latency",
"refId": "A"
},
{
"expr": "histogram_quantile(0.50, sum(rate(http_server_requests_seconds_bucket{kubernetes_namespace=\"applications\",app=\"mic-after-work-server-impl-quarkus-main\"}[5m])) by (le)) * 1000",
"legendFormat": "p50 Latency",
"refId": "B"
}
],
"title": "Response Time",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"unit": "percent"
}
},
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 8},
"id": 3,
"options": {},
"targets": [
{
"expr": "sum(rate(http_server_requests_seconds_count{kubernetes_namespace=\"applications\",app=\"mic-after-work-server-impl-quarkus-main\",status=~\"5..\"}[5m])) / sum(rate(http_server_requests_seconds_count{kubernetes_namespace=\"applications\",app=\"mic-after-work-server-impl-quarkus-main\"}[5m])) * 100",
"legendFormat": "Error Rate %",
"refId": "A"
}
],
"title": "Error Rate",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"unit": "bytes"
}
},
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 8},
"id": 4,
"options": {},
"targets": [
{
"expr": "sum(container_memory_working_set_bytes{namespace=\"applications\",pod=~\"mic-after-work-server-impl-quarkus-main.*\"})",
"legendFormat": "Memory Used",
"refId": "A"
},
{
"expr": "sum(container_spec_memory_limit_bytes{namespace=\"applications\",pod=~\"mic-after-work-server-impl-quarkus-main.*\"})",
"legendFormat": "Memory Limit",
"refId": "B"
}
],
"title": "Memory Usage",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"unit": "short"
}
},
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 16},
"id": 5,
"options": {},
"targets": [
{
"expr": "sum(rate(container_cpu_usage_seconds_total{namespace=\"applications\",pod=~\"mic-after-work-server-impl-quarkus-main.*\"}[5m])) * 1000",
"legendFormat": "CPU Usage (millicores)",
"refId": "A"
}
],
"title": "CPU Usage",
"type": "timeseries"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "red", "value": null},
{"color": "green", "value": 1}
]
}
}
},
"gridPos": {"h": 4, "w": 6, "x": 12, "y": 16},
"id": 6,
"options": {
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"showThresholdLabels": false,
"showThresholdMarkers": true
},
"targets": [
{
"expr": "up{job=~\".*afterwork.*\"}",
"legendFormat": "Status",
"refId": "A"
}
],
"title": "API Status",
"type": "gauge"
},
{
"datasource": {
"type": "prometheus",
"uid": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"thresholds": {
"mode": "absolute",
"steps": [
{"color": "green", "value": null},
{"color": "yellow", "value": 1},
{"color": "red", "value": 3}
]
}
}
},
"gridPos": {"h": 4, "w": 6, "x": 18, "y": 16},
"id": 7,
"options": {
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
}
},
"targets": [
{
"expr": "increase(kube_pod_container_status_restarts_total{namespace=\"applications\",pod=~\"mic-after-work-server-impl-quarkus-main.*\"}[1h])",
"legendFormat": "Restarts (1h)",
"refId": "A"
}
],
"title": "Pod Restarts (1h)",
"type": "stat"
}
],
"refresh": "30s",
"schemaVersion": 38,
"style": "dark",
"tags": ["lions", "afterwork", "quarkus", "api"],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"timezone": "browser",
"title": "AfterWork API Dashboard",
"uid": "afterwork-api",
"version": 1,
"weekStart": ""
}

View File

@@ -6,8 +6,175 @@ metadata:
labels:
app: afterwork-api
component: secrets
environment: production
project: lions-infrastructure-2025
type: Opaque
stringData:
# Base de données PostgreSQL
# Pattern cohérent avec unionflow et btpxpress
# ==============================================================================
# BASE DE DONNÉES PostgreSQL
# ==============================================================================
# Utilise le PostgreSQL de l'infrastructure Lions
# postgresql-service.postgresql.svc.cluster.local:5432
DB_PASSWORD: "AfterWork2025!"
# ==============================================================================
# JWT / SÉCURITÉ
# ==============================================================================
# Clé secrète JWT (minimum 32 caractères, aléatoire)
# Générer avec: openssl rand -base64 32
JWT_SECRET: "AfterWorkJWTSecret2025LionsInfrastructureKey"
# ==============================================================================
# COMPTE ADMINISTRATEUR INITIAL
# ==============================================================================
ADMIN_EMAIL: "admin@afterwork.ci"
ADMIN_PASSWORD: "AdminAfterWork2025!"
# ==============================================================================
# SERVICE EMAIL (SMTP)
# ==============================================================================
# Configuration Gmail ou autre SMTP
MAILER_USERNAME: "noreply@afterwork.ci"
MAILER_PASSWORD: "CHANGEZ_MOI_SMTP_PASSWORD"
# ==============================================================================
# WAVE PAYMENT (Intégration paiement)
# ==============================================================================
WAVE_API_KEY: "CHANGEZ_MOI_WAVE_API_KEY"
WAVE_SECRET: "CHANGEZ_MOI_WAVE_SECRET"
---
# ==============================================================================
# CONFIGMAP POUR CONFIGURATION NON-SENSIBLE
# ==============================================================================
apiVersion: v1
kind: ConfigMap
metadata:
name: afterwork-config
namespace: applications
labels:
app: afterwork-api
component: configuration
environment: production
project: lions-infrastructure-2025
data:
# ==============================================================================
# BASE DE DONNÉES - Lions PostgreSQL
# ==============================================================================
DB_HOST: "postgresql-service.postgresql.svc.cluster.local"
DB_PORT: "5432"
DB_NAME: "mic-after-work-server-impl-quarkus-main"
DB_USERNAME: "lionsuser"
# ==============================================================================
# QUARKUS
# ==============================================================================
QUARKUS_PROFILE: "prod"
QUARKUS_LOG_LEVEL: "INFO"
QUARKUS_LOG_CONSOLE_JSON: "true"
# ==============================================================================
# JWT
# ==============================================================================
JWT_LIFESPAN: "86400"
JWT_ISSUER: "afterwork-api"
# ==============================================================================
# KAFKA - Lions Infrastructure
# ==============================================================================
# Utilise le Kafka déployé dans le namespace kafka
KAFKA_BOOTSTRAP_SERVERS: "kafka-service.kafka.svc.cluster.local:9092"
# ==============================================================================
# EMAIL (SMTP)
# ==============================================================================
MAILER_HOST: "smtp.gmail.com"
MAILER_PORT: "587"
MAILER_FROM: "AfterWork <noreply@afterwork.ci>"
MAILER_START_TLS: "REQUIRED"
# En production, mettre false. true = mock (pas d'envoi réel)
MAILER_MOCK: "true"
# ==============================================================================
# RATE LIMITING
# ==============================================================================
AFTERWORK_RATELIMIT_MAX_REQUESTS: "10"
AFTERWORK_RATELIMIT_WINDOW_SECONDS: "60"
# ==============================================================================
# WAVE PAYMENT
# ==============================================================================
WAVE_BASE_URL: "https://api.wave.com"
WAVE_CURRENCY: "XOF"
WAVE_CALLBACK_URL: "https://api.lions.dev/afterwork/webhooks/wave"
# ==============================================================================
# OBSERVABILITY - Lions Prometheus/Grafana
# ==============================================================================
# Prometheus scrape via annotations sur le pod
# Grafana disponible sur https://grafana.lions.dev
# ==============================================================================
# KEYCLOAK / SSO (optionnel)
# ==============================================================================
# OIDC_AUTH_SERVER_URL: "https://security.lions.dev/realms/lions"
# OIDC_CLIENT_ID: "afterwork-api"
---
# ==============================================================================
# EXTERNAL SECRET - Intégration Vault (ACTIF)
# ==============================================================================
# Vault est déverrouillé sur https://vault.lions.dev
# Les secrets sont synchronisés depuis Vault vers Kubernetes automatiquement
#
# PRÉREQUIS: Créer les secrets dans Vault avec:
# vault kv put lions/afterwork \
# db_password="AfterWork2025!" \
# jwt_secret="AfterWorkJWTSecret2025LionsInfrastructureKey" \
# admin_password="AdminAfterWork2025!" \
# mailer_password="SMTP_PASSWORD" \
# wave_api_key="WAVE_KEY" \
# wave_secret="WAVE_SECRET"
#
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: afterwork-vault-secrets
namespace: applications
labels:
app: afterwork-api
component: external-secrets
project: lions-infrastructure-2025
spec:
refreshInterval: "1h"
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: afterwork-secrets-vault
creationPolicy: Owner
data:
- secretKey: DB_PASSWORD
remoteRef:
key: lions/data/afterwork
property: db_password
- secretKey: JWT_SECRET
remoteRef:
key: lions/data/afterwork
property: jwt_secret
- secretKey: ADMIN_PASSWORD
remoteRef:
key: lions/data/afterwork
property: admin_password
- secretKey: MAILER_PASSWORD
remoteRef:
key: lions/data/afterwork
property: mailer_password
- secretKey: WAVE_API_KEY
remoteRef:
key: lions/data/afterwork
property: wave_api_key
- secretKey: WAVE_SECRET
remoteRef:
key: lions/data/afterwork
property: wave_secret

View File

@@ -1,10 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: afterwork-api
name: mic-after-work-server-impl-quarkus-main-service
namespace: applications
labels:
app: afterwork-api
app: mic-after-work-server-impl-quarkus-main
component: application
project: lions-infrastructure-2025
annotations:
description: "Service for AfterWork API"
spec:
type: ClusterIP
sessionAffinity: ClientIP
@@ -12,9 +16,15 @@ spec:
clientIP:
timeoutSeconds: 10800
ports:
- port: 8080
# Port 80 exposé, route vers 8080 du container
- port: 80
targetPort: 8080
protocol: TCP
name: http
# Port 8080 pour compatibilité directe
- port: 8080
targetPort: 8080
protocol: TCP
name: http-direct
selector:
app: afterwork-api
app: mic-after-work-server-impl-quarkus-main