Files
sogoms/DOCTECH.md
Pierre 65da4efdad SOGOMS v1.0.3 - Admin UI, Cron, Config reload
Phase 13 : sogoms-cron
- Jobs planifiés avec schedule cron standard
- Types: query_email, http, service
- Actions: list, trigger, status

Phase 16 : Réorganisation config/apps/{app}/
- Tous les fichiers d'une app dans un seul dossier
- Migration prokov vers nouvelle structure

Phase 17 : sogoms-admin
- Interface web d'administration (Go templates + htmx)
- Auth sessions cookies signées HMAC-SHA256
- Rôles super_admin / app_admin avec permissions

Phase 19 : Création d'app via Admin UI
- Formulaire création app avec config DB/auth
- Bouton "Scanner la base" : introspection + schema.yaml
- Rechargement automatique sogoway via SIGHUP

Infrastructure :
- sogoctl : socket de contrôle /run/sogoctl.sock
- sogoway : reload config sur SIGHUP sans restart

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 20:30:56 +01:00

17 KiB

SOGOMS - Documentation Technique

Service Oriented GO MicroServices - Plateforme SaaS modulaire multi-tenant.

Version: 1.0.1 Date: 16 décembre 2025


Table des matières

  1. Architecture
  2. Services
  3. Communication IPC
  4. Configuration
  5. API REST
  6. Système de Queries
  7. Authentification
  8. Déploiement
  9. Structure du projet

Architecture

Client → Nginx(:443) → Sogoway(:8080) → Sogoms-* → MariaDB
                              ↓
                        Unix Sockets
                     /run/sogoms-*.sock

