tfrere HF Staff commited on
Commit
32a4aca
·
1 Parent(s): 76fc93a

docs: refresh README, architecture, spec and add agent teams proposal

Browse files

- README: align env var table with real backend (OPENROUTER_API_KEY, HF_DATASET_ID, SPACE_ID,
PUBLISH_BASE_URL, ENABLE_PDF, OAUTH_SCOPES) and fix prerequisites
- ARCHITECTURE / SPECIFICATION: describe the new transformer pipeline, embed studio flow,
mobile TOC + CommentPopover; drop the deleted CommentsSidebar reference
- TESTS: announce the Playwright E2E suite as part of the stack and add 4.1.4 for the
upload rate limiter; note the split between fast hermetic suite and opt-in E2E
- Add AGENT_TEAMS_PROPOSAL.md to track the upcoming multi-agent collaboration design

Made-with: Cursor

Files changed (4) hide show
  1. README.md +155 -13
  2. docs/AGENT_TEAMS_PROPOSAL.md +186 -0
  3. docs/ARCHITECTURE.md +40 -12
  4. docs/SPECIFICATION.md +16 -11
README.md CHANGED
@@ -13,25 +13,167 @@ hf_oauth_scopes:
13
 
14
  # Research Article Template Editor
15
 
16
- Collaborative real-time scientific article editor. Built with TipTap, Yjs, and Hocuspocus.
17
 
18
- ## Features
19
 
20
- - Real-time collaborative editing (multiple cursors)
21
- - Rich text: headings, bold, italic, lists, blockquotes, code blocks
22
- - Export to MDX format
23
- - Dark theme
24
 
25
- ## Development
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  ```bash
28
- # Backend
29
- cd backend && npm install && npm run dev
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- # Frontend (separate terminal)
32
- cd frontend && npm install && npm run dev
 
 
 
33
  ```
34
 
35
- Open http://localhost:5173. Open a second tab to see collaboration in action.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- The app uses a single shared document (`default`).
 
13
 
14
  # Research Article Template Editor
15
 
