- sogoctl: supervisor avec health checks et restart auto - sogoway: gateway HTTP, auth JWT, routing par hostname - sogoms-db: microservice MariaDB avec pool par application - Protocol IPC Unix socket JSON length-prefixed - Config YAML multi-application (prokov) - Deploy script pour container Alpine gw3 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1196 lines
33 KiB
Markdown
Executable File
1196 lines
33 KiB
Markdown
Executable File
# SOGOMS - Service Oriented GO MicroServices
|
|
|
|
> Architecture modulaire, configurable et multi-tenant pour plateformes SaaS
|
|
|
|
**Website** : https://sogoms.com
|
|
|
|
---
|
|
|
|
## 1. Vision et Principes
|
|
|
|
### 1.1 Concept
|
|
|
|
SOGOMS est une architecture de plateforme permettant de construire des applications SaaS modulaires, hautement configurables et multi-tenant.
|
|
|
|
L'idée centrale : **une seule plateforme, plusieurs services, plusieurs clients, configurations illimitées.**
|
|
|
|
### 1.2 Principes fondamentaux
|
|
|
|
| Principe | Description |
|
|
|----------|-------------|
|
|
| **Modularité** | Chaque fonctionnalité = un binaire Go indépendant |
|
|
| **Configuration over Code** | Comportements définis en YAML, pas en dur |
|
|
| **Multi-tenant natif** | Isolation des données et configs par client |
|
|
| **Orchestration** | Workflows complexes via scénarios paramétrables |
|
|
| **Scalabilité horizontale** | Chaque binaire peut avoir N instances |
|
|
| **Simplicité** | Un container, plusieurs processus supervisés |
|
|
|
|
### 1.3 Cas d'usage cibles
|
|
|
|
- Plateformes SaaS B2B multi-clients
|
|
- Applications métier avec workflows personnalisables
|
|
- Systèmes de gestion documentaire (PDF, signatures, archivage)
|
|
- Plateformes de communication (emails, notifications, SMS)
|
|
- Back-offices d'applications mobiles Flutter
|
|
|
|
### 1.4 Composants de l'écosystème
|
|
|
|
| Composant | Description |
|
|
|-----------|-------------|
|
|
| **SOGOMS** | Plateforme principale (ce document) |
|
|
| **SOGOMS Vigil** | Extension monitoring (voir `sogoms-vigil.md`) |
|
|
|
|
---
|
|
|
|
## 2. Architecture Globale
|
|
|
|
### 2.1 Infrastructure
|
|
|
|
```
|
|
Internet
|
|
│
|
|
▼
|
|
┌────────────────────────────────────────────────────────────────────────────┐
|
|
│ IN3 (Dev/Recette) ou IN4 (Prod) │
|
|
│ Debian 13 - Host │
|
|
├────────────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Nginx Host (:443 TLS → :80 HTTP) │
|
|
│ │ │
|
|
│ ├── api-dev.sogoms.com ──→ gw3:8080 (Dev) │
|
|
│ ├── api.sogoms.com ──────→ gw4:8080 (Prod) │
|
|
│ └── (autres sites) ──────→ [containers PHP existants] │
|
|
│ │
|
|
├────────────────────────────────────────────────────────────────────────────┤
|
|
│ Bridge Incus : 13.23.33.0/24 │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────────────────┐ │
|
|
│ │ gw3 - 13.23.33.5 (ou gw4) │ │
|
|
│ │ Alpine 3.21 │ │
|
|
│ │ │ │
|
|
│ │ ┌────────────────────────────────────────────────────────┐ │ │
|
|
│ │ │ Sogoctl (superviseur) │ │ │
|
|
│ │ │ PID 1 - Admin :9000 │ │ │
|
|
│ │ └────────────────────────┬───────────────────────────────┘ │ │
|
|
│ │ │ supervise │ │
|
|
│ │ ┌────────────────────────┴───────────────────────────────┐ │ │
|
|
│ │ │ │ │ │
|
|
│ │ │ Sogoway (:8080) │ │ │
|
|
│ │ │ │ │ │ │
|
|
│ │ │ ▼ unix socket │ │ │
|
|
│ │ │ Sogorch (N instances) │ │ │
|
|
│ │ │ │ │ │ │
|
|
│ │ │ ▼ unix sockets │ │ │
|
|
│ │ │ ┌──────────┬──────────┬──────────┬──────────┐ │ │ │
|
|
│ │ │ │sogoms-db │sogoms-pdf│sogoms- │sogoms- │ │ │ │
|
|
│ │ │ │ (N) │ (N) │ email(N) │ stor.(N) │ │ │ │
|
|
│ │ │ └──────────┴──────────┴──────────┴──────────┘ │ │ │
|
|
│ │ │ │ │ │
|
|
│ │ └────────────────────────────────────────────────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ /run/ /config/ /data/storage/ │ │
|
|
│ │ └── *.sock ├── sogoctl.yaml └── tenants/ │ │
|
|
│ │ ├── routes/ └── {tenant}/ │ │
|
|
│ │ └── scenarios/ │ │
|
|
│ └──────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌─────────────────┐ ┌─────────────────┐ │
|
|
│ │ maria3 │ │ redis3 │ │
|
|
│ │ 13.23.33.4 │ │ 13.23.33.6 │ │
|
|
│ │ MariaDB :3306 │ │ Redis :6379 │ │
|
|
│ └─────────────────┘ └─────────────────┘ │
|
|
│ │
|
|
└────────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.2 Containers Incus
|
|
|
|
| Container | IP | Rôle | Base |
|
|
|-----------|-----|------|------|
|
|
| **gw3** (dev) / **gw4** (prod) | 13.23.33.5 | Gateway + Orchestrateur + Microservices | Alpine |
|
|
| **maria3** / **maria4** | 13.23.33.4 | MariaDB (existant) | Alpine |
|
|
| **redis3** / **redis4** | 13.23.33.6 | Cache, sessions, rate-limit (V2+) | Alpine |
|
|
|
|
### 2.3 Flux de données
|
|
|
|
```
|
|
1. Client HTTPS → Nginx Host (:443)
|
|
2. Nginx → Sogoway (:8080) via proxy HTTP
|
|
3. Sogoway → Valide JWT → Identifie tenant → Trouve route
|
|
4. Sogoway → Sogorch (unix socket)
|
|
5. Sogorch → Charge scénario YAML → Exécute steps
|
|
6. Sogorch → Sogoms-* (unix sockets) pour chaque step
|
|
7. Sogoms-* → Traite (DB, PDF, email...) → Retourne résultat
|
|
8. Sogorch → Agrège résultats → Retourne à Sogoway
|
|
9. Sogoway → Nginx → Client
|
|
```
|
|
|
|
### 2.4 Identification des Applications Clientes
|
|
|
|
Chaque application cliente de SOGOMS (Prokov, etc.) est identifiée par son **hostname**.
|
|
|
|
#### Flow d'identification
|
|
|
|
```
|
|
1. Requête arrive : GET https://prokov.unikoffice.com/api/auth/me
|
|
2. Nginx Host → Sogoway (:8080) avec Header "Host: prokov.unikoffice.com"
|
|
3. Sogoway parcourt config/routes/*.yaml
|
|
4. Sogoway trouve prokov.yaml car "prokov.unikoffice.com" est dans ses "hosts"
|
|
5. Sogoway identifie app_id = "prokov"
|
|
6. Pour chaque appel à sogoms-db, Sogoway inclut app_id dans la requête
|
|
7. Sogoms-db charge config/routes/prokov.yaml → section "database"
|
|
8. Sogoms-db exécute la requête SQL sur la DB de l'application
|
|
```
|
|
|
|
#### Configuration obligatoire par application
|
|
|
|
Chaque fichier `config/routes/{app}.yaml` DOIT contenir :
|
|
|
|
```yaml
|
|
app: prokov # Identifiant unique
|
|
hosts: # Hostnames associés
|
|
- prokov.unikoffice.com
|
|
- prokov.sogoms.com
|
|
|
|
database: # Config DB isolée
|
|
host: 13.23.33.4
|
|
port: 3306
|
|
user: prokov # User DB dédié
|
|
password_file: /secrets/prokov_db_pass
|
|
name: prokov # Base de données dédiée
|
|
```
|
|
|
|
#### Principe d'isolation
|
|
|
|
| Élément | Isolation |
|
|
|---------|-----------|
|
|
| Base de données | Une DB par application |
|
|
| User MariaDB | Un user par application |
|
|
| Credentials | Fichier séparé par application |
|
|
| Données | Aucun partage entre applications |
|
|
|
|
---
|
|
|
|
## 3. Binaires Go
|
|
|
|
### 3.1 Vue d'ensemble
|
|
|
|
| Binaire | Rôle | Instances | Port/Socket |
|
|
|---------|------|-----------|-------------|
|
|
| **sogoctl** | Superviseur, admin, monitoring | 1 | TCP :9000 |
|
|
| **sogoway** | HTTP Gateway, auth, routing | 1 | TCP :8080 |
|
|
| **sogorch** | Orchestrateur, exécute scénarios | N | Unix socket |
|
|
| **sogoms-db** | Service accès MariaDB | N | Unix socket |
|
|
| **sogoms-pdf** | Service génération PDF | N | Unix socket |
|
|
| **sogoms-email** | Service envoi emails | N | Unix socket |
|
|
| **sogoms-storage** | Service gestion fichiers | N | Unix socket |
|
|
|
|
### 3.2 Sogoctl (Superviseur)
|
|
|
|
Sogoctl est le processus principal (PID 1) qui supervise tous les autres binaires.
|
|
|
|
#### Responsabilités
|
|
|
|
- Démarrer/arrêter les binaires au boot
|
|
- Health checks périodiques
|
|
- Redémarrage automatique en cas de crash
|
|
- Load balancing round-robin entre instances
|
|
- API d'administration (stats, scaling, logs)
|
|
- Registry des instances actives
|
|
|
|
#### Configuration
|
|
|
|
```yaml
|
|
# /config/sogoctl.yaml
|
|
|
|
supervisor:
|
|
socket: /run/sogoctl.sock
|
|
admin_port: 9000
|
|
health_interval: 5s
|
|
restart_delay: 1s
|
|
max_restarts: 5
|
|
|
|
logging:
|
|
level: info
|
|
output: /var/log/sogoms/sogoctl.log
|
|
|
|
services:
|
|
sogoway:
|
|
binary: /opt/sogoms/bin/sogoway
|
|
instances: 1
|
|
port: 8080
|
|
health_endpoint: /health
|
|
|
|
sogorch:
|
|
binary: /opt/sogoms/bin/sogorch
|
|
instances: 2
|
|
socket_pattern: /run/sogorch.{id}.sock
|
|
health_endpoint: /health
|
|
|
|
sogoms-db:
|
|
binary: /opt/sogoms/bin/sogoms-db
|
|
instances: 2
|
|
socket_pattern: /run/sogoms-db.{id}.sock
|
|
env:
|
|
MARIA_HOST: 13.23.33.4
|
|
MARIA_PORT: "3306"
|
|
MARIA_USER: sogoms
|
|
MARIA_PASS_FILE: /secrets/maria_password
|
|
|
|
sogoms-pdf:
|
|
binary: /opt/sogoms/bin/sogoms-pdf
|
|
instances: 1
|
|
socket_pattern: /run/sogoms-pdf.{id}.sock
|
|
autoscale:
|
|
enabled: true
|
|
min: 1
|
|
max: 5
|
|
metric: queue_depth
|
|
threshold: 10
|
|
|
|
sogoms-email:
|
|
binary: /opt/sogoms/bin/sogoms-email
|
|
instances: 1
|
|
socket_pattern: /run/sogoms-email.{id}.sock
|
|
env:
|
|
SMTP_HOST: smtp.example.com
|
|
SMTP_PORT: "587"
|
|
|
|
sogoms-storage:
|
|
binary: /opt/sogoms/bin/sogoms-storage
|
|
instances: 1
|
|
socket_pattern: /run/sogoms-storage.{id}.sock
|
|
env:
|
|
STORAGE_BASE: /data/storage
|
|
```
|
|
|
|
#### CLI Sogoctl
|
|
|
|
```bash
|
|
# Statut global
|
|
$ sogoctl status
|
|
|
|
SERVICE INSTANCE PID STATUS CPU MEM UPTIME
|
|
sogoway 1 1234 running 2% 45MB 2h15m
|
|
sogorch 1 1235 running 5% 32MB 2h15m
|
|
sogorch 2 1236 running 3% 30MB 2h15m
|
|
sogoms-db 1 1237 running 1% 28MB 2h15m
|
|
sogoms-db 2 1238 running 1% 27MB 2h15m
|
|
sogoms-pdf 1 1239 running 0% 52MB 2h15m
|
|
sogoms-email 1 1240 running 0% 25MB 2h15m
|
|
|
|
# Scaler un service
|
|
$ sogoctl scale sogoms-pdf 3
|
|
Scaling sogoms-pdf: 1 → 3
|
|
Starting sogoms-pdf.2 ... OK (PID 1241)
|
|
Starting sogoms-pdf.3 ... OK (PID 1242)
|
|
|
|
# Instances d'un service
|
|
$ sogoctl instances sogoms-pdf
|
|
|
|
INSTANCE PID SOCKET STATUS REQUESTS
|
|
1 1239 /run/sogoms-pdf.1.sock running 1,234
|
|
2 1241 /run/sogoms-pdf.2.sock running 156
|
|
3 1242 /run/sogoms-pdf.3.sock running 89
|
|
|
|
# Redémarrer un service
|
|
$ sogoctl restart sogorch
|
|
|
|
# Logs
|
|
$ sogoctl logs sogoms-pdf.1 --follow
|
|
$ sogoctl logs sogorch --all --since 1h
|
|
|
|
# Stats temps réel
|
|
$ sogoctl top
|
|
|
|
# Info d'un service
|
|
$ sogoctl info sogorch
|
|
```
|
|
|
|
### 3.3 Sogoway (Gateway HTTP)
|
|
|
|
Point d'entrée HTTP unique pour toutes les requêtes API.
|
|
|
|
#### Responsabilités
|
|
|
|
- Réception des requêtes HTTP
|
|
- Authentification (JWT, API Keys)
|
|
- Identification du tenant
|
|
- Routing vers les scénarios
|
|
- Rate limiting
|
|
- Logging des requêtes
|
|
|
|
#### Configuration
|
|
|
|
```yaml
|
|
# /config/sogoway.yaml
|
|
|
|
server:
|
|
port: 8080
|
|
read_timeout: 30s
|
|
write_timeout: 30s
|
|
max_body_size: 10MB
|
|
|
|
auth:
|
|
jwt:
|
|
secret_env: JWT_SECRET
|
|
algorithm: HS256
|
|
expiration: 24h
|
|
claims:
|
|
tenant_id: tenant
|
|
user_id: sub
|
|
roles: roles
|
|
api_keys:
|
|
enabled: true
|
|
header: X-API-Key
|
|
storage: redis
|
|
|
|
tenant:
|
|
resolution:
|
|
- type: jwt_claim
|
|
claim: tenant_id
|
|
- type: header
|
|
name: X-Tenant-ID
|
|
- type: subdomain
|
|
pattern: "{tenant}.api.sogoms.com"
|
|
|
|
rate_limit:
|
|
enabled: true
|
|
storage: redis
|
|
default:
|
|
requests: 1000
|
|
window: 1m
|
|
by_tenant: true
|
|
|
|
orchestrator:
|
|
pool_size: 10
|
|
timeout: 30s
|
|
|
|
routes_path: /config/routes
|
|
|
|
logging:
|
|
level: info
|
|
format: json
|
|
output: stdout
|
|
|
|
metrics:
|
|
enabled: true
|
|
path: /metrics
|
|
```
|
|
|
|
#### Routes par application
|
|
|
|
```yaml
|
|
# /config/routes/prokov.yaml
|
|
|
|
app: prokov
|
|
version: "1.0"
|
|
base_path: /api/prokov
|
|
|
|
auth:
|
|
required: true
|
|
roles: [user, admin]
|
|
|
|
routes:
|
|
# Liste des tâches
|
|
- path: /tasks
|
|
method: GET
|
|
scenario: list_tasks
|
|
cache:
|
|
enabled: true
|
|
ttl: 30s
|
|
|
|
# Créer une tâche
|
|
- path: /tasks
|
|
method: POST
|
|
scenario: create_task
|
|
rate_limit:
|
|
requests: 100
|
|
window: 1m
|
|
|
|
# Détail d'une tâche
|
|
- path: /tasks/{id}
|
|
method: GET
|
|
scenario: get_task
|
|
|
|
# Modifier une tâche
|
|
- path: /tasks/{id}
|
|
method: PUT
|
|
scenario: update_task
|
|
|
|
# Supprimer une tâche
|
|
- path: /tasks/{id}
|
|
method: DELETE
|
|
scenario: delete_task
|
|
auth:
|
|
roles: [admin]
|
|
```
|
|
|
|
### 3.4 Sogorch (Orchestrateur)
|
|
|
|
Exécute les scénarios YAML en appelant les microservices.
|
|
|
|
#### Responsabilités
|
|
|
|
- Charger et parser les scénarios YAML
|
|
- Exécuter les steps séquentiellement ou en parallèle
|
|
- Gérer le contexte et les variables
|
|
- Appeler les Sogoms via Unix sockets
|
|
- Gérer les erreurs, retry, conditions
|
|
- Retourner le résultat agrégé
|
|
|
|
#### Scénario type
|
|
|
|
```yaml
|
|
# /config/scenarios/create_task.yaml
|
|
|
|
name: create_task
|
|
version: "1.0"
|
|
description: Créer une tâche et notifier l'assigné
|
|
|
|
input:
|
|
required:
|
|
- title
|
|
- assigned_to
|
|
optional:
|
|
- description
|
|
- priority
|
|
- notify
|
|
defaults:
|
|
priority: medium
|
|
notify: false
|
|
|
|
context:
|
|
created_at: "{{now}}"
|
|
created_by: "{{auth.user_id}}"
|
|
|
|
steps:
|
|
# Valider que l'utilisateur assigné existe
|
|
- id: validate_user
|
|
service: db
|
|
action: query_one
|
|
params:
|
|
query: "SELECT id, email FROM users WHERE id = ? AND tenant_id = ?"
|
|
args: ["{{input.assigned_to}}", "{{tenant.id}}"]
|
|
on_error: abort
|
|
error_message: "Utilisateur assigné non trouvé"
|
|
|
|
# Insérer la tâche
|
|
- id: insert_task
|
|
service: db
|
|
action: insert
|
|
params:
|
|
table: tasks
|
|
data:
|
|
tenant_id: "{{tenant.id}}"
|
|
title: "{{input.title}}"
|
|
description: "{{input.description}}"
|
|
priority: "{{input.priority}}"
|
|
assigned_to: "{{input.assigned_to}}"
|
|
status: "pending"
|
|
created_by: "{{context.created_by}}"
|
|
created_at: "{{context.created_at}}"
|
|
on_error: abort
|
|
|
|
# Notifier par email (optionnel, async)
|
|
- id: send_notification
|
|
service: email
|
|
action: send
|
|
condition: "{{input.notify == true}}"
|
|
async: true
|
|
params:
|
|
to: "{{steps.validate_user.result.email}}"
|
|
template: task_assigned
|
|
data:
|
|
task_id: "{{steps.insert_task.insert_id}}"
|
|
task_title: "{{input.title}}"
|
|
assigned_by: "{{auth.user_name}}"
|
|
|
|
output:
|
|
status: 201
|
|
body:
|
|
success: true
|
|
task:
|
|
id: "{{steps.insert_task.insert_id}}"
|
|
title: "{{input.title}}"
|
|
status: "pending"
|
|
created_at: "{{context.created_at}}"
|
|
```
|
|
|
|
#### Syntaxe des scénarios
|
|
|
|
```yaml
|
|
# Conditions
|
|
- id: premium_only
|
|
service: billing
|
|
action: check_feature
|
|
condition: "{{tenant.plan == 'premium'}}"
|
|
|
|
# Boucles
|
|
- id: notify_all
|
|
service: email
|
|
action: send
|
|
foreach: "{{input.recipients}}"
|
|
foreach_as: recipient
|
|
params:
|
|
to: "{{recipient.email}}"
|
|
template: notification
|
|
|
|
# Parallélisme
|
|
- id: parallel_tasks
|
|
parallel:
|
|
- id: gen_pdf
|
|
service: pdf
|
|
action: generate
|
|
params: {...}
|
|
- id: send_copy
|
|
service: email
|
|
action: send
|
|
params: {...}
|
|
|
|
# Retry
|
|
- id: external_call
|
|
service: http
|
|
action: post
|
|
retry:
|
|
attempts: 3
|
|
delay: 2s
|
|
backoff: exponential
|
|
|
|
# Switch/case
|
|
- id: route_by_type
|
|
switch: "{{input.document_type}}"
|
|
cases:
|
|
invoice:
|
|
service: pdf
|
|
action: generate_invoice
|
|
contract:
|
|
service: pdf
|
|
action: generate_contract
|
|
default:
|
|
service: pdf
|
|
action: generate_generic
|
|
```
|
|
|
|
### 3.5 Microservices (Sogoms-*)
|
|
|
|
Chaque microservice est un binaire Go spécialisé.
|
|
|
|
#### Structure commune
|
|
|
|
```go
|
|
// Chaque Sogoms implémente cette interface
|
|
type Service interface {
|
|
Name() string
|
|
Actions() map[string]ActionHandler
|
|
Health() error
|
|
}
|
|
|
|
type ActionHandler func(ctx context.Context, params map[string]any) (any, error)
|
|
```
|
|
|
|
#### Sogoms-db
|
|
|
|
```yaml
|
|
# Actions disponibles
|
|
actions:
|
|
- query # SELECT avec plusieurs résultats
|
|
- query_one # SELECT avec un seul résultat
|
|
- insert # INSERT, retourne insert_id
|
|
- update # UPDATE, retourne affected_rows
|
|
- delete # DELETE, retourne affected_rows
|
|
- exec # Requête brute
|
|
- transaction # Groupe de requêtes transactionnelles
|
|
```
|
|
|
|
#### Sogoms-pdf
|
|
|
|
```yaml
|
|
actions:
|
|
- generate # Générer un PDF depuis un template
|
|
- merge # Fusionner plusieurs PDFs
|
|
- split # Séparer un PDF
|
|
- extract_text # Extraire le texte
|
|
- add_signature # Ajouter une signature
|
|
```
|
|
|
|
#### Sogoms-email
|
|
|
|
```yaml
|
|
actions:
|
|
- send # Envoyer un email
|
|
- send_bulk # Envoyer en masse
|
|
- validate # Valider une adresse email
|
|
```
|
|
|
|
#### Sogoms-storage
|
|
|
|
```yaml
|
|
actions:
|
|
- put # Stocker un fichier
|
|
- get # Récupérer un fichier
|
|
- delete # Supprimer un fichier
|
|
- list # Lister les fichiers
|
|
- get_url # Obtenir une URL signée temporaire
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Communication Inter-Processus
|
|
|
|
### 4.1 Protocole Unix Socket
|
|
|
|
Les binaires communiquent via Unix sockets avec un protocole simple basé sur JSON.
|
|
|
|
#### Format des messages
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────┐
|
|
│ 4 bytes │ N bytes │
|
|
│ Length │ JSON Payload │
|
|
└─────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
#### Requête
|
|
|
|
```json
|
|
{
|
|
"id": "req_abc123",
|
|
"action": "insert",
|
|
"tenant_id": "acme",
|
|
"params": {
|
|
"table": "tasks",
|
|
"data": {
|
|
"title": "Ma tâche",
|
|
"status": "pending"
|
|
}
|
|
},
|
|
"timeout_ms": 5000
|
|
}
|
|
```
|
|
|
|
#### Réponse
|
|
|
|
```json
|
|
{
|
|
"id": "req_abc123",
|
|
"status": "success",
|
|
"result": {
|
|
"insert_id": 42,
|
|
"affected_rows": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
```json
|
|
{
|
|
"id": "req_abc123",
|
|
"status": "error",
|
|
"error": {
|
|
"code": "DB_ERROR",
|
|
"message": "Duplicate entry for key 'title'"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4.2 Load Balancing
|
|
|
|
Sogoctl maintient un pool de connexions pour chaque service :
|
|
|
|
```go
|
|
type ServicePool struct {
|
|
name string
|
|
instances []*Instance
|
|
mu sync.RWMutex
|
|
counter uint64
|
|
}
|
|
|
|
func (p *ServicePool) Next() *Instance {
|
|
p.mu.RLock()
|
|
defer p.mu.RUnlock()
|
|
|
|
// Round-robin
|
|
idx := atomic.AddUint64(&p.counter, 1) % uint64(len(p.instances))
|
|
return p.instances[idx]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Multi-Tenancy
|
|
|
|
### 5.1 Identification du tenant
|
|
|
|
Le tenant est identifié dans cet ordre de priorité :
|
|
|
|
1. Claim JWT `tenant_id`
|
|
2. Header `X-Tenant-ID`
|
|
3. Sous-domaine (`acme.api.sogoms.com`)
|
|
4. API Key (lookup en base)
|
|
|
|
### 5.2 Configuration par tenant
|
|
|
|
```yaml
|
|
# /config/tenants/acme.yaml
|
|
|
|
tenant:
|
|
id: acme
|
|
name: ACME Corporation
|
|
domain: acme.example.com
|
|
plan: premium
|
|
status: active
|
|
|
|
database:
|
|
prefix: acme_ # Tables préfixées ou schema séparé
|
|
|
|
limits:
|
|
rate_limit: 5000/min
|
|
storage: 50GB
|
|
users: 100
|
|
api_keys: 20
|
|
|
|
features:
|
|
- pdf
|
|
- email
|
|
- storage
|
|
- custom_workflows
|
|
|
|
storage:
|
|
type: local # local | s3 | minio
|
|
config:
|
|
base_path: /data/storage/tenants/acme
|
|
|
|
customization:
|
|
branding:
|
|
logo_url: https://acme.example.com/logo.png
|
|
primary_color: "#1a73e8"
|
|
email:
|
|
from_name: ACME Platform
|
|
from_email: noreply@acme.example.com
|
|
```
|
|
|
|
### 5.3 Isolation des données
|
|
|
|
```sql
|
|
-- Chaque table inclut tenant_id
|
|
CREATE TABLE tasks (
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
tenant_id VARCHAR(50) NOT NULL,
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
status ENUM('pending', 'in_progress', 'completed') DEFAULT 'pending',
|
|
assigned_to BIGINT,
|
|
created_by BIGINT NOT NULL,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
INDEX idx_tenant (tenant_id),
|
|
INDEX idx_tenant_status (tenant_id, status)
|
|
);
|
|
|
|
-- Sogoms-db ajoute automatiquement la clause tenant_id
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Stockage Fichiers
|
|
|
|
### 6.1 Structure
|
|
|
|
```
|
|
/data/storage/
|
|
├── _system/ # Fichiers système SOGOMS
|
|
│ ├── templates/ # Templates PDF, email
|
|
│ │ ├── pdf/
|
|
│ │ │ ├── invoice.html
|
|
│ │ │ └── contract.html
|
|
│ │ └── email/
|
|
│ │ ├── welcome.html
|
|
│ │ └── task_assigned.html
|
|
│ └── tmp/ # Fichiers temporaires
|
|
│
|
|
└── tenants/
|
|
├── acme/
|
|
│ ├── documents/ # PDFs générés
|
|
│ ├── uploads/ # Fichiers uploadés
|
|
│ └── tmp/ # Temporaires du tenant
|
|
│
|
|
└── startup/
|
|
├── documents/
|
|
├── uploads/
|
|
└── tmp/
|
|
```
|
|
|
|
### 6.2 Interface Storage (évolutive)
|
|
|
|
```go
|
|
type Storage interface {
|
|
Put(ctx context.Context, path string, data []byte) error
|
|
Get(ctx context.Context, path string) ([]byte, error)
|
|
Delete(ctx context.Context, path string) error
|
|
List(ctx context.Context, prefix string) ([]string, error)
|
|
GetURL(ctx context.Context, path string, expiry time.Duration) (string, error)
|
|
}
|
|
|
|
// Implémentations disponibles
|
|
// - LocalStorage : fichiers locaux
|
|
// - S3Storage : AWS S3 / Scaleway Object Storage
|
|
// - MinioStorage : MinIO self-hosted
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Sécurité
|
|
|
|
### 7.1 Authentification JWT
|
|
|
|
```yaml
|
|
# Structure du token JWT
|
|
header:
|
|
alg: HS256
|
|
typ: JWT
|
|
|
|
payload:
|
|
sub: "user_123" # User ID
|
|
tenant: "acme" # Tenant ID
|
|
roles: ["user", "admin"] # Rôles
|
|
exp: 1704067200 # Expiration
|
|
iat: 1703980800 # Issued at
|
|
```
|
|
|
|
### 7.2 Rate Limiting
|
|
|
|
```yaml
|
|
# Par défaut
|
|
rate_limit:
|
|
default: 1000/min
|
|
|
|
# Par tenant (override)
|
|
rate_limit:
|
|
acme: 5000/min
|
|
startup: 500/min
|
|
|
|
# Par endpoint (override)
|
|
routes:
|
|
- path: /api/heavy-operation
|
|
rate_limit:
|
|
requests: 10
|
|
window: 1m
|
|
```
|
|
|
|
### 7.3 Validation des entrées
|
|
|
|
Chaque scénario valide ses inputs :
|
|
|
|
```yaml
|
|
input:
|
|
required:
|
|
- email
|
|
- password
|
|
optional:
|
|
- name
|
|
validation:
|
|
email:
|
|
type: string
|
|
format: email
|
|
password:
|
|
type: string
|
|
min_length: 8
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Structure du Projet
|
|
|
|
```
|
|
sogoms/
|
|
├── cmd/
|
|
│ ├── sogoctl/ # Superviseur
|
|
│ │ └── main.go
|
|
│ ├── sogoway/ # Gateway HTTP
|
|
│ │ └── main.go
|
|
│ ├── sogorch/ # Orchestrateur
|
|
│ │ └── main.go
|
|
│ └── sogoms/
|
|
│ ├── db/ # Microservice DB
|
|
│ │ └── main.go
|
|
│ ├── pdf/ # Microservice PDF
|
|
│ │ └── main.go
|
|
│ ├── email/ # Microservice Email
|
|
│ │ └── main.go
|
|
│ └── storage/ # Microservice Storage
|
|
│ └── main.go
|
|
│
|
|
├── internal/
|
|
│ ├── protocol/ # Protocole Unix socket
|
|
│ │ ├── message.go
|
|
│ │ ├── client.go
|
|
│ │ └── server.go
|
|
│ ├── pool/ # Load balancer interne
|
|
│ │ └── pool.go
|
|
│ ├── config/ # Lecture configs YAML
|
|
│ │ ├── config.go
|
|
│ │ ├── tenant.go
|
|
│ │ └── routes.go
|
|
│ ├── scenario/ # Exécution scénarios
|
|
│ │ ├── parser.go
|
|
│ │ ├── executor.go
|
|
│ │ └── context.go
|
|
│ ├── auth/ # JWT, API Keys
|
|
│ │ ├── jwt.go
|
|
│ │ └── apikey.go
|
|
│ └── registry/ # Registry des instances
|
|
│ └── registry.go
|
|
│
|
|
├── pkg/
|
|
│ └── logger/ # Logger partagé
|
|
│ └── logger.go
|
|
│
|
|
├── config/
|
|
│ ├── sogoctl.yaml # Config superviseur
|
|
│ ├── sogoway.yaml # Config gateway
|
|
│ ├── tenants/ # Configs tenants
|
|
│ │ ├── acme.yaml
|
|
│ │ └── startup.yaml
|
|
│ ├── routes/ # Routes par application
|
|
│ │ └── prokov.yaml
|
|
│ └── scenarios/ # Scénarios
|
|
│ ├── create_task.yaml
|
|
│ ├── update_task.yaml
|
|
│ └── delete_task.yaml
|
|
│
|
|
├── scripts/
|
|
│ ├── build.sh # Build tous les binaires
|
|
│ ├── install.sh # Installation dans container
|
|
│ └── dev.sh # Lancement dev local
|
|
│
|
|
├── deploy/
|
|
│ └── incus/
|
|
│ ├── setup-gw3.sh # Setup container gw3
|
|
│ └── setup-redis3.sh # Setup container redis3
|
|
│
|
|
├── go.mod
|
|
├── go.sum
|
|
├── Makefile
|
|
└── README.md
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Déploiement
|
|
|
|
### 9.1 Build
|
|
|
|
```makefile
|
|
# Makefile
|
|
|
|
BINARIES = sogoctl sogoway sogorch sogoms-db sogoms-pdf sogoms-email sogoms-storage
|
|
VERSION = $(shell git describe --tags --always)
|
|
LDFLAGS = -s -w -X main.version=$(VERSION)
|
|
|
|
.PHONY: all clean $(BINARIES)
|
|
|
|
all: $(BINARIES)
|
|
|
|
sogoctl:
|
|
CGO_ENABLED=0 GOOS=linux go build -ldflags="$(LDFLAGS)" -o dist/sogoctl ./cmd/sogoctl
|
|
|
|
sogoway:
|
|
CGO_ENABLED=0 GOOS=linux go build -ldflags="$(LDFLAGS)" -o dist/sogoway ./cmd/sogoway
|
|
|
|
sogorch:
|
|
CGO_ENABLED=0 GOOS=linux go build -ldflags="$(LDFLAGS)" -o dist/sogorch ./cmd/sogorch
|
|
|
|
sogoms-%:
|
|
CGO_ENABLED=0 GOOS=linux go build -ldflags="$(LDFLAGS)" -o dist/sogoms-$* ./cmd/sogoms/$*
|
|
|
|
clean:
|
|
rm -rf dist/*
|
|
|
|
install: all
|
|
scp dist/* gw3:/opt/sogoms/bin/
|
|
ssh gw3 'sogoctl restart all'
|
|
```
|
|
|
|
### 9.2 Setup Container Incus
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# deploy/incus/setup-gw3.sh
|
|
|
|
# Créer le container
|
|
incus launch images:alpine/3.21 gw3
|
|
|
|
# Configurer l'IP fixe
|
|
incus config device override gw3 eth0 ipv4.address=13.23.33.5
|
|
|
|
# Créer les dossiers
|
|
incus exec gw3 -- mkdir -p /opt/sogoms/bin
|
|
incus exec gw3 -- mkdir -p /config
|
|
incus exec gw3 -- mkdir -p /data/storage/tenants
|
|
incus exec gw3 -- mkdir -p /run
|
|
incus exec gw3 -- mkdir -p /var/log/sogoms
|
|
|
|
# Installer les dépendances (pour sogoms-pdf notamment)
|
|
incus exec gw3 -- apk add --no-cache \
|
|
chromium \
|
|
font-noto \
|
|
font-noto-emoji
|
|
|
|
# Copier les binaires
|
|
incus file push dist/* gw3/opt/sogoms/bin/
|
|
|
|
# Copier les configs
|
|
incus file push -r config/* gw3/config/
|
|
|
|
# Configurer sogoctl comme service init
|
|
incus exec gw3 -- sh -c 'cat > /etc/init.d/sogoms << EOF
|
|
#!/sbin/openrc-run
|
|
command=/opt/sogoms/bin/sogoctl
|
|
command_args="--config /config/sogoctl.yaml"
|
|
pidfile=/run/sogoctl.pid
|
|
EOF'
|
|
|
|
incus exec gw3 -- chmod +x /etc/init.d/sogoms
|
|
incus exec gw3 -- rc-update add sogoms default
|
|
|
|
# Démarrer
|
|
incus exec gw3 -- rc-service sogoms start
|
|
```
|
|
|
|
### 9.3 Config Nginx Host
|
|
|
|
```nginx
|
|
# /etc/nginx/sites-available/sogoms
|
|
|
|
upstream sogoms_gateway {
|
|
server 13.23.33.5:8080;
|
|
keepalive 16;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name api.sogoms.com api-dev.sogoms.com;
|
|
|
|
ssl_certificate /etc/letsencrypt/live/sogoms.com/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/sogoms.com/privkey.pem;
|
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
|
|
|
access_log /var/log/nginx/sogoms.access.log;
|
|
error_log /var/log/nginx/sogoms.error.log;
|
|
|
|
location / {
|
|
proxy_pass http://sogoms_gateway;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_set_header Connection "";
|
|
|
|
proxy_connect_timeout 10s;
|
|
proxy_send_timeout 60s;
|
|
proxy_read_timeout 60s;
|
|
}
|
|
|
|
location /ws/ {
|
|
proxy_pass http://sogoms_gateway;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_set_header Host $host;
|
|
proxy_read_timeout 86400;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Monitoring
|
|
|
|
### 10.1 Métriques (via Sogoctl)
|
|
|
|
```bash
|
|
# API Admin :9000
|
|
|
|
GET /metrics # Prometheus format
|
|
GET /health # Health check global
|
|
GET /status # Status détaillé JSON
|
|
GET /services # Liste des services et instances
|
|
GET /services/{name} # Détail d'un service
|
|
```
|
|
|
|
### 10.2 Logs
|
|
|
|
```bash
|
|
# Logs centralisés par Sogoctl
|
|
/var/log/sogoms/
|
|
├── sogoctl.log
|
|
├── sogoway.log
|
|
├── sogorch.log
|
|
├── sogoms-db.log
|
|
├── sogoms-pdf.log
|
|
├── sogoms-email.log
|
|
└── sogoms-storage.log
|
|
```
|
|
|
|
### 10.3 SOGOMS Vigil
|
|
|
|
Pour un monitoring avancé multi-hosts avec agents, voir **[sogoms-vigil.md](sogoms-vigil.md)**.
|
|
|
|
---
|
|
|
|
## 11. Roadmap
|
|
|
|
### Phase 1 : Foundation (MVP)
|
|
|
|
- [ ] Sogoctl : superviseur basique (start/stop/restart)
|
|
- [ ] Sogoway : routing, auth JWT
|
|
- [ ] Sogorch : exécution scénarios simples
|
|
- [ ] Sogoms-db : CRUD MariaDB
|
|
- [ ] Protocole Unix socket
|
|
- [ ] Config YAML (routes + scénarios)
|
|
|
|
### Phase 2 : Features
|
|
|
|
- [ ] Multi-tenant complet
|
|
- [ ] Sogoms-pdf : génération PDF
|
|
- [ ] Sogoms-email : envoi emails
|
|
- [ ] Sogoms-storage : gestion fichiers
|
|
- [ ] Rate limiting Redis
|
|
- [ ] Sogoctl : scaling dynamique
|
|
|
|
### Phase 3 : Production
|
|
|
|
- [ ] Health checks avancés
|
|
- [ ] Métriques Prometheus
|
|
- [ ] Autoscaling basé sur métriques
|
|
- [ ] Hot reload des configs
|
|
- [ ] Dashboard admin
|
|
|
|
### Phase 4 : Enterprise
|
|
|
|
- [ ] Workflows complexes (conditions, boucles, parallélisme)
|
|
- [ ] API Keys management
|
|
- [ ] Webhooks
|
|
- [ ] Multi-région
|
|
- [ ] Audit logs
|
|
|
|
---
|
|
|
|
## 12. Références
|
|
|
|
- [Go Chi Router](https://github.com/go-chi/chi) - HTTP routing
|
|
- [Go YAML v3](https://github.com/go-yaml/yaml) - Parsing YAML
|
|
- [Go MariaDB Driver](https://github.com/go-sql-driver/mysql) - Accès MariaDB
|
|
- [Chromedp](https://github.com/chromedp/chromedp) - Génération PDF
|
|
- [Incus Documentation](https://linuxcontainers.org/incus/docs/main/) - Containers
|
|
|
|
---
|
|
|
|
**Website** : https://sogoms.com
|
|
**Documentation** : https://docs.sogoms.com
|
|
**API** : https://api.sogoms.com
|
|
|
|
*Document mis à jour le 2025-01-15 - Version 2.0.0*
|