Flux de données

  1. Client envoie requête HTTPS vers Nginx
  2. Nginx route /api/* vers sogoway:8080
  3. Sogoway identifie l'app par hostname, valide JWT, route vers le bon service
  4. Sogoms-db exécute les requêtes SQL
  5. Sogoms-logs enregistre événements et erreurs

Principes

  • Modularité : 1 feature = 1 binaire Go
  • Configuration YAML : requêtes SQL externalisées, pas de recompilation
  • Multi-tenant : isolation par user_id, filtrage configurable par rôle
  • Supervision : sogoctl gère le cycle de vie des services

Services

Binaire Rôle Port/Socket
sogoctl Superviseur PID 1, health checks, restart auto -
sogoway Gateway HTTP, auth JWT, routing CRUD TCP :8080
sogoms-db Accès MariaDB, pool par application /run/sogoms-db.1.sock
sogoms-logs Logging centralisé, rotation auto /run/sogoms-logs.1.sock
sogoms-smtp Envoi d'emails, templates YAML /run/sogoms-smtp.1.sock
sogoms-cron Tâches planifiées, jobs périodiques /run/sogoms-cron.1.sock
sogoms-admin Interface web d'administration TCP :9000

sogoctl (Superviseur)

  • Démarre les services dans l'ordre des dépendances
  • Health checks périodiques (socket ou HTTP)
  • Redémarrage automatique en cas de crash
  • Arrêt gracieux sur SIGTERM/SIGINT
  • Socket de contrôle /run/sogoctl.sock pour commandes runtime :
    • reload <service> : envoie SIGHUP au service (rechargement config)
    • status : affiche l'état des services
# config/sogoctl.yaml
supervisor:
  health_interval: 10s
  restart_delay: 2s
  max_restarts: 5

services:
  sogoms-logs:
    binary: /opt/sogoms/bin/sogoms-logs
    args: ["-config", "/config", "-socket", "/run/sogoms-logs.1.sock"]
    health_socket: /run/sogoms-logs.1.sock

  sogoms-db:
    binary: /opt/sogoms/bin/sogoms-db
    args: ["-config", "/config", "-socket", "/run/sogoms-db.1.sock"]
    health_socket: /run/sogoms-db.1.sock
    depends_on: [sogoms-logs]

  sogoway:
    binary: /opt/sogoms/bin/sogoway
    args: ["-config", "/config", "-port", "8080"]
    health_url: http://localhost:8080/health
    depends_on: [sogoms-db, sogoms-logs]

sogoway (Gateway HTTP)

  • Routing par hostname → charge la config de l'app
  • Authentification JWT (HS256)
  • CRUD générique paramétré par YAML
  • Logging des événements (login, register)
  • Rechargement à chaud : SIGHUP recharge registry + JWT sans restart

sogoms-db (Base de données)

Actions disponibles :

  • query : SELECT multi-résultats
  • query_one : SELECT un résultat
  • insert : INSERT, retourne insert_id
  • update : UPDATE, retourne affected_rows
  • delete : DELETE, retourne affected_rows
  • health : ping DB

sogoms-logs (Logging)

Actions disponibles :

  • log_event : événement applicatif (login, register, etc.)
  • log_error : erreur avec niveau (error, warn, info)
  • health : statut OK

Fichiers générés : /var/log/sogoms/{app}-{YYYYMMDD}-{type}.log

Format : JSON, une ligne par entrée

Rotation : suppression automatique des fichiers > 30 jours (configurable)

sogoms-smtp (Emails)

Actions disponibles :

  • send : envoi email simple (to, subject, body, body_html)
  • send_template : envoi avec template YAML
  • send_bulk : envoi en masse (tableau de destinataires)
  • health : statut OK

Configuration SMTP dans config/routes/{app}.yaml :

smtp:
  host: mail.example.com
  port: 587
  user: noreply@example.com
  password_file: /secrets/{app}_smtp_pass
  from: noreply@example.com
  from_name: Mon App
  tls: false  # false = STARTTLS (587), true = TLS (465)

Templates dans config/emails/{app}/*.yaml :

subject: "Bienvenue {{.Name}} !"
body: |
  Bonjour {{.Name}},
  Bienvenue sur notre plateforme.
body_html: |
  <h1>Bienvenue {{.Name}} !</h1>
  <p>Bienvenue sur notre plateforme.</p>

sogoms-cron (Tâches planifiées)

Exécute des jobs périodiques définis en YAML avec support cron standard.

Actions disponibles :

  • list : liste les jobs configurés avec prochain run
  • trigger : déclenche un job manuellement
  • status : historique des dernières exécutions
  • health : statut OK

Types de jobs :

  • query_email : requête DB + envoi email groupé par utilisateur
  • http : appel HTTP (GET/POST) vers endpoint interne ou externe
  • service : appel service interne (sogoms-db, sogoms-smtp, etc.)

Configuration dans config/apps/{app}/cron.yaml :

timezone: Europe/Paris
retry:
  max_attempts: 3
  delay: 5m
history_days: 7

jobs:
  tasks_today:
    schedule: "0 8 * * 1-5"    # 8h00 lun-ven
    type: query_email
    query: |
      SELECT u.id AS user_id, u.email, u.name AS user_name,
             t.title, p.name AS project_name, s.name AS status_name
      FROM users u
      INNER JOIN tasks t ON t.user_id = u.id
      LEFT JOIN projects p ON t.project_id = p.id
      LEFT JOIN statuses s ON t.status_id = s.id
      WHERE t.date_end <= CURDATE()
    group_by: user_id
    template: tasks_today
    enabled: true

Format cron : minute heure jour mois jour_semaine

  • 0 8 * * 1-5 : 8h00 du lundi au vendredi
  • */15 * * * * : toutes les 15 minutes
  • 0 9 1 * * : 9h00 le premier de chaque mois

sogoms-admin (Interface web)

Interface d'administration web pour gérer les applications SOGOMS.

Rôles :

  • super_admin : accès global à toutes les apps et services
  • app_admin : accès limité aux apps assignées avec permissions fines

Stack :

  • Backend : Go net/http
  • Frontend : Go templates + htmx + Pico.css (embarqués via go:embed)
  • Auth : sessions cookies signées (HMAC-SHA256)

Sécurité :

  • Passwords : bcrypt cost=12
  • Sessions : Cookie HttpOnly + Secure + SameSite=Strict
  • CSRF : Token par session
  • Rate limiting : 5 tentatives/min par IP

Routes :

  • GET /admin/login : page de connexion
  • POST /admin/login : authentification
  • GET /admin/ : dashboard principal
  • POST /admin/logout : déconnexion
  • GET /admin/api/apps : liste apps (htmx partial)
  • GET /admin/api/services/health : statut services (htmx partial)

Configuration :

# /secrets/admin_users.yaml
session:
  secret_file: /secrets/admin_session_secret
  max_age: 3600
  cookie_name: sogoms_admin_sid

rate_limit:
  login_max: 5
  login_window: 60

users:
  - username: pierre
    password_hash: "$2a$12$..."
    role: super_admin
    email: pierre@example.com

  - username: client1
    password_hash: "$2a$12$..."
    role: app_admin
    apps: [prokov]
    permissions:
      - schema:read
      - queries:read
      - cron:read
      - logs:read

