Parent : [[INDEX-WEB-UIUX]]
Modèle données annotations
Problème
Sans schema versionné, les annotations cassent à la première évolution (nouveau type, migration) et l'autosave corrompt les données (race conditions).
Solution — Document racine versionné
interface AnnotationDocument {
version: 1
id: string
targetUrl: string
createdAt: string
updatedAt: string
viewport: { width: number; height: number }
annotations: Annotation[]
}
type Annotation =
| PinAnnotation
| TextAnnotation
| RectAnnotation
| ThreadAnnotation
interface BaseAnnotation {
id: string
type: "pin" | "text" | "rect" | "thread"
authorId: string
createdAt: string
/** Position normalisée [[KNOW-PAT-149|KNOW-PAT-149]] */
anchor: { x: number; y: number; scrollX: number; scrollY: number }
resolved?: boolean
}
interface PinAnnotation extends BaseAnnotation {
type: "pin"
color: string
label?: string
}
interface TextAnnotation extends BaseAnnotation {
type: "text"
content: string
fontSize: number
width: number
}
interface ThreadAnnotation extends BaseAnnotation {
type: "thread"
messages: { id: string; body: string; createdAt: string }[]
}
Persistance
| Couche | Rôle |
|---|---|
| Optimistic local | IndexedDB ou localStorage draft immédiat |
| Autosave serveur | Debounce 2–5s, PAT-136 race guards |
| Snapshot export | JSON + PNG optionnel pour partage |
// Autosave : jamais écraser si version serveur > locale
async function save(doc: AnnotationDocument) {
const remote = await api.get(doc.id)
if (remote && remote.updatedAt > doc.updatedAt) {
throw new ConflictError(remote)
}
await api.put(doc)
}
API minimale
GET /sessions/:id
PUT /sessions/:id (If-Match: updatedAt ou version)
POST /sessions/:id/annotations
PATCH /annotations/:id
DELETE /annotations/:id
Exemple incorrect
// ❌ Tableau global non typé, coords px, pas de version
const comments = [{ x: 400, y: 200, text: "fix this" }]
localStorage.setItem("data", JSON.stringify(comments))
Source
- Excellence design-tool — 2026-06-09
Liens connexes
- [[KNOW-PAT-136-ProjectBeta-editor-ux-patterns|KNOW-PAT-136]]
- [[KNOW-PAT-149|KNOW-PAT-149]]