discovery-media-player 0.1.76 → 0.1.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/HOST-CONTRACT.md +5 -0
- package/docs/RETENTION.md +122 -0
- package/package.json +4 -1
package/docs/HOST-CONTRACT.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Host contract
|
|
2
2
|
|
|
3
|
+
> **This document is an export of the package** — resolve it with
|
|
4
|
+
> `require.resolve("discovery-media-player/contrat")` (and the retention policy with
|
|
5
|
+
> `…/retention`). An exposed path is a promise that survives file reorganizations; reading
|
|
6
|
+
> `node_modules` paths by hand is a guess about our tree, and it broke twice in one day.
|
|
7
|
+
|
|
3
8
|
What a host application may call, what it must implement, and what will not change without a
|
|
4
9
|
version bump. If you are integrating the player, this page and [`API.md`](API.md) are the two you
|
|
5
10
|
need.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Rétention des données
|
|
2
|
+
|
|
3
|
+
Ce document est le **périmètre déclaré** de la rétention : chaque colonne du schéma dont la forme
|
|
4
|
+
peut porter une donnée personnelle y a une politique — *purgée après N* ou *conservée parce que*.
|
|
5
|
+
Une garde de forge énumère les colonnes du schéma **vivant** (`information_schema`, jamais notre
|
|
6
|
+
mémoire du fichier) et refuse toute colonne à forme personnelle absente d'ici : une donnée sans
|
|
7
|
+
politique écrite ne peut pas entrer dans le schéma sans rougir.
|
|
8
|
+
|
|
9
|
+
Le contrat de vérification a deux moitiés, volontairement **indépendantes** (aucun code partagé —
|
|
10
|
+
ni fonction de périmètre, ni filtre) :
|
|
11
|
+
|
|
12
|
+
1. la **purge** (`server/retention.js`) déclare ce qu'elle a effacé, compte par compte ;
|
|
13
|
+
2. le **recensement** (`supabase/recensement-retention.sql`, SQL nu) compte ce qui reste dans le
|
|
14
|
+
périmètre revendiqué. Les deux nombres doivent se contredire si l'un ment.
|
|
15
|
+
|
|
16
|
+
> ⚠️ **Fenêtres proposées, à valider par l'exploitant.** Les durées ci-dessous sont des défauts
|
|
17
|
+
> raisonnés (journaux analytiques : 13 mois, comparaison année sur année ; archives de
|
|
18
|
+
> présentation : 12 mois après la fin). Un hôte les ajuste via `config.retention`.
|
|
19
|
+
>
|
|
20
|
+
> ⚠️ **Le balayage automatique est OPT-IN STRICT** : il ne tourne que si l'hôte écrit
|
|
21
|
+
> `config.retention.balayage: true`. Un hôte qui consomme le contexte autonome tel quel hérite de
|
|
22
|
+
> toutes ses capacités par défaut — « rien à brancher parce que rien n'a été débranché » — et une
|
|
23
|
+
> suppression est une décision métier : elle n'agit que là où un exploitant l'a écrite. L'action
|
|
24
|
+
> `retention.run` (hôte de confiance ou admin) reste disponible sans opt-in : l'appeler EST la
|
|
25
|
+
> décision.
|
|
26
|
+
|
|
27
|
+
## Journaux de lecture (population externe)
|
|
28
|
+
|
|
29
|
+
Finalité : statistiques de lecture d'un document envoyé. **Purge : 13 mois** après l'événement.
|
|
30
|
+
|
|
31
|
+
| colonne | contenu | sort |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| `commercial_doc_views.recipient_email` | à qui la lecture est attribuée | purgée avec la ligne, 13 mois après `at` |
|
|
34
|
+
| `commercial_doc_views.session_id` | corrèle les vues d'une session | idem |
|
|
35
|
+
| `commercial_doc_views.ua` | navigateur (User-Agent brut) | idem |
|
|
36
|
+
| `commercial_doc_sessions.recipient_email` | attribution de la session | purgée avec la ligne, 13 mois après `last_at` |
|
|
37
|
+
| `commercial_doc_sessions.session_id` | identifiant de session | idem |
|
|
38
|
+
| `commercial_doc_sessions.ip` | **adresse IP en clair** | idem — c'est la donnée la plus sensible du schéma |
|
|
39
|
+
| `commercial_doc_sessions.ua` | User-Agent brut | idem |
|
|
40
|
+
| `commercial_doc_sessions.num_pages` / `commercial_doc_sessions.pages_time` | comportement de lecture page par page | idem |
|
|
41
|
+
|
|
42
|
+
## Journaux de lecture (équipe interne)
|
|
43
|
+
|
|
44
|
+
Même finalité, population interne. **Purge : 13 mois** après `last_at`.
|
|
45
|
+
|
|
46
|
+
| colonne | sort |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `commercial_doc_internal_sessions.user_email` / `commercial_doc_internal_sessions.user_name` | purgées avec la ligne |
|
|
49
|
+
| `commercial_doc_internal_sessions.session_id` | idem |
|
|
50
|
+
| `commercial_doc_internal_sessions.num_pages` / `commercial_doc_internal_sessions.pages_time` | idem |
|
|
51
|
+
|
|
52
|
+
## Liens d'envoi (`commercial_doc_shares`)
|
|
53
|
+
|
|
54
|
+
Un lien **vivant** est un enregistrement métier : ses champs restent tant que l'URL distribuée
|
|
55
|
+
doit fonctionner. Un lien **révoqué** ne sert plus personne : **purge 13 mois après révocation**
|
|
56
|
+
(alignée sur les journaux, qui référencent son slug). La révocation est **datée** par
|
|
57
|
+
`commercial_doc_shares.revoked_at` (migration 0013) ; les révoqués d'avant la colonne ont reçu la
|
|
58
|
+
date de la migration — leur horloge démarre là, compter large plutôt qu'inventer. Sans la
|
|
59
|
+
colonne, cette purge-là se tait (sonde de schéma), les autres tournent.
|
|
60
|
+
|
|
61
|
+
| colonne | contenu | sort |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `commercial_doc_shares.recipient_email` | qui peut expédier au repartage | conservée tant que le lien vit ; ligne purgée 13 mois après révocation |
|
|
64
|
+
| `commercial_doc_shares.attested_recipient_email` | à qui l'hôte atteste le lien | idem |
|
|
65
|
+
| `commercial_doc_shares.recipient_name` | nom du destinataire | idem |
|
|
66
|
+
| `commercial_doc_shares.created_by` | email du commercial créateur | idem |
|
|
67
|
+
| `commercial_doc_shares.file_name` | nom du fichier (peut porter un nom de personne) | métier, purgé avec la ligne |
|
|
68
|
+
|
|
69
|
+
## Présentations en direct
|
|
70
|
+
|
|
71
|
+
Une présentation **inactive** (terminée ou abandonnée) est une archive : **purge 12 mois après
|
|
72
|
+
`updated_at`** — la présentation, ses messages, ses présences, et ses pièces jointes du bucket
|
|
73
|
+
`present-attachments` (si l'hôte fournit `storage.remove`, sinon la limite est dite ci-dessous).
|
|
74
|
+
|
|
75
|
+
| colonne | contenu | sort |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `doc_presentations.presenter_name` / `doc_presentations.owner_name` | identité du présentateur | purgées avec la ligne, 12 mois après la fin |
|
|
78
|
+
| `doc_presentations.owner_email` / `doc_presentations.owner_user_id` | propriétaire | idem |
|
|
79
|
+
| `doc_presentations.owner_avatar` | URL d'avatar | idem |
|
|
80
|
+
| `doc_presentations.control_hash` | empreinte du jeton de contrôle (pas le jeton) | idem |
|
|
81
|
+
| `doc_presentations.content` | contenu partagé (cartes, médias) | idem |
|
|
82
|
+
| `doc_presentations.file_name` | nom du fichier présenté | idem |
|
|
83
|
+
| `doc_presentation_messages.author_name` / `doc_presentation_messages.author_email` / `doc_presentation_messages.author_avatar` | identité de l'auteur | purgées avec la présentation |
|
|
84
|
+
| `doc_presentation_messages.author_hash` | empreinte du jeton d'auteur | idem |
|
|
85
|
+
| `doc_presentation_messages.body` | corps du message | idem |
|
|
86
|
+
| `doc_presentation_messages.reply_name` / `doc_presentation_messages.reply_text` | citation d'un autre message | idem |
|
|
87
|
+
| `doc_presentation_messages.attachment` | URL de pièce jointe | idem — fichier du bucket inclus quand `storage.remove` existe |
|
|
88
|
+
| `doc_presentation_messages.client_key` | clé d'idempotence d'envoi | idem |
|
|
89
|
+
| `doc_presentation_attendees.name` / `doc_presentation_attendees.email` / `doc_presentation_attendees.avatar` | identité du participant | purgées avec la présentation |
|
|
90
|
+
| `doc_presentation_attendees.attendee_key` | identifiant de présence | idem |
|
|
91
|
+
| `doc_presentation_attendees.pages` | pages vues par le participant | idem |
|
|
92
|
+
|
|
93
|
+
## Sessions d'agent (`doc_bot_sessions`)
|
|
94
|
+
|
|
95
|
+
Parcours guidé par l'agent : **purge 13 mois** après `last_at`.
|
|
96
|
+
|
|
97
|
+
| colonne | sort |
|
|
98
|
+
|---|---|
|
|
99
|
+
| `doc_bot_sessions.rating` / `doc_bot_sessions.rating_comment` | avis du visiteur — purgés avec la ligne |
|
|
100
|
+
| `doc_bot_sessions.in_tokens` / `doc_bot_sessions.out_tokens` / `doc_bot_sessions.cache_tokens` | volumétrie IA (pas personnelle, mais portée par la ligne) — purgés avec elle |
|
|
101
|
+
|
|
102
|
+
## Limites de débit (`player_rate_limits`)
|
|
103
|
+
|
|
104
|
+
| colonne | contenu | sort |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `player_rate_limits.key` | peut contenir une **IP en clair** (`hshare:<ip>`) ou un email | ligne purgée dès `expires_at` dépassé (opportuniste, à chaque passage) |
|
|
107
|
+
|
|
108
|
+
## Limites dites plutôt que tues
|
|
109
|
+
|
|
110
|
+
- **Pièces jointes orphelines** : la purge des lignes n'efface le fichier du bucket que si le
|
|
111
|
+
contexte hôte fournit `storage.remove` (capacité optionnelle). Sans elle, l'URL devient
|
|
112
|
+
introuvable depuis le produit mais l'objet survit dans le bucket — c'est dit ici plutôt que
|
|
113
|
+
simulé.
|
|
114
|
+
- **Le recensement ne tourne pas tout seul en production** : c'est un SQL qu'un exploitant lance
|
|
115
|
+
(et que la forge exécute à chaque course sur une base réelle vieillie artificiellement).
|
|
116
|
+
- **« Ce qui existe » a une profondeur temporelle qu'`information_schema` n'a pas** (question du
|
|
117
|
+
second hôte, sans réponse mécanique) : une colonne supprimée du schéma sort du périmètre des
|
|
118
|
+
deux textes, mais sa donnée peut survivre dans un dump, une sauvegarde ou une table d'archive.
|
|
119
|
+
Ce contrat couvre la BASE VIVANTE ; les copies (sauvegardes, exports, dumps de migration) sont
|
|
120
|
+
le périmètre de l'exploitant, nommé ici plutôt que simulé. Corollaire opératoire : supprimer
|
|
121
|
+
une colonne à donnée personnelle est un acte de rétention — sa ligne quitte ce document dans
|
|
122
|
+
le même commit, et les copies antérieures suivent la politique de sauvegarde de l'hôte.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discovery-media-player",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.77",
|
|
4
4
|
"description": "Self-hosted document viewer: per-recipient tracked links, reading analytics, live presentation. The core knows nothing about the application hosting it — everything it borrows arrives through an injected context.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pdf-viewer",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"LICENSE",
|
|
37
37
|
"LICENSE-MIT",
|
|
38
38
|
"docs/HOST-CONTRACT.md",
|
|
39
|
+
"docs/RETENTION.md",
|
|
39
40
|
"!**/__tests__"
|
|
40
41
|
],
|
|
41
42
|
"exports": {
|
|
@@ -43,6 +44,8 @@
|
|
|
43
44
|
"./shares": "./server/shares.js",
|
|
44
45
|
"./presentations": "./server/presentations.js",
|
|
45
46
|
"./brands": "./server/brands.js",
|
|
47
|
+
"./contrat": "./docs/HOST-CONTRACT.md",
|
|
48
|
+
"./retention": "./docs/RETENTION.md",
|
|
46
49
|
"./context/standalone": "./context/standalone.js",
|
|
47
50
|
"./context/storage": "./context/storage.js",
|
|
48
51
|
"./bridge": {
|