Permissions disponibles :

  • schema:read/write/upload : gestion schema
  • queries:read/write : requêtes SQL
  • emails:read/write : templates email
  • cron:read/write/trigger : jobs cron
  • logs:read : consultation logs
  • db:introspect : introspection DB
  • * : toutes (super_admin)

Accès externe : admin.sogoms.com via Nginx → :9000


Communication IPC

Protocole Unix socket avec messages JSON length-prefixed :

[4 bytes: longueur BigEndian] [payload JSON]

Request

{
  "id": "req_20251216123456.000000",
  "action": "query",
  "params": {
    "app_id": "prokov",
    "query": "SELECT * FROM users WHERE id = ?",
    "args": [1]
  }
}

Response (succès)

{
  "id": "req_...",
  "status": "success",
  "result": { ... }
}

Response (erreur)

{
  "id": "req_...",
  "status": "error",
  "error": {
    "code": "DB_ERROR",
    "message": "connection refused"
  }
}

Configuration

Structure

config/
├── sogoctl.yaml              # Superviseur
├── routes/
│   └── prokov.yaml           # Config app (DB, auth, routes)
└── queries/
    └── prokov/
        ├── auth.yaml         # Requêtes authentification
        ├── projects.yaml     # CRUD projects
        ├── tasks.yaml        # CRUD tasks
        ├── tags.yaml         # CRUD tags
        └── statuses.yaml     # CRUD statuses

Config application (routes/prokov.yaml)

app: prokov
version: "1.0"
base_path: /api

hosts:
  - prokov.unikoffice.com
  - prokov.sogoms.com

database:
  host: 13.23.33.4
  port: 3306
  user: prokov_user
  password_file: /secrets/prokov_db_pass
  name: prokov

auth:
  jwt_secret_file: /secrets/prokov_jwt_secret
  jwt_expiry: 24h

logs:
  retention_days: 30

API REST

Authentification

Méthode Endpoint Auth Description
POST /api/auth/register Non Inscription
POST /api/auth/login Non Connexion
POST /api/auth/logout Oui Déconnexion
GET /api/auth/me Oui User courant

Login - Réponse enrichie

{
  "success": true,
  "message": "Connexion réussie",
  "data": {
    "token": "eyJ...",
    "user": { "id": 1, "email": "...", "name": "..." },
    "projects": [...],
    "tasks": [...],
    "tags": [...],
    "statuses": [...]
  }
}

CRUD Générique

Méthode Endpoint Action
GET /api/{resource} Liste
GET /api/{resource}/{id} Détail
POST /api/{resource} Création
PUT /api/{resource}/{id} Modification
DELETE /api/{resource}/{id} Suppression

Resources disponibles : projects, tasks, tags, statuses

Réponses standardisées

Succès :

{
  "success": true,
  "message": "Created",
  "data": { "insert_id": 123 }
}

Erreur :

{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Token expired"
  }
}

Système de Queries

Les requêtes SQL sont externalisées dans des fichiers YAML pour éviter la recompilation.

Structure Read (list/show)

list:
  query: >
    SELECT id, name, description FROM projects
  filters:
    default: "user_id = :user_id"
    admin: ""
  order: "position ASC"

show:
  query: >
    SELECT id, name, description FROM projects WHERE id = :id
  filters:
    default: "user_id = :user_id"
    admin: ""

Structure CUD (create/update/delete)

create:
  table: projects
  fields:
    - user_id
    - name
    - description
    - position

update:
  table: projects
  fields:
    - name
    - description
    - position
  filters:
    default: "user_id = :user_id"
    admin: ""

delete:
  table: projects
  filters:
    default: "user_id = :user_id"
    admin: ""

Placeholders

  • :user_id → ID utilisateur depuis JWT
  • :id → ID ressource depuis URL
  • :project_id → ID projet (pour filtres)

Filtres par rôle

Le filtre appliqué dépend du rôle de l'utilisateur :

  • default : utilisateur standard, filtré par user_id
  • admin : pas de filtre, voit tout

Authentification

JWT (JSON Web Token)

  • Algorithme : HS256
  • Expiration : configurable (défaut 24h)
  • Secret : stocké dans fichier (/secrets/{app}_jwt_secret)

Payload JWT

{
  "sub": 1,
  "email": "user@example.com",
  "name": "User Name",
  "app": "prokov",
  "exp": 1765959278,
  "iat": 1765872878
}

Header HTTP

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Sécurité

  • Passwords hashés avec bcrypt
  • JWT stateless (pas de stockage serveur)
  • Secrets dans fichiers séparés (pas dans YAML)
  • Filtrage user_id automatique sur toutes les requêtes CRUD

