# 09-activity – Spécifications techniques

## 1. Modèle d’événement

- Entrée canonique :

```json
{
  "id": "uuid",
  "boardId": "123",
  "actorId": "user-1",
  "kind": "command",
  "subkind": "structure.move",
  "timestamp": 1736463600,
  "nodeRefs": ["node-a", "node-b"],    // optionnel
  "runId": "run-123",                  // optionnel (Interactions/Logic)
  "status": "success|partial|failed",
  "code": "STATE_CONFLICT",
  "message": "Lisible",
  "details": { "...": "..." }
}
```

- `subkind` est strictement enuméré ; exemples et champs obligatoires :
  - `structure.move` : `fromParent`, `toParent`, `fromPos`, `toPos`.
  - `structure.rename` : `titleBefore`, `titleAfter`.
  - `structure.create/delete` : `nodeId`, `parentId`, `position`.
  - `state.change` : `from`, `to`.
  - `progress.set` : `from`, `to`, `max?`.
  - `deadline.set` : `category`, `from`, `to`.
  - `relation.created/deleted` : `from`, `to`, `kind`.
  - `interaction.run` : `runId`, `actionId`, `status`, `actionsSuccess`, `actionsFailed`, `reason`, `budgetUsed/Limit`.
  - `logic.rule` : `ruleId`, `status`, `actionsSuccess`, `actionsFailed`, `reason`, `budgetUsed/Limit`.
  - `teams.roleChanged/invite/deny/grant` : infos rôle/scope.
  - `community.publish/import/fork/unpublish` : `sourceBoardId`, `publicBoardId?`, `targetBoardId?`.
- Chaque `subkind` DOIT respecter ce contrat minimal de champs dans `details` ; les consommateurs peuvent se baser dessus sans heuristique.
- `nodeRefs` liste les nodes concernés (pour filtrage ciblé).
- `runId` relie les événements d’un même run Interactions/Logique.

## 2. Filtrage par Teams (projection)

- Projection basée sur les droits **courants** du lecteur :
  - événements touchant uniquement des nodes invisibles → masqués totalement (aucun stub, aucun compteur “caché”),
  - mix visible/invisible → seules les références visibles sont projetées, sans mention de volume masqué,
  - `actorId` invisible/supprimé → rendu générique (pseudonyme “hidden”), pas de fuite d’ID,
  - redaction des champs sensibles (contenu, tags non visibles) dans `details`.
- Les journaux peuvent diverger entre utilisateurs.
- La réponse API PEUT porter :
  - un flag `partial: true` si la projection ou la rétention ont supprimé des événements pour le lecteur,
  - un tableau optionnel `partialReasons: ["permissions","retention", ...]` pour le debug/admin, sans révéler combien ni quels événements manquent.

## 3. Lisibilité / anti-bruit

- Regroupements par jour/utilisateur/type ; coalescing lecture sur fenêtre courte (ex. 60s) pour `progress.set`, `state.change` répétés sur le même node.
- Résumé “replié” par défaut, avec détail déroulable.
- Pagination obligatoire ; horizon par défaut 90 jours configurable par board (requête au-delà → code explicite).
 - Le back ne coalesce pas les entrées stockées ; il fournit `timestamp`, `nodeRefs`, `kind/subkind` pour permettre un regroupement côté UI.

## 4. Points d’intégration

- **CommandBus** : chaque commande logge un événement (succès ou échec) selon la taxonomie.
- **Interactions/Logic** : chaque run logge un `interaction.run` / `logic.rule` avec `runId`, stats de succès/échec, budget consommé/dépassement.
- **Teams** : invitations/changes de rôle/deny/grant loggés.
- **Community/Library** : publication, fork/import, retrait loggés avec `sourceBoardId`/`publicBoardId`/`targetBoardId` quand applicable.
- Visibilité cross-board : le détail d’un événement Community/Library n’est visible qu’aux utilisateurs disposant des capabilities adéquates (ex. `manage-community`) ; sinon un message générique est projeté.
- **Scheduler** : actions automatisées loggées avec actor “system”/“scheduler” mais toujours projetées via Teams.

## 5. Structures de persistance (suggestion)

- Table `activity` avec colonnes normalisées : `id`, `boardId`, `actorId`, `kind`, `subkind`, `timestamp`, `runId`, `status`, `code`, `message`, `details`, `nodeRefs`.
- Index : `boardId+timestamp`, `actorId`, `kind`, `runId`, GIN/BTREE sur `nodeRefs` (ou table de jonction si SGBD l’exige).
- API de lecture : filtres `boardId`, `actorId`, `nodeId`, `kind/subkind`, plage temporelle ; pagination.

## 6. Flux types

- **Commande utilisateur** : avant Apply → audit minimal ; après Apply → event `command.<subkind>` success/failed.
- **Run Interactions atomic** : `interaction.run.start` puis `interaction.run.end` avec liste des effets (succès/échec) + `runId`.
- **Règle Logique** : `logic.rule` après évaluation (actions appliquées, budget, raison d’échec).
- **Teams** : `teams.roleChanged` lors d’un changement de rôle/scope.
- **Publication** : `community.publish/import/fork/unpublish` aux actions correspondantes.

## 7. Rétention / export / risques

- Horizon par défaut 90 jours (configurable par board) ; les réponses peuvent être tronquées par rétention (voir `partial/partialReasons`).
- Export audit : JSONL complet, option `anonymizeActors=true` (pseudonymes stables par board, pseudonymisation et non anonymisation forte).
- Volume : surveiller taille de `details`; envisager archivage froid pour vieux événements.