16
+ A collaborative, real-time editor for web-native scientific articles. It lets multiple authors co-write a paper with rich text, math, citations, figures and interactive D3 embeds, then publishes the result as a static HTML page (or a PDF) aligned with the [research-article-template](https://github.com/huggingface/research-article-template).
17
 
18
+ ![editor screenshot](./docs/screenshot.png)
19
 
20
+ ## What it gives you
 
 
 
21
 
22
+ - **Real-time collaboration** over WebSocket (Y.js + Hocuspocus), with visible cursors and per-user selection colors
23
+ - **Rich article authoring**: headings, lists, tables, code blocks with syntax highlighting, LaTeX math (KaTeX), footnotes, sidenotes, block quotes, callouts
24
+ - **Research-specific blocks**: citations + bibliography (BibTeX), figures with captions, stacks / wide / full-width layouts, glossary terms, Mermaid/Wardley/architecture diagrams
25
+ - **Interactive D3 embeds** authored inline: each embed is a self-contained HTML file the editor can generate and iterate on via an **AI-assisted "embed studio"**
26
+ - **Comments & discussion** anchored on any selection
27
+ - **Slash menu** (`/`) and drag/drop block handles, in the spirit of Notion
28
+ - **Click-to-edit frontmatter**: title, subtitle, authors, affiliations, links, banner color
29
+ - **Publishing pipeline**: one-click export to a standalone static HTML bundle, plus PDF generation (Puppeteer)
30
+ - **Persistence**:
31
+ - Local mode: documents stored on disk under `DATA_DIR`
32
+ - HF mode: documents pushed/pulled from a Hugging Face dataset via OAuth
33
+ - **Dark mode**, responsive layout (TOC drawer on mobile), live table of contents with scroll-spy
34
+ - **AI chat side-panel** that can edit the article via structured tool calls (agent loop over the current TipTap doc)
35
+
36
+ ## Stack
37
+
38
+ | Layer | Tech |
39
+ |---|---|
40
+ | Editor | React 18, TypeScript, TipTap v3, ProseMirror |
41
+ | Collaboration | Y.js, Hocuspocus (WebSocket), y-tiptap |
42
+ | Backend | Node.js, Express, Vite (dev proxy), Hocuspocus server |
43
+ | Publishing | Custom TipTap-JSON → HTML renderer, Puppeteer for PDF |
44
+ | AI | Vercel AI SDK v6 (`ai`, `@ai-sdk/react`), streaming tool calls |
45
+ | Styling | Plain CSS with custom properties, no framework |
46
+ | Storage | Local FS or Hugging Face datasets (via `@huggingface/hub`) |
47
+ | Container | Single-image Docker build, runs on port 8080 |
48
+
49
+ Around **3.6k LOC backend** and **9.5k LOC frontend** (TypeScript/TSX, excluding generated code).
50
+
51
+ ## Repo layout
52
+
53
+ ```
54
+ collab-editor/
55
+ ├── backend/ # Express + Hocuspocus server, publisher, AI agent routes
56
+ │ └── src/
57
+ │ ├── server.ts # Entry point
58
+ │ ├── create-app.ts # App factory (routes, middleware, Hocuspocus)
59
+ │ ├── publisher/ # TipTap-JSON → HTML + PDF
60
+ │ ├── agent/ # LLM agent (tool calls over the doc)
61
+ │ ├── shared/ # Component defs shared with the frontend
62
+ │ └── hf-storage.ts # HF dataset sync
63
+ ├── frontend/ # Vite + React + TipTap editor
64
+ │ └── src/
65
+ │ ├── App.tsx # Top-level shell
66
+ │ ├── editor/ # TipTap editor + extensions + components
67
+ │ ├── components/ # Shared UI pieces (TOC, Chat, Dialog, ...)
68
+ │ ├── hooks/ # React hooks (agent chat, selection, ...)
69
+ │ ├── styles/ # CSS layers (see docs/ARCHITECTURE.md)
70
+ │ └── utils/
71
+ ├── docs/
72
+ │ ├── ARCHITECTURE.md # Deep dive on layers, data flow, CSS
73
+ │ ├── SPECIFICATION.md # Feature spec and contracts
74
+ │ ├── TESTS.md # Testing strategy
75
+ │ └── embed-studio.md # How the AI-authored embeds pipeline works
76
+ └── Dockerfile # Production multi-stage build
77
+ ```
78
+
79
+ See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for a diagram and the full tour.
80
+
81
+ ## Getting started
82
+
83
+ ### Prerequisites
84
+
85
+ - Node.js 20+
86
+ - An OpenRouter API key if you want the AI features (embed studio, chat agent)
87
+ - A Hugging Face OAuth app (client id/secret) if you want login + HF dataset persistence
88
+
89
+ ### Local development
90
+
91
+ Backend and frontend run as two separate processes in dev (Vite proxies `/api`, `/collab`, `/uploads`, `/published`, `/oauth`, `/auth` to the backend).
92
 
93
  ```bash
94
+ # terminal 1 — backend (Express + Hocuspocus on :8080)
95
+ cd backend
96
+ cp .env.example .env # fill in HF_TOKEN, OPENAI_API_KEY, ...
97
+ npm install
98
+ npm run dev
99
+
100
+ # terminal 2 — frontend (Vite on :5678)
101
+ cd frontend
102
+ npm install
103
+ npm run dev
104
+ ```
105
+
106
+ Then open http://localhost:5678. Open a second tab or browser to see collaboration in action.
107
+
108
+ ### Production (Docker / HF Spaces)
109
 
110
+ The `Dockerfile` builds both frontend and backend into a single image listening on port 8080. This is the image used by the Hugging Face Space.
111
+
112
+ ```bash
113
+ docker build -t collab-editor .
114
+ docker run -p 8080:8080 --env-file backend/.env collab-editor
115
  ```
116
 
117
+ Then open http://localhost:8080.
118
+
119
+ ## Scripts
120
+
121
+ ### Backend (`cd backend`)
122
+
123
+ | Command | What it does |
124
+ |---|---|
125
+ | `npm run dev` | Start Express + Hocuspocus in watch mode |
126
+ | `npm run build` | Compile TypeScript to `dist/` |
127
+ | `npm start` | Run the compiled server |
128
+ | `npm run test` | Unit + integration tests (Vitest) |
129
+ | `npm run test:e2e` | End-to-end tests (Playwright) |
130
+
131
+ ### Frontend (`cd frontend`)
132
+
133
+ | Command | What it does |
134
+ |---|---|
135
+ | `npm run dev` | Start Vite dev server on :5678 |
136
+ | `npm run build` | Production bundle to `dist/` |
137
+ | `npm run preview` | Preview the built bundle |
138
+ | `npm run test` | Unit tests (Vitest) |
139
+ | `npm run typecheck` | `tsc --noEmit` on the whole frontend |
140
+
141
+ ## Environment variables
142
+
143
+ Copy `backend/.env.example` to `backend/.env` and fill the relevant values. Key ones:
144
+
145
+ | Variable | Purpose |
146
+ |---|---|
147
+ | `OAUTH_CLIENT_ID` / `OAUTH_CLIENT_SECRET` | HF OAuth app for user login (required to edit when running on a Space) |
148
+ | `OAUTH_SCOPES` | OAuth scopes (default `openid profile`) |
149
+ | `OPENROUTER_API_KEY` | API key used by the AI agent (chat panel + embed studio) |
150
+ | `OPENROUTER_MODEL` | Override the default OpenRouter model id |
151
+ | `HF_TOKEN` | Server-side Hugging Face token (fallback when no user OAuth token is present) |
152
+ | `HF_DATASET_ID` | Target HF dataset repo for document persistence (when not running on a Space) |
153
+ | `SPACE_ID` / `SPACE_HOST` | Auto-set by HF Spaces; drive dataset id + secure cookies in production |
154
+ | `DATA_DIR` | Where documents, uploads and published bundles are stored on disk (default: `./data`) |
155
+ | `PUBLISH_BASE_URL` | Absolute base URL used when publishing (defaults to `http://127.0.0.1:${PORT}`) |
156
+ | `ENABLE_PDF` | Set to `false` to disable Playwright-based PDF export |
157
+ | `PORT` | Server port (default 8080) |
158
+
159
+ ## Testing
160
+
161
+ - **Backend unit tests**: Vitest covers the publisher (HTML renderer, frontmatter, bibliography), storage, auth utilities.
162
+ - **Backend E2E**: Playwright drives the full editor against a real backend.
163
+ - **Frontend unit tests**: Vitest covers chat persistence and a handful of utilities.
164
+ - **Type checking**: `npm run typecheck` in both workspaces.
165
+
166
+ See [`docs/TESTS.md`](docs/TESTS.md) for the current strategy and gaps.
167
+
168
+ ## Known technical debt
169
+
170
+ These are tracked explicitly so new contributors don't trip on them:
171
+
172
+ - **`useAgentChat` / `useEmbedChat` still lack dedicated unit tests**; the rest of the stores (frontmatter, comments, embeds) are now covered.
173
+ - **Bundle size warning**: the frontend bundle is over the 500 kB Vite warning threshold. Code-splitting the Mermaid / KaTeX / D3 stacks via dynamic imports would help.
174
+ - **`addToolOutput` typing**: the ai-sdk v6 `ChatAddToolOutputFunction` is a generic over the tool name union. We currently cast to a plain signature at the two call sites because we don't export a typed tool registry yet.
175
+ - **`backend/src/publisher/html-renderer.ts` is ~1000 LOC**: a per-node-type registry would make it more maintainable.
176
+
177
+ ## License
178
 
179
+ Follow the upstream [research-article-template](https://github.com/huggingface/research-article-template) license.
docs/AGENT_TEAMS_PROPOSAL.md ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Proposition - Passer d'un agent unique à une équipe d'agents
2
+
3
+ > Réflexion inspirée de l'article [The Collaboration Gap](https://robotscooking.substack.com/p/the-collaboration-gap) (Adam Hyde, 2026) appliquée à `collab-editor`.
4
+
5
+ ## 1. Constat sur l'état actuel
6
+
7
+ Le `collab-editor` est aujourd'hui structuré autour de **deux agents isolés** :
8
+
9
+ | Agent | Fichier | Rôle |
10
+ |---|---|---|
11
+ | Article agent | `backend/src/agent/chat.ts` + `frontend/src/hooks/useAgentChat.ts` | Édite le TipTap doc via `applyDiff` / `replaceSelection` / `insertAtCursor` |
12
+ | Embed agent | `backend/src/agent/embed-chat.ts` + `frontend/src/hooks/useEmbedChat.ts` | Génère les embeds D3 |
13
+
14
+ Les deux ne se parlent pas. Ils ne partagent pas de contexte. L'utilisateur est le seul "orchestrateur", à la main, en switchant d'interface.
15
+
16
+ C'est exactement le pattern "one human, one AI, one task" que l'article pointe comme limitant.
17
+
18
+ ## 2. Ce qu'on a déjà gratuitement (et que la plupart des setups multi-agents n'ont pas)
19
+
20
+ | Brique | Fichier | Pourquoi c'est un atout |
21
+ |---|---|---|
22
+ | État partagé versionné (CRDT) | Y.js + Hocuspocus | C'est LE "shared board" de l'article, déjà construit, déjà résolveur de conflits |
23
+ | Canal de messages ancrés | `frontend/src/editor/comments.ts` + `CommentsSidebar.tsx` | Communication latérale entre agents, visible par l'humain |
24
+ | Undo groupé par tour | `UndoManager` + `startAgentBatch` | Rollback atomique d'une action d'équipe |
25
+ | Tool calls structurés | `backend/src/agent/tools.ts` | Protocole déjà formalisé |
26
+ | Frontmatter store réactif | `frontend/src/editor/frontmatter/frontmatter-store.ts` | État structuré séparé du corps, parfait pour un agent dédié |
27
+
28
+ **Traduction** : on est mieux placés que Pure.Science pour implémenter ce que décrit Adam Hyde, parce que notre "bubble" existe déjà côté humain.
29
+
30
+ ## 3. Proposition d'architecture - 5 rôles
31
+
32
+ Inspirée directement de Pure.Science (Wax, Ketty, Coco, Paige, Koda), mais adaptée à l'écriture scientifique web-native.
33
+
34
+ ### 3.1. Rôles
35
+
36
+ | Agent | Rôle | Outils autorisés | Zones d'écriture |
37
+ |---|---|---|---|
38
+ | **Scout** | Topic Strategist : cadre le papier, propose l'angle | `setFrontmatterDraft`, `proposeOutline` (commentaire) | Commentaires uniquement |
39
+ | **Archi** | Outliner / Structurer : gère TOC, hiérarchie, sections | `applyDiff` sur headings, `insertSection` | Headings, structure |
40
+ | **Scribe** | Writer : rédige les paragraphes | `applyDiff`, `insertAtCursor` | Corps du texte |
41
+ | **Biblio** | Literature Retriever : cherche des refs, pose des citations | `addCitation`, `addBibEntry`, `commentSuggestion` | Bibliography.bib + balises `[@key]` |
42
+ | **Critic** | QA / Reviewer : relit, pointe incohérences, passe des commentaires | `comment`, `resolveComment`, `flagInconsistency` | Commentaires uniquement (read-only sur le doc) |
43
+
44
+ **Point crucial** : seuls `Archi` et `Scribe` touchent au texte. `Critic` **ne peut pas éditer**, il commente - ça force la friction que décrit l'article et évite le "yes-man loop" des LLMs.
45
+
46
+ ### 3.2. Orchestrateur
47
+
48
+ Un agent léger côté backend (nouveau fichier `backend/src/agent/orchestrator.ts`) qui :
49
+
50
+ 1. Reçoit le message de l'humain
51
+ 2. Lit l'état du doc (+ frontmatter + commentaires ouverts)
52
+ 3. Décide quel(s) agent(s) réveiller et dans quel ordre
53
+ 4. Tient un journal de tâches visible (équivalent du "board" dans l'article)
54
+
55
+ L'orchestrateur n'édite jamais. Il **dispatche** et **attend**. Comme le facilitateur d'un Book Sprint.
56
+
57
+ ### 3.3. Code de conduite partagé
58
+
59
+ Un prompt-système commun (nouveau `backend/src/agent/team-code-of-conduct.ts`) injecté dans **tous** les agents :
60
+
61
+ ```md
62
+ 1. Avant toute action, lis le board (commentaires ouverts + journal orchestrateur).
63
+ 2. Reste dans ton rôle. Si une tâche sort de ton périmètre, ping l'agent compétent via un commentaire typé.
64
+ 3. N'écrase pas le travail d'un autre agent sans laisser un commentaire justifiant le changement.
65
+ 4. Les désaccords se résolvent par commentaire ancré, pas par écrasement silencieux.
66
+ 5. Sois concis. Un message = une intention.
67
+ ```
68
+
69
+ Directement dérivé du "code of conduct" Pure.Science.
70
+
71
+ ## 4. Communication latérale - piggyback sur les commentaires
72
+
73
+ Plutôt qu'un bus de messages séparé, on étend le système de commentaires existant avec un champ `author` et `audience` :
74
+
75
+ ```ts
76
+ interface AgentComment {
77
+ author: "scout" | "archi" | "scribe" | "biblio" | "critic" | "human";
78
+ audience: Array<"scout" | "archi" | "scribe" | "biblio" | "critic" | "human">;
79
+ kind: "suggestion" | "question" | "blocker" | "task";
80
+ anchor: { from: number; to: number };
81
+ body: string;
82
+ }
83
+ ```
84
+
85
+ Bénéfices :
86
+ - L'humain voit **tout** dans la sidebar existante (`CommentsSidebar.tsx`)
87
+ - Les agents s'adressent à un autre agent via `audience: ["scribe"]`
88
+ - Rien à construire côté infra, juste étendre le schema
89
+
90
+ ## 5. UI - rendre l'équipe visible
91
+
92
+ L'article insiste sur le fait que **la valeur de la collab est invisible si on ne la montre pas**. Proposition côté UI :
93
+
94
+ ### 5.1. Team activity timeline
95
+
96
+ Un petit panneau dans `TopBar.tsx` ou sous le chat :
97
+
98
+ ```
99
+ [Archi] → created section "Methodology" 2s ago
100
+ [Biblio] → suggested 3 citations in §2 5s ago
101
+ [Critic] → flagged: unsupported claim in §3 8s ago
102
+ [Scribe] → drafted paragraph in §1 12s ago
103
+ ```
104
+
105
+ ### 5.2. Curseurs colorés par agent
106
+
107
+ On a déjà les curseurs multi-utilisateurs via `collaboration-cursor-v3.ts`. Chaque agent devient un "utilisateur virtuel" avec sa couleur et son nom de rôle. L'humain **voit en direct** où chaque agent travaille. Zero nouvelle infra.
108
+
109
+ ### 5.3. Quick actions par rôle
110
+
111
+ Remplacer le `sendQuickAction` générique de `useAgentChat.ts` par un sélecteur de rôle :
112
+
113
+ ```
114
+ Ask [ Scribe ▾ ] to: [ rewrite this paragraph ]
115
+ ```
116
+
117
+ ## 6. Plan d'implémentation progressif
118
+
119
+ Par ordre de ROI, du plus petit au plus gros.
120
+
121
+ ### Étape 1 - Split sémantique sans nouvelle infra (2-3j)
122
+
123
+ - Spécialiser le prompt actuel : le SYSTEM prompt passe de "tu es un assistant qui édite" à "tu es le Scribe, tu écris les paragraphes".
124
+ - Ajouter un prompt `Critic` qui ne fait QUE passer des commentaires (pas de tool d'édition).
125
+ - UI : un dropdown "Talk to [ Scribe / Critic ]".
126
+
127
+ Valeur : on valide l'hypothèse qu'un agent read-only qui commente améliore la qualité perçue, avant de construire l'orchestration.
128
+
129
+ ### Étape 2 - Curseurs agents + timeline (2j)
130
+
131
+ - Chaque agent = user Y.js virtuel avec couleur.
132
+ - Timeline agrégée depuis les tool calls loggés.
133
+
134
+ Valeur : rend la collaboration lisible, c'est le point central d'Adam Hyde.
135
+
136
+ ### Étape 3 - Biblio agent autonome (3-4j)
137
+
138
+ - Outils `addCitation`, `searchArxiv`, `addBibEntry`.
139
+ - Déclenchement automatique quand `Scribe` écrit une affirmation factuelle (via tool `requestCitation`).
140
+
141
+ Valeur : premier cas de communication latérale agent→agent concrète.
142
+
143
+ ### Étape 4 - Orchestrateur (5-7j)
144
+
145
+ - Nouveau route `/api/orchestrate` qui dispatche plutôt que de `/api/chat` directement.
146
+ - Board visible dans le chat.
147
+
148
+ Valeur : vrai multi-agent, mais seulement une fois les étapes 1-3 validées.
149
+
150
+ ### Étape 5 - Scout (cadrage initial) (3j)
151
+
152
+ - Agent qui intervient uniquement au début d'un nouveau doc, à partir d'un prompt court "je veux écrire sur X".
153
+ - Génère frontmatter + TOC + commentaires de cadrage.
154
+
155
+ Valeur : onboarding d'un nouvel article 10x plus fluide.
156
+
157
+ ## 7. Métrique de succès
158
+
159
+ Adam Hyde souligne qu'on ne sait pas benchmarker la collaboration. Proposition de 3 mesures simples et propres à l'éditeur :
160
+
161
+ | Métrique | Comment | Pourquoi |
162
+ |---|---|---|
163
+ | **Commentaires résolus par session** | Compteur via le store de commentaires | Proxy de la qualité de la friction |
164
+ | **Ratio d'édits rollback par l'humain** | Undo après action agent / total actions agent | Mesure l'alignement |
165
+ | **Temps médian d'un article jusqu'à "publish"** | Log `published_at - created_at` côté backend | Mesure l'effet global |
166
+
167
+ Pas de benchmark LLM abstrait : on mesure **sur le produit**.
168
+
169
+ ## 8. Risques et limites
170
+
171
+ - **Coût tokens ×N** : chaque tour peut réveiller 2-3 agents. À mitiger avec un routing intelligent côté orchestrateur (ne pas réveiller `Biblio` si le message est "fix grammaire").
172
+ - **LLMs d'accord avec tout** : le rôle `Critic` ne marche que si le prompt force la contradiction explicite. À itérer avec des exemples few-shot.
173
+ - **UX du bruit** : si les 5 agents commentent en permanence, la sidebar devient illisible. Prévoir un mode "muet par défaut, opt-in par rôle".
174
+ - **Complexité de debug** : logger impérativement le journal orchestrateur pour pouvoir rejouer une session.
175
+
176
+ ## 9. Ce que ça apporte à ton produit
177
+
178
+ Aujourd'hui `collab-editor` est "un Notion-like pour papiers scientifiques avec un AI assistant". C'est bien, mais une dizaine de produits font ça.
179
+
180
+ Avec cette architecture, tu deviens **le premier éditeur scientifique où une équipe d'agents spécialisés co-écrit avec l'humain**, en s'appuyant sur l'infra temps-réel Y.js que tu as déjà. C'est une proposition produit claire et différenciante, directement alignée avec la thèse de l'article :
181
+
182
+ > "Les organisations qui investissent dans l'architecture de collaboration avec le même sérieux qu'elles investissent dans la capacité des modèles produiront de meilleurs résultats."
183
+
184
+ ## 10. Prochaine étape concrète suggérée
185
+
186
+ Commencer par **l'étape 1** : forker `useAgentChat` en `useScribeChat` + `useCriticChat`, avec un simple toggle d'UI. C'est 2 jours de boulot, ça valide ou invalide l'hypothèse avant d'engager l'orchestrateur.
docs/ARCHITECTURE.md CHANGED
@@ -29,37 +29,57 @@ The collab-editor is a collaborative article editor built for Hugging Face Space
29
 
30
  | Path | Description |
31
  |------|-------------|
32
- | `backend/src/server.ts` | Express server, routes, WebSocket setup |
 
33
  | `backend/src/publisher/` | HTML rendering, PDF generation, bibliography formatting |
34
  | `backend/src/publisher/html-renderer.ts` | Converts TipTap JSON to static HTML page |
35
  | `backend/src/publisher/extensions.ts` | Server-side TipTap extensions (mirrors frontend) |
36
  | `backend/src/shared/component-defs.ts` | Shared component definitions (single source of truth) |
 
 
 
37
  | `frontend/src/editor/` | TipTap editor, toolbars, components |
38
  | `frontend/src/editor/components/registry.ts` | Component registry (imports from shared defs) |
39
  | `frontend/src/styles/` | All CSS files |
40
- | `frontend/src/styles/_publisher.css` | Publisher-only CSS (injected into static HTML) |
41
- | `frontend/src/styles/_ui.css` | Editor chrome CSS (buttons, dialogs, drawers) |
42
 
43
  ## Styling architecture
44
 
45
  ### CSS layers
46
 
47
- The project uses three CSS layers:
48
 
49
- 1. **Template CSS** (`_variables.css`, `_base.css`, `_layout.css`, `article.css`, `components/`)
50
- - Defines the article's visual identity
51
  - Uses CSS custom properties (`--text-color`, `--surface-bg`, `--primary-color`, etc.)
 
52
  - Shared between the editor preview and the published output
53
 
54
- 2. **Editor chrome CSS** (`_ui.css`)
55
- - Styles the editor UI: toolbars, sidebars, dialogs, forms
56
  - Uses `--ed-*` custom properties for the dark editor theme
57
  - Only loaded in the editor, never in published output
58
 
59
- 3. **Publisher CSS** (`_publisher.css`)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  - Styles specific to the published static HTML page
61
- - Footer layout, bibliography, footnotes, citation links, theme toggle
62
- - Only injected by the HTML renderer, never loaded in the editor
63
 
64
  ### No CSS-in-JS
65
 
@@ -139,9 +159,15 @@ The `postProcess()` function uses `linkedom` for DOM manipulation instead of reg
139
 
140
  `GET /api/preview/:docName` renders the HTML without saving or uploading. Useful for testing the publisher pipeline.
141
 
 
 
 
 
 
 
142
  ## Testing
143
 
144
- Tests use Vitest. Run with `npm test` from `backend/`.
145
 
146
  | Test file | What it covers |
147
  |-----------|----------------|
@@ -152,3 +178,5 @@ Tests use Vitest. Run with `npm test` from `backend/`.
152
  | `tests/utils.test.ts` | Path sanitization utilities |
153
  | `tests/auth.test.ts` | Token extraction, OAuth configuration |
154
  | `tests/hf-storage.test.ts` | HF dataset storage configuration |
 
 
 
29
 
30
  | Path | Description |
31
  |------|-------------|
32
+ | `backend/src/server.ts` | Entry point: imports `createApp()`, starts listener, signal handlers |
33
+ | `backend/src/create-app.ts` | Express app factory: routes, Hocuspocus, WebSocket, middleware |
34
  | `backend/src/publisher/` | HTML rendering, PDF generation, bibliography formatting |
35
  | `backend/src/publisher/html-renderer.ts` | Converts TipTap JSON to static HTML page |
36
  | `backend/src/publisher/extensions.ts` | Server-side TipTap extensions (mirrors frontend) |
37
  | `backend/src/shared/component-defs.ts` | Shared component definitions (single source of truth) |
38
+ | `backend/src/utils.ts` | Shared utilities: `docPath()`, `sanitizeName()`, injectable `DATA_DIR` |
39
+ | `backend/src/auth.ts` | OAuth flow, token extraction, user resolution |
40
+ | `backend/src/hf-storage.ts` | HF dataset sync (push/pull documents and assets) |
41
  | `frontend/src/editor/` | TipTap editor, toolbars, components |
42
  | `frontend/src/editor/components/registry.ts` | Component registry (imports from shared defs) |
43
  | `frontend/src/styles/` | All CSS files |
 
 
44
 
45
  ## Styling architecture
46
 
47
  ### CSS layers
48
 
49
+ The project uses five CSS layers, loaded in this order by `main.tsx`:
50
 
51
+ 1. **Template foundation** (`_variables.css`, `_reset.css`, `_base.css`, `_layout.css`, `_print.css`, `components/*`)
52
+ - Defines the article's visual identity (typography, grid, components)
53
  - Uses CSS custom properties (`--text-color`, `--surface-bg`, `--primary-color`, etc.)
54
+ - Layout tokens centralize grid math (`--layout-toc-width`, `--layout-content-width`, `--layout-gap`, breakpoints)
55
  - Shared between the editor preview and the published output
56
 
57
+ 2. **Editor chrome** (`_ui.css`)
58
+ - Styles the editor UI: top-bar, sidebars, dialogs, chat panel, embed studio
59
  - Uses `--ed-*` custom properties for the dark editor theme
60
  - Only loaded in the editor, never in published output
61
 
62
+ 3. **Design tokens** (`tokens.css`)
63
+ - Light/dark theming tokens for both editor and article
64
+ - Text, background, border, accent, code highlighting, danger, shadows
65
+ - Supports `data-theme` attribute and `prefers-color-scheme` media query
66
+ - Shared between editor and published output (injected by publisher)
67
+
68
+ 4. **Shared article styles** (`article.css`, `toc.css`)
69
+ - Article content styles shared between editor preview and published output
70
+ - `article.css` includes wrapper components (Note, Stack, Quote, Sidenote...), with editor-specific variants scoped by `.editor-app`
71
+
72
+ 5. **Editor-only styles** (`styles/editor/*.css`, 5 files)
73
+ - `_layout.css`: grid overrides (3-col symmetric, aligned with template), TOC drawer, responsive breakpoints (1100px collapse, 768px mobile)
74
+ - `_chrome.css`: ProseMirror editing visuals (placeholder, selection, cursors, comment marks, math editing)
75
+ - `_block-tools.css`: block handles (drag + add) and slash menu
76
+ - `_panels.css`: image upload card, footnote tooltip, citation panel
77
+ - `_hero-editable.css`: transparent click-to-edit inputs for FrontmatterHero
78
+
79
+ 6. **Publisher CSS** (`_publisher.css`)
80
  - Styles specific to the published static HTML page
81
+ - Theme toggle animations, wide/fullWidth breakout, sidenote float, lightbox, PDF link
82
+ - Only injected by the HTML renderer (backend), never loaded in the editor
83
 
84
  ### No CSS-in-JS
85
 
 
159
 
160
  `GET /api/preview/:docName` renders the HTML without saving or uploading. Useful for testing the publisher pipeline.
161
 
162
+ ## Auth and security
163
+
164
+ - AI chat routes (`/api/chat`, `/api/embed-chat`) are auth-guarded when OAuth is enabled
165
+ - The `requireEditor` middleware checks cookie token and verifies write access
166
+ - Published articles are served without auth (public)
167
+
168
  ## Testing
169
 
170
+ Tests use Vitest + Supertest. Run with `npm test` from `backend/`.
171
 
172
  | Test file | What it covers |
173
  |-----------|----------------|
 
178
  | `tests/utils.test.ts` | Path sanitization utilities |
179
  | `tests/auth.test.ts` | Token extraction, OAuth configuration |
180
  | `tests/hf-storage.test.ts` | HF dataset storage configuration |
181
+ | `tests/persistence.test.ts` | Local file persistence, debounced save |
182
+ | `tests/api-routes.test.ts` | API route integration tests (publish, auth status) |
docs/SPECIFICATION.md CHANGED
@@ -4,7 +4,7 @@
4
 
5
  A collaborative, real-time scientific article editor deployed as a Hugging Face Space. Users write rich content (math, citations, custom components) in a TipTap-based editor synced via Yjs/Hocuspocus, then publish a self-contained static HTML article. An AI assistant helps with writing and editing.
6
 
7
- **Stack**: React 18 + MUI 9 + TipTap 3 + Yjs (frontend) / Express + Hocuspocus + Node 20 (backend) / Docker on HF Spaces.
8
 
9
  **Relationship to `research-article-template`**: the CSS foundation, design tokens, and visual language come from the [research-article-template](https://huggingface.co/spaces/tfrere/research-article-template) project. The editor imports the template's CSS files (`_variables.css`, `_reset.css`, `_base.css`, `_layout.css`, component partials) and the publisher injects them inline into published HTML. The published output is designed to look identical to articles built with the Astro-based template.
10
 
@@ -152,7 +152,7 @@ flowchart LR
152
  ### 5.1 App Shell
153
 
154
  - **No router** - single view with conditional rendering
155
- - **Theme**: MUI `ThemeProvider` with dynamic primary color from `settings.primaryHue` (OKLCH color model)
156
  - **Layout**: top bar (undo/redo, settings, publish, user chip) + 3-column CSS grid (TOC / editor / comments)
157
  - **Chat**: floating button bottom-left, `ChatPanel` overlay
158
  - **Modals**: comment dialog, settings drawer, publish confirmation
@@ -198,7 +198,7 @@ Registry-based system for MDX-like custom components:
198
  | `rawHtml` | atomic | Raw HTML injection |
199
  | `mermaid` | atomic | Mermaid diagram (live preview) |
200
 
201
- - **Factory**: `createWrapperExtension(def)` / `createAtomicExtension(def)` generate TipTap nodes from registry definitions
202
  - **NodeViews**: `WrapperView` (editable content area + chrome), `AtomicView` (placeholder + field editor), `MermaidView` (textarea + SVG preview)
203
  - **Slash menu integration**: each component generates a slash menu item via `getComponentSlashItems()`
204
 
@@ -214,7 +214,7 @@ Registry-based system for MDX-like custom components:
214
 
215
  - **`TableOfContents`**: extracts headings from TipTap doc, scroll-based active state, collapsible sub-sections
216
  - **`ChatPanel`**: message list + quick actions on selection + input with streaming
217
- - **`CommentsSidebar`**: positioned comment threads with resolve/delete
218
  - **`BubbleToolbar`**: floating toolbar on text selection (bold, italic, link, comment, etc.)
219
  - **`BlockHandle`**: drag handle for block-level nodes
220
 
@@ -222,25 +222,30 @@ Registry-based system for MDX-like custom components:
222
 
223
  ```
224
  styles/
225
- _variables.css # Design tokens, --primary-color, breakpoints, @custom-media
226
- _reset.css # Scoped reset (avoids MUI conflicts)
227
  _base.css # Typography, scoped to article content
228
  _layout.css # 3-column grid, .wide/.full-width helpers
229
  _print.css # Print styles
230
- _editor-tokens.css # Editor-specific tokens (accents, syntax)
231
- article.css # .tiptap content styles (shared editor/published concept)
 
232
  toc.css # Editor TOC overrides
233
  editing.css # Editor-only: layout, cursors, slash menu
 
234
  components/
235
  _code.css # Code blocks + syntax highlighting
236
  _table.css # Tables
237
  _tag.css # Tags
238
  _card.css # Cards
239
  _mermaid.css # Mermaid diagrams
 
 
240
  _hero.css # Hero section (from template)
241
  _toc.css # Base TOC styles (from template)
242
- _button.css # NOT imported in editor (MUI conflict)
243
- _form.css # NOT imported in editor (MUI conflict)
 
244
  ```
245
 
246
  The publisher reads these same CSS files server-side and injects them inline into published HTML, using `resolveCustomMedia()` to expand `@custom-media` queries into standard `@media` rules.
@@ -389,7 +394,7 @@ sequenceDiagram
389
 
390
  ## 8. Current Limitations and Known Issues
391
 
392
- - **No test suite**: zero tests across backend and frontend
393
  - **Single document**: only `"default"` document supported; no multi-doc
394
  - **Single-user token**: last OAuth token cached globally for all HF API calls
395
  - **No rate limiting** on `/api/chat` or `/api/citations/*`
 
4
 
5
  A collaborative, real-time scientific article editor deployed as a Hugging Face Space. Users write rich content (math, citations, custom components) in a TipTap-based editor synced via Yjs/Hocuspocus, then publish a self-contained static HTML article. An AI assistant helps with writing and editing.
6
 
7
+ **Stack**: React 18 + TipTap 3 + Yjs (frontend) / Express + Hocuspocus + Node 20 (backend) / Docker on HF Spaces. No CSS-in-JS - all styling via vanilla CSS custom properties.
8
 
9
  **Relationship to `research-article-template`**: the CSS foundation, design tokens, and visual language come from the [research-article-template](https://huggingface.co/spaces/tfrere/research-article-template) project. The editor imports the template's CSS files (`_variables.css`, `_reset.css`, `_base.css`, `_layout.css`, component partials) and the publisher injects them inline into published HTML. The published output is designed to look identical to articles built with the Astro-based template.
10
 
 
152
  ### 5.1 App Shell
153
 
154
  - **No router** - single view with conditional rendering
155
+ - **Theme**: CSS custom properties with dynamic primary color from `settings.primaryHue` (OKLCH color model, synced via Yjs settings)
156
  - **Layout**: top bar (undo/redo, settings, publish, user chip) + 3-column CSS grid (TOC / editor / comments)
157
  - **Chat**: floating button bottom-left, `ChatPanel` overlay
158
  - **Modals**: comment dialog, settings drawer, publish confirmation
 
198
  | `rawHtml` | atomic | Raw HTML injection |
199
  | `mermaid` | atomic | Mermaid diagram (live preview) |
200
 
201
+ - **Factory**: `createComponentExtension(def)` generates TipTap nodes from registry definitions (handles both wrapper and atomic kinds)
202
  - **NodeViews**: `WrapperView` (editable content area + chrome), `AtomicView` (placeholder + field editor), `MermaidView` (textarea + SVG preview)
203
  - **Slash menu integration**: each component generates a slash menu item via `getComponentSlashItems()`
204
 
 
214
 
215
  - **`TableOfContents`**: extracts headings from TipTap doc, scroll-based active state, collapsible sub-sections
216
  - **`ChatPanel`**: message list + quick actions on selection + input with streaming
217
+ - **`CommentPopover`**: positioned comment popover anchored to the active thread (resolve/delete inline)
218
  - **`BubbleToolbar`**: floating toolbar on text selection (bold, italic, link, comment, etc.)
219
  - **`BlockHandle`**: drag handle for block-level nodes
220
 
 
222
 
223
  ```
224
  styles/
225
+ _variables.css # Template tokens: --primary-color, breakpoints, @custom-media
226
+ _reset.css # Scoped reset for article content
227
  _base.css # Typography, scoped to article content
228
  _layout.css # 3-column grid, .wide/.full-width helpers
229
  _print.css # Print styles
230
+ _ui.css # Editor chrome: buttons, dialogs, drawers, spinner
231
+ tokens.css # Design tokens (light/dark): text, bg, accent, code, danger, shadows
232
+ article.css # .tiptap content styles (shared editor/published)
233
  toc.css # Editor TOC overrides
234
  editing.css # Editor-only: layout, cursors, slash menu
235
+ _publisher.css # Published-only: theme toggle, wide/fullWidth, footer, lightbox
236
  components/
237
  _code.css # Code blocks + syntax highlighting
238
  _table.css # Tables
239
  _tag.css # Tags
240
  _card.css # Cards
241
  _mermaid.css # Mermaid diagrams
242
+ _embed.css # Embed containers
243
+ _embed-studio.css # Embed studio overlay
244
  _hero.css # Hero section (from template)
245
  _toc.css # Base TOC styles (from template)
246
+ _button.css # Buttons (template)
247
+ _form.css # Form elements (template)
248
+ _footer.css # Footer (template)
249
  ```
250
 
251
  The publisher reads these same CSS files server-side and injects them inline into published HTML, using `resolveCustomMedia()` to expand `@custom-media` queries into standard `@media` rules.
 
394
 
395
  ## 8. Current Limitations and Known Issues
396
 
397
+ - **Test suite in progress**: P0 tests being added (see `docs/TESTS.md`)
398
  - **Single document**: only `"default"` document supported; no multi-doc
399
  - **Single-user token**: last OAuth token cached globally for all HF API calls
400
  - **No rate limiting** on `/api/chat` or `/api/citations/*`