Déploiement

Script deploy.sh

./deploy.sh

Étapes :

  1. Build des binaires (linux/amd64)
  2. Création des archives tar.gz
  3. Copie vers jump server (IN3)
  4. Déploiement dans container Incus (gw3)
  5. Backup local des archives
  6. Redémarrage automatique de sogoctl

Cible

  • Jump host : IN3 (195.154.80.116)
  • Container : gw3 (Alpine, 13.23.33.5)
  • Binaires : /opt/sogoms/bin/
  • Config : /config/
  • Secrets : /secrets/
  • Logs : /var/log/sogoms/

Commandes manuelles sur gw3

# Voir les logs
tail -f /var/log/sogoms/sogoctl.log

# Lister les processus
pgrep -la sogo

# Redémarrer
pkill -9 sogo && /opt/sogoms/bin/sogoctl &

Structure du projet

sogoms/
├── cmd/
│   ├── sogoctl/main.go           # Superviseur
│   ├── sogoway/main.go           # Gateway HTTP
│   └── sogoms/
│       ├── db/main.go            # Microservice DB
│       ├── logs/main.go          # Microservice Logs
│       ├── smtp/main.go          # Microservice SMTP
│       ├── cron/main.go          # Microservice Cron
│       └── admin/                # Interface web admin
│           ├── main.go
│           ├── handlers.go
│           ├── middleware.go
│           ├── session.go
│           ├── services.go
│           └── templates/
├── internal/
│   ├── protocol/
│   │   ├── message.go            # Structs Request/Response
│   │   ├── server.go             # Serveur Unix socket
│   │   └── client.go             # Client + Pool connexions
│   ├── config/
│   │   └── config.go             # Registry, Queries, CUD
│   ├── cron/
│   │   └── scheduler.go          # Parser cron, calcul next run
│   ├── auth/
│   │   ├── jwt.go                # Génération/validation JWT
│   │   └── password.go           # Hash bcrypt
│   ├── admin/
│   │   ├── config.go             # Chargement admin_users.yaml
│   │   ├── permissions.go        # Vérification droits
│   │   └── audit.go              # Logging actions
│   └── version/
│       └── version.go            # Version, BuildTime
├── config/
│   ├── sogoctl.yaml
│   └── apps/
│       └── prokov/
│           ├── app.yaml          # Config app (DB, auth, SMTP)
│           ├── schema.yaml       # Schema DB généré
│           ├── cron.yaml         # Jobs planifiés
│           ├── queries/          # Requêtes SQL
│           │   ├── auth.yaml
│           │   ├── projects.yaml
│           │   └── ...
│           └── emails/           # Templates email
│               ├── welcome.yaml
│               └── tasks_today.yaml
├── bin/                          # Binaires compilés
├── deploy.sh                     # Script déploiement
├── VERSION                       # Numéro de version
├── go.mod
├── go.sum
├── README.md
├── CLAUDE.md                     # Instructions Claude Code
├── DOCTECH.md                    # Documentation technique
└── TODO.md                       # Roadmap

Dépendances Go

go 1.24.0

github.com/go-sql-driver/mysql v1.9.3
gopkg.in/yaml.v3 v3.0.1
golang.org/x/crypto v0.46.0

Roadmap

Services planifiés

Phase Service Description
11 sogoms-crypt Chiffrement/déchiffrement données sensibles (AES-256-GCM)
12b sogoms-imap Lecture boîtes email (IMAP)
12c sogoms-mailproc Traitement emails (règles, webhooks)
13 sogoms-cron Tâches planifiées (format cron standard)
14 sogoms-push Push temps réel via MQTT (Mosquitto)
15 sogoms-schema Génération d'API depuis schéma YAML

Vision Phase 15 : Schema-Driven API

# config/schema/monapp.yaml - 1 fichier = 1 API complète
tables:
  users:
    fields:
      id: { type: int, primary: true, auto: true }
      email: { type: string, unique: true, auth: login }
      password: { type: string, auth: password, hidden: true }

  projects:
    fields:
      id: { type: int, primary: true, auto: true }
      user_id: { type: int, foreign: users.id, filter: owner }
      name: { type: string, required: true }
    crud: [list, show, create, update, delete]

Génère automatiquement : routes, queries, validation, filtres user_id, auth.

Hors scope V1

  • sogorch (orchestrateur scénarios)
  • sogoms-pdf, sogoms-storage
  • Multi-tenant avancé (workspaces, partage)
  • Rate limiting
  • Rôles utilisateurs (admin, manager, user)