# Architecture Go + htmx (sogoms-admin)

Guide pour comprendre et modifier l'interface d'administration SOGOMS.

## Vue d'ensemble

```
Browser (htmx)  ←→  Go Server  ←→  Services (sockets)
     │                  │
     │   HTTP GET/POST  │
     ▼                  ▼
  Templates         Handlers
  (HTML)            (Go)
```

**Stack :**
- **Backend** : Go net/http (pas de framework)
- **Frontend** : Go templates + htmx + Pico.css
- **Principe** : Le serveur renvoie des fragments HTML, htmx les injecte dans le DOM

---

## Structure des fichiers

```
cmd/sogoms/admin/
├── main.go           # Point d'entrée, routes, config
├── handlers.go       # Handlers HTTP (logique métier)
├── middleware.go     # Auth, CSRF, logging, rate limiting
├── session.go        # Gestion des sessions
├── services.go       # Appels vers microservices (sockets)
└── templates/
    ├── layout.html           # Layout commun (head, nav, footer)
    ├── login.html            # Page de connexion
    ├── dashboard.html        # Dashboard principal
    └── partials/             # Fragments htmx
        ├── apps_list.html
        └── services_status.html
```

---

## Flux de données

### 1. Requête initiale (page complète)

```
GET /admin/
    │
    ▼
main.go:103 ─────────────────────────────────────────────┐
│ mux.HandleFunc("GET /admin/", AuthMiddleware(...))    │
└───────────────────────────────────────────────────────┘
    │
    ▼
handlers.go:114-138 ─────────────────────────────────────┐
│ func HandleDashboard(w, r) {                          │
│     data := map[string]any{                           │
│         "Title": "Dashboard",                         │
│         "Apps":  accessibleApps,                      │
│         ...                                           │
│     }                                                 │
│     s.render(w, "dashboard.html", data)               │
│ }                                                     │
└───────────────────────────────────────────────────────┘
    │
    ▼
templates/dashboard.html ────────────────────────────────┐
│ {{template "layout" .}}                               │
│ <h1>Dashboard</h1>                                    │
│ <div hx-get="/admin/api/services/health"             │
│      hx-trigger="load">                               │
│     Chargement...                                     │
│ </div>                                                │
└───────────────────────────────────────────────────────┘
```

### 2. Requête htmx (fragment)

```
hx-get="/admin/api/services/health"
    │
    ▼
main.go:109 ─────────────────────────────────────────────┐
│ mux.HandleFunc("GET /admin/api/services/health", ...) │
└───────────────────────────────────────────────────────┘
    │
    ▼
handlers.go:172-193 ─────────────────────────────────────┐
│ func HandleAPIServicesHealth(w, r) {                  │
│     statuses := s.services.HealthCheck()              │
│     data := map[string]any{"Services": statuses}      │
│     s.render(w, "partials/services_status.html", data)│
│ }                                                     │
└───────────────────────────────────────────────────────┘
    │
    ▼
templates/partials/services_status.html ─────────────────┐
│ <ul>                                                  │
│     {{range .Services}}                               │
│     <li>{{.Name}} - {{if .Available}}OK{{end}}</li>  │
│     {{end}}                                           │
│ </ul>                                                 │
└───────────────────────────────────────────────────────┘
    │
    ▼
htmx remplace le contenu du <div> avec ce fragment
```

---

## Attributs htmx essentiels

| Attribut | Description | Exemple |
|----------|-------------|---------|
| `hx-get` | GET AJAX vers URL | `hx-get="/admin/api/apps"` |
| `hx-post` | POST AJAX vers URL | `hx-post="/admin/api/apps/create"` |
| `hx-trigger` | Quand déclencher | `load`, `click`, `every 30s`, `submit` |
| `hx-target` | Où injecter la réponse | `hx-target="#result"` (défaut: élément courant) |
| `hx-swap` | Comment injecter | `innerHTML` (défaut), `outerHTML`, `beforeend` |
| `hx-indicator` | Spinner pendant chargement | `hx-indicator=".loading"` |
| `hx-confirm` | Confirmation avant action | `hx-confirm="Supprimer ?"` |

### Exemples

```html
<!-- Charger au chargement de la page -->
<div hx-get="/admin/api/apps" hx-trigger="load">
    Chargement...
</div>

<!-- Rafraîchir toutes les 30 secondes -->
<div hx-get="/admin/api/services/health"
     hx-trigger="load, every 30s">
</div>

<!-- Soumettre un formulaire en AJAX -->
<form hx-post="/admin/api/apps/create"
      hx-target="#apps-list"
      hx-swap="beforeend">
    <input name="name" required>
    <button type="submit">Créer</button>
</form>

<!-- Supprimer avec confirmation -->
<button hx-delete="/admin/api/apps/123"
        hx-confirm="Supprimer cette app ?"
        hx-target="closest li"
        hx-swap="outerHTML">
    Supprimer
</button>
```

---

## Templates Go

### Syntaxe de base

```html
<!-- Variable -->
{{.Title}}

<!-- Condition -->
{{if .IsSuperAdmin}}
    Super Admin
{{else}}
    App Admin
{{end}}

<!-- Boucle -->
{{range .Apps}}
    <li>{{.Name}}</li>
{{end}}

<!-- Inclusion de template -->
{{template "layout" .}}

<!-- Bloc définissable -->
{{define "content"}}
    Contenu ici
{{end}}
```

### Structure layout.html

```html
{{define "layout"}}
<!DOCTYPE html>
<html>
<head>
    <title>{{.Title}} - SOGOMS Admin</title>
    <script src="https://unpkg.com/htmx.org@1.9.10"></script>
    <link rel="stylesheet" href="https://unpkg.com/@picocss/pico@1/css/pico.min.css">
</head>
<body>
    <nav>...</nav>
    <main class="container">
        {{template "content" .}}
    </main>
</body>
</html>
{{end}}
```

### Structure page (dashboard.html)

```html
{{define "dashboard.html"}}
{{template "layout" .}}
{{end}}

{{define "content"}}
<h1>Dashboard</h1>
<!-- contenu de la page -->
{{end}}
```

---

## Ajouter une nouvelle fonctionnalité

### Exemple : Liste des jobs cron

**1. Créer le partial** `templates/partials/cron_jobs.html`

```html
{{define "partials/cron_jobs.html"}}
<table>
    <thead>
        <tr>
            <th>Job</th>
            <th>Schedule</th>
            <th>Prochain run</th>
        </tr>
    </thead>
    <tbody>
        {{range .Jobs}}
        <tr>
            <td>{{.Name}}</td>
            <td><code>{{.Schedule}}</code></td>
            <td>{{.NextRun}}</td>
        </tr>
        {{end}}
    </tbody>
</table>
{{end}}
```

**2. Ajouter le handler** dans `handlers.go`

```go
func (s *AdminServer) HandleAPICronJobs(w http.ResponseWriter, r *http.Request) {
    user := GetUserFromContext(r.Context())
    if user == nil {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)
        return
    }

    jobs, err := s.services.GetCronJobs()
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    data := map[string]any{
        "Jobs": jobs,
    }

    s.render(w, "partials/cron_jobs.html", data)
}
```

**3. Ajouter la route** dans `main.go`

```go
mux.HandleFunc("GET /admin/api/cron/jobs",
    AuthMiddleware(sessions, adminCfg, server.HandleAPICronJobs))
```

**4. Utiliser dans le dashboard** `templates/dashboard.html`

```html
<article>
    <header><strong>Jobs Cron</strong></header>
    <div hx-get="/admin/api/cron/jobs" hx-trigger="load">
        Chargement...
    </div>
</article>
```

---

## Mode développement

Le flag `-dev` recharge les templates à chaque requête :

```yaml
# config/sogoctl.yaml
sogoms-admin:
  args:
    - "-templates"
    - "/config/admin/templates"
    - "-dev"  # ← rechargement auto
```

**Workflow dev :**

```bash
# 1. Modifier un template localement
vim cmd/sogoms/admin/templates/dashboard.html

# 2. Déployer les templates (sans recompilation)
./deploy-admin.sh

# 3. Rafraîchir le navigateur → changements visibles
```

**Pour la prod**, retirer `-dev` (templates chargés une fois au démarrage).

---

## Fichiers de configuration

| Fichier | Rôle |
|---------|------|
| `/secrets/admin_users.yaml` | Users, passwords, rôles |
| `/secrets/admin_session_secret` | Clé HMAC pour cookies |
| `/config/sogoctl.yaml` | Args de sogoms-admin |
| `/config/admin/templates/` | Templates HTML (si -templates) |

---

## Ressources

- **htmx** : https://htmx.org/docs/
- **Pico.css** : https://picocss.com/docs/
- **Go templates** : https://pkg.go.dev/html/template
