@consilioweb/spellcheck 0.10.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ConsilioWEB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,567 @@
1
+ <p align="center">
2
+ <img src="https://readme-typing-svg.demolab.com?font=Fira+Code&weight=600&size=28&pause=1000&color=2563EB&center=true&vCenter=true&width=600&lines=@consilioweb/spellcheck;Payload+CMS+Spellcheck+Plugin;LanguageTool+%2B+Claude+AI;Dashboard+%2B+Sidebar+%2B+Auto-check" alt="Typing SVG" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@consilioweb/spellcheck"><img src="https://img.shields.io/npm/v/@consilioweb/spellcheck?color=2563eb&label=npm" alt="npm version" /></a>
7
+ <a href="https://www.npmjs.com/package/@consilioweb/spellcheck"><img src="https://img.shields.io/npm/dm/@consilioweb/spellcheck?color=22c55e" alt="npm downloads" /></a>
8
+ <img src="https://img.shields.io/badge/Payload_CMS-3.x-blue" alt="Payload CMS 3.x" />
9
+ <img src="https://img.shields.io/badge/LanguageTool-API-green" alt="LanguageTool" />
10
+ <img src="https://img.shields.io/badge/i18n-FR%20%2F%20EN-purple" alt="i18n" />
11
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow" alt="MIT License" /></a>
12
+ <img src="https://img.shields.io/badge/TypeScript-5.x-3178c6" alt="TypeScript" />
13
+ </p>
14
+
15
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
16
+
17
+ ## About
18
+
19
+ **@consilioweb/spellcheck** is a Payload CMS 3 plugin that adds real-time spelling and grammar checking to your admin panel. Powered by [LanguageTool](https://languagetool.org/) with optional Claude AI semantic analysis.
20
+
21
+ | Feature | Description |
22
+ |---------|-------------|
23
+ | **Dashboard** | Full admin view at `/admin/spellcheck` with bulk scanning |
24
+ | **Sidebar Field** | Real-time spellcheck score + issues in the editor |
25
+ | **Auto-check** | Fire-and-forget hook checks content on every save |
26
+ | **One-click Fix** | Apply corrections directly in Lexical JSON |
27
+ | **LanguageTool** | Grammar, spelling, punctuation via free API |
28
+ | **Claude AI** | Optional semantic analysis (coherence, tone, phrasing) |
29
+ | **Custom Dictionary** | Whitelist tech terms, brand names, proper nouns |
30
+ | **Dynamic Dictionary** | Add/remove words from admin UI, persists in DB |
31
+ | **Offset-based Fix** | Precise corrections using LanguageTool offsets |
32
+ | **Ignore Issues** | Dismiss false positives (persists across reloads) |
33
+ | **i18n** | French and English UI translations |
34
+
35
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
36
+
37
+ ## Table of Contents
38
+
39
+ - [Features](#features)
40
+ - [Installation](#installation)
41
+ - [Quick Start](#quick-start)
42
+ - [Configuration](#configuration)
43
+ - [Admin Views](#admin-views)
44
+ - [Dynamic Dictionary](#dynamic-dictionary)
45
+ - [API Endpoints](#api-endpoints)
46
+ - [Engine](#engine)
47
+ - [Package Exports](#package-exports)
48
+ - [Uninstall](#uninstall)
49
+ - [Changelog](#changelog)
50
+ - [License](#license)
51
+
52
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
53
+
54
+ ## Features
55
+
56
+ ### Dashboard (`/admin/spellcheck`)
57
+
58
+ - **Tabbed interface** — Results tab + Dictionary tab
59
+ - **Selective scan** — Check specific pages or all documents at once
60
+ - **Checkbox selection** — Pick individual documents to scan
61
+ - **Collection filter** — Filter by collection (pages, posts, etc.)
62
+ - **Sortable table** — Sort by score, issues, word count, last checked
63
+ - **Expandable rows** — Click a document to see all issues inline
64
+ - **Before/After diff** — Visual comparison of original vs corrected text
65
+ - **Multiple suggestions** — Dropdown to choose between alternative corrections
66
+ - **One-click fix** — Apply corrections directly (issue removed from UI + DB)
67
+ - **Ignore button** — Dismiss false positives (persists in DB across reloads)
68
+ - **Add to dictionary** — Whitelist a word directly from an issue card
69
+ - **Summary cards** — Total documents, average score, issues count
70
+
71
+ ### Sidebar Field
72
+
73
+ - **Score badge** — Color-coded score (green/yellow/red) in the editor sidebar
74
+ - **Issue list** — All issues with context, suggestions, and fix buttons
75
+ - **Manual check** — "Vérifier" button for on-demand analysis
76
+ - **Auto-check** — Results loaded automatically from last check
77
+
78
+ ### Auto-check on Save
79
+
80
+ - **Non-blocking** — Fire-and-forget async (IIFE pattern, does not slow down saves)
81
+ - **Upsert results** — Stores/updates results in `spellcheck-results` collection
82
+ - **Configurable** — Enable/disable via `checkOnSave` option
83
+
84
+ ### LanguageTool Engine
85
+
86
+ - **Free API** — No API key required (public LanguageTool API)
87
+ - **Rate-limited** — 3-second delay between requests for bulk scans
88
+ - **18K char limit** — Automatic text truncation for API compliance
89
+ - **Smart filtering** — Skip premium rules, typography, style-only issues
90
+ - **Custom dictionary** — Whitelist words that shouldn't be flagged
91
+
92
+ ### Claude AI Fallback (Optional)
93
+
94
+ - **Semantic analysis** — Checks coherence, tone, phrasing, missing words
95
+ - **Complementary** — Does NOT duplicate LanguageTool (no spelling/grammar)
96
+ - **Cost-efficient** — Uses Claude Haiku for fast, cheap analysis
97
+ - **Opt-in** — Disabled by default, enable via `enableAiFallback: true`
98
+
99
+ ### Dynamic Dictionary
100
+
101
+ - **Admin UI** — Manage dictionary from the "Dictionnaire" tab in the dashboard
102
+ - **Add words** — Single word or comma-separated bulk input
103
+ - **Import** — Paste a list of words (one per line or comma-separated)
104
+ - **Export** — Download all dictionary words as a `.txt` file
105
+ - **Search & filter** — Find words in the dictionary
106
+ - **Bulk delete** — Select and remove multiple words at once
107
+ - **Merged sources** — Config `customDictionary` (defaults) + DB dictionary (dynamic)
108
+ - **5-min cache** — Dictionary loaded from DB with in-memory TTL cache
109
+ - **Auto-schema** — Plugin auto-creates missing DB columns on init (SQLite/Postgres)
110
+
111
+ ### Lexical JSON Support
112
+
113
+ - **Recursive extraction** — Traverses Lexical AST to extract plain text
114
+ - **Code block skip** — Ignores code blocks (not natural language)
115
+ - **Offset-based fixes** — Precise corrections using LanguageTool offsets (v0.8.0+)
116
+ - **Legacy fallback** — Substring search for backwards compatibility
117
+ - **Multi-field** — Extracts from hero, content, layout blocks, columns
118
+
119
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
120
+
121
+ ## Installation
122
+
123
+ ```bash
124
+ # npm
125
+ npm install @consilioweb/spellcheck
126
+
127
+ # pnpm
128
+ pnpm add @consilioweb/spellcheck
129
+
130
+ # yarn
131
+ yarn add @consilioweb/spellcheck
132
+ ```
133
+
134
+ | Peer Dependency | Version |
135
+ |----------------|---------|
136
+ | `payload` | `^3.0.0` |
137
+ | `@payloadcms/next` | `^3.0.0` |
138
+ | `@payloadcms/ui` | `^3.0.0` |
139
+ | `react` | `^18.0.0 \|\| ^19.0.0` |
140
+
141
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
142
+
143
+ ## Quick Start
144
+
145
+ Add the plugin to your Payload config:
146
+
147
+ ```typescript
148
+ // src/plugins/index.ts (or payload.config.ts)
149
+ import { spellcheckPlugin } from '@consilioweb/spellcheck'
150
+
151
+ export default buildConfig({
152
+ plugins: [
153
+ spellcheckPlugin({
154
+ collections: ['pages', 'posts'],
155
+ language: 'fr',
156
+ }),
157
+ ],
158
+ })
159
+ ```
160
+
161
+ Then regenerate the import map:
162
+
163
+ ```bash
164
+ npx payload generate:importmap
165
+ ```
166
+
167
+ That's it! The plugin automatically:
168
+ - Creates `spellcheck-results` and `spellcheck-dictionary` collections (hidden from admin nav)
169
+ - Registers API endpoints (`validate`, `fix`, `bulk`, `status`, `dictionary`)
170
+ - Adds a sidebar field to your target collections
171
+ - Creates a dashboard view at `/admin/spellcheck` (Results + Dictionary tabs)
172
+ - Adds an `afterChange` hook for auto-checking on save
173
+ - Auto-fixes missing DB columns on init (SQLite/Postgres `push:true` compatibility)
174
+
175
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
176
+
177
+ ## Configuration
178
+
179
+ ```typescript
180
+ spellcheckPlugin({
181
+ // Target collections (default: ['pages', 'posts'])
182
+ collections: ['pages', 'posts'],
183
+
184
+ // Rich text field name (default: 'content')
185
+ contentField: 'content',
186
+
187
+ // LanguageTool language (default: 'fr')
188
+ language: 'fr',
189
+
190
+ // Auto-check on save (default: true)
191
+ checkOnSave: true,
192
+
193
+ // Sidebar field in editor (default: true)
194
+ addSidebarField: true,
195
+
196
+ // Dashboard view at /admin/spellcheck (default: true)
197
+ addDashboardView: true,
198
+
199
+ // Base path for API endpoints (default: '/spellcheck')
200
+ endpointBasePath: '/spellcheck',
201
+
202
+ // ── Filtering ──────────────────────────────────────
203
+
204
+ // LanguageTool rule IDs to skip
205
+ skipRules: ['FR_SPELLING_RULE', 'WHITESPACE_RULE'],
206
+
207
+ // LanguageTool categories to skip
208
+ skipCategories: ['TYPOGRAPHY', 'STYLE'],
209
+
210
+ // Words to never flag as errors
211
+ customDictionary: [
212
+ 'Next.js', 'Payload', 'TypeScript', 'SEO',
213
+ 'Corrèze', 'Limoges', 'ConsilioWEB',
214
+ ],
215
+
216
+ // Minimum score threshold for warnings (default: 80)
217
+ warningThreshold: 80,
218
+
219
+ // ── Claude AI Fallback (optional) ──────────────────
220
+
221
+ // Enable semantic analysis via Claude (default: false)
222
+ enableAiFallback: false,
223
+
224
+ // Anthropic API key (required if enableAiFallback is true)
225
+ anthropicApiKey: process.env.ANTHROPIC_API_KEY,
226
+ })
227
+ ```
228
+
229
+ ### Options Reference
230
+
231
+ | Option | Type | Default | Description |
232
+ |--------|------|---------|-------------|
233
+ | `collections` | `string[]` | `['pages', 'posts']` | Collections to check |
234
+ | `contentField` | `string` | `'content'` | Rich text field name |
235
+ | `language` | `string` | `'fr'` | LanguageTool language code |
236
+ | `checkOnSave` | `boolean` | `true` | Auto-check on document save |
237
+ | `addSidebarField` | `boolean` | `true` | Add sidebar field in editor |
238
+ | `addDashboardView` | `boolean` | `true` | Add `/admin/spellcheck` view |
239
+ | `endpointBasePath` | `string` | `'/spellcheck'` | Base path for API endpoints |
240
+ | `enableAiFallback` | `boolean` | `false` | Enable Claude AI semantic analysis |
241
+ | `anthropicApiKey` | `string` | — | Anthropic API key for Claude |
242
+ | `skipRules` | `string[]` | `[]` | LanguageTool rule IDs to skip |
243
+ | `skipCategories` | `string[]` | `[]` | LanguageTool categories to skip |
244
+ | `customDictionary` | `string[]` | `[]` | Words to never flag |
245
+ | `warningThreshold` | `number` | `80` | Score below which a warning is shown |
246
+
247
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
248
+
249
+ ## Admin Views
250
+
251
+ ### Dashboard (`/admin/spellcheck`)
252
+
253
+ The dashboard provides a complete overview of your content's spelling quality:
254
+
255
+ - **Summary cards** — Document count, average score, total issues, error-free count
256
+ - **Sortable table** — Click column headers to sort by score, issues, words, date
257
+ - **Expandable rows** — Click any row to see detailed issues with context and suggestions
258
+ - **Bulk scan** — "Scanner tout" analyzes all published documents sequentially
259
+ - **One-click fix** — Apply a correction directly from the expanded issue view
260
+
261
+ ### Sidebar Field
262
+
263
+ The sidebar field appears in the editor for every target collection:
264
+
265
+ - **Score badge** — Color-coded (green ≥95, yellow ≥80, red <80)
266
+ - **Stats bar** — Word count, issue count, last check time
267
+ - **Issue cards** — Each issue shows message, context with highlighted error, suggestion
268
+ - **Fix button** — Applies the suggestion directly in the Lexical JSON
269
+ - **Ignore button** — Removes the issue from the current view
270
+
271
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
272
+
273
+ ## API Endpoints
274
+
275
+ All endpoints require authentication (Payload admin user).
276
+
277
+ | Endpoint | Method | Description |
278
+ |----------|--------|-------------|
279
+ | `/api/spellcheck/validate` | `POST` | Check a single document or raw text |
280
+ | `/api/spellcheck/fix` | `POST` | Apply a correction in Lexical JSON (offset-based) |
281
+ | `/api/spellcheck/bulk` | `POST` | Scan all documents (sequential, rate-limited) |
282
+ | `/api/spellcheck/status` | `GET` | Get current bulk scan progress |
283
+ | `/api/spellcheck/dictionary` | `GET` | List all dictionary words |
284
+ | `/api/spellcheck/dictionary` | `POST` | Add word(s) to dictionary |
285
+ | `/api/spellcheck/dictionary` | `DELETE` | Remove word(s) from dictionary |
286
+
287
+ ### POST `/api/spellcheck/validate`
288
+
289
+ ```json
290
+ // Check a document by ID
291
+ { "id": "123", "collection": "pages" }
292
+
293
+ // Check raw text
294
+ { "text": "Ceci est une test.", "language": "fr" }
295
+ ```
296
+
297
+ **Response:**
298
+
299
+ ```json
300
+ {
301
+ "docId": "123",
302
+ "collection": "pages",
303
+ "score": 85,
304
+ "issueCount": 2,
305
+ "wordCount": 450,
306
+ "issues": [
307
+ {
308
+ "ruleId": "GRAMMAR",
309
+ "category": "GRAMMAR",
310
+ "message": "Le déterminant « une » ne correspond pas...",
311
+ "context": "Ceci est une test.",
312
+ "original": "une",
313
+ "replacements": ["un"],
314
+ "source": "languagetool"
315
+ }
316
+ ],
317
+ "lastChecked": "2025-02-22T20:30:00.000Z"
318
+ }
319
+ ```
320
+
321
+ ### POST `/api/spellcheck/fix`
322
+
323
+ ```json
324
+ {
325
+ "id": "123",
326
+ "collection": "pages",
327
+ "original": "une test",
328
+ "replacement": "un test",
329
+ "offset": 42,
330
+ "length": 8
331
+ }
332
+ ```
333
+
334
+ > `offset` and `length` enable precise offset-based targeting (v0.8.0+). Falls back to substring search if omitted.
335
+
336
+ ### GET `/api/spellcheck/dictionary`
337
+
338
+ **Response:**
339
+
340
+ ```json
341
+ { "words": [{ "id": "1", "word": "typescript", "addedBy": { "email": "admin@example.com" }, "createdAt": "..." }], "count": 1 }
342
+ ```
343
+
344
+ ### POST `/api/spellcheck/dictionary`
345
+
346
+ ```json
347
+ // Single word
348
+ { "word": "TypeScript" }
349
+
350
+ // Multiple words
351
+ { "words": ["TypeScript", "Next.js", "Payload"] }
352
+ ```
353
+
354
+ ### DELETE `/api/spellcheck/dictionary`
355
+
356
+ ```json
357
+ // Single
358
+ { "id": "abc123" }
359
+
360
+ // Multiple
361
+ { "ids": ["abc123", "def456"] }
362
+ ```
363
+
364
+ ### POST `/api/spellcheck/bulk`
365
+
366
+ ```json
367
+ // Scan all configured collections
368
+ {}
369
+
370
+ // Scan a specific collection
371
+ { "collection": "posts" }
372
+ ```
373
+
374
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
375
+
376
+ ## Engine
377
+
378
+ ### Text Extraction
379
+
380
+ The plugin extracts text from Payload documents by recursively traversing:
381
+
382
+ 1. **Title** — Document title
383
+ 2. **Hero** — `hero.richText` (Lexical JSON)
384
+ 3. **Content** — Main content field (Lexical JSON)
385
+ 4. **Layout blocks** — Each block's `richText` and `columns[].richText`
386
+
387
+ Code blocks are automatically skipped (not natural language).
388
+
389
+ ### LanguageTool
390
+
391
+ - **API**: `POST https://api.languagetool.org/v2/check` (free, no auth)
392
+ - **Limit**: 18,000 characters per request (auto-truncated)
393
+ - **Rate**: 3-second delay between bulk requests
394
+ - **Timeout**: 30 seconds per request
395
+
396
+ ### Filtering
397
+
398
+ Issues are filtered through multiple layers:
399
+
400
+ 1. **Premium rules** — Skipped (free API only)
401
+ 2. **Configured rules** — `skipRules` option
402
+ 3. **Configured categories** — `skipCategories` option
403
+ 4. **Custom dictionary** — Case-insensitive word matching
404
+ 5. **Single-character** — Skipped (often punctuation false positives)
405
+
406
+ ### Scoring
407
+
408
+ Score = `max(0, 100 - (issues / words * 1000))`
409
+
410
+ - **100** — No issues
411
+ - **90+** — Excellent (green)
412
+ - **80+** — Good (yellow)
413
+ - **<80** — Needs work (red)
414
+
415
+ ### Claude AI (Optional)
416
+
417
+ When `enableAiFallback: true`, the plugin also sends text to Claude Haiku for:
418
+
419
+ - Inconsistent tone or register
420
+ - Incoherent statements or contradictions
421
+ - Awkward phrasing
422
+ - Missing words that change meaning
423
+
424
+ Claude issues are tagged with `source: 'claude'` and category `COHERENCE`, `TONE`, `PHRASING`, or `MISSING_WORD`.
425
+
426
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
427
+
428
+ ## Collections
429
+
430
+ The plugin auto-creates two collections:
431
+
432
+ | Collection | Slug | Description |
433
+ |------------|------|-------------|
434
+ | SpellCheck Results | `spellcheck-results` | Stores check results per document |
435
+ | SpellCheck Dictionary | `spellcheck-dictionary` | Dynamic dictionary (one doc per word) |
436
+
437
+ **Results fields**: `docId`, `collection`, `title`, `slug`, `score`, `issueCount`, `wordCount`, `issues` (JSON), `lastChecked`
438
+
439
+ **Dictionary fields**: `word` (text, unique, indexed), `addedBy` (relationship to users)
440
+
441
+ Both collections are hidden from the admin nav. The dictionary is managed via the Dashboard's "Dictionnaire" tab or the REST API.
442
+
443
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
444
+
445
+ ## Package Exports
446
+
447
+ ### Main Entry (`@consilioweb/spellcheck`)
448
+
449
+ ```typescript
450
+ // Plugin
451
+ export { spellcheckPlugin } from './plugin'
452
+
453
+ // Types
454
+ export type { SpellCheckPluginConfig, SpellCheckIssue, SpellCheckResult } from './types'
455
+
456
+ // Engine (for programmatic use)
457
+ export { extractTextFromLexical, countWords } from './engine/lexicalParser'
458
+ export { checkWithLanguageTool } from './engine/languagetool'
459
+ export { checkWithClaude } from './engine/claude'
460
+ export { filterFalsePositives, calculateScore } from './engine/filters'
461
+
462
+ // Dictionary cache
463
+ export { loadDictionaryWords, invalidateDictionaryCache } from './endpoints/dictionary'
464
+
465
+ // i18n
466
+ export { getTranslations, getScoreLabel } from './i18n'
467
+ ```
468
+
469
+ ### Client Entry (`@consilioweb/spellcheck/client`)
470
+
471
+ ```typescript
472
+ export { SpellCheckField } from './components/SpellCheckField'
473
+ export { SpellCheckDashboard } from './components/SpellCheckDashboard'
474
+ export { IssueCard } from './components/IssueCard'
475
+ ```
476
+
477
+ ### Views Entry (`@consilioweb/spellcheck/views`)
478
+
479
+ ```typescript
480
+ export { SpellCheckView } from './views/SpellCheckView'
481
+ ```
482
+
483
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
484
+
485
+ ## Requirements
486
+
487
+ - **Node.js** >= 18
488
+ - **Payload CMS** 3.x
489
+ - **React** 18.x or 19.x
490
+ - **Any Payload DB adapter** (SQLite, PostgreSQL, MongoDB)
491
+
492
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
493
+
494
+ ## Uninstall
495
+
496
+ ### Automatic (recommended)
497
+
498
+ ```bash
499
+ npx spellcheck-uninstall
500
+ ```
501
+
502
+ This will:
503
+ 1. Remove all `@consilioweb/spellcheck` imports and plugin calls from your source files
504
+ 2. Drop the `spellcheck_results` table and indexes from your database
505
+ 3. Remove the npm package
506
+ 4. Regenerate the import map
507
+
508
+ > Use `--keep-data` to preserve the database table.
509
+
510
+ ### Manual
511
+
512
+ 1. Remove the plugin from your config
513
+ 2. Run `npx payload generate:importmap`
514
+ 3. (Optional) Drop the database table:
515
+
516
+ ```sql
517
+ -- SQLite
518
+ DROP INDEX IF EXISTS `spellcheck_results_doc_id_idx`;
519
+ DROP INDEX IF EXISTS `spellcheck_results_collection_idx`;
520
+ DROP INDEX IF EXISTS `spellcheck_results_last_checked_idx`;
521
+ DROP TABLE IF EXISTS `spellcheck_results`;
522
+ ```
523
+
524
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
525
+
526
+ ## Changelog
527
+
528
+ ### v0.8.1
529
+
530
+ - **Fix**: Corrections now remove the issue from the UI immediately (optimistic update)
531
+ - **Fix**: "Ignorer" persists in DB across page reloads (was local state only)
532
+ - **Fix**: Auto-fix missing DB columns on init (`push:true` compatibility for SQLite/Postgres)
533
+
534
+ ### v0.8.0
535
+
536
+ - **New**: Dynamic dictionary — manage words from the admin dashboard (add/remove/import/export)
537
+ - **New**: `spellcheck-dictionary` collection (one document per word, merged with config dictionary)
538
+ - **New**: Dictionary REST API (GET/POST/DELETE at `/api/spellcheck/dictionary`)
539
+ - **New**: Offset-based corrections — precise fix targeting using LanguageTool offsets
540
+ - **New**: "Add to dictionary" button on issue cards (+ Dico)
541
+ - **New**: "Ignore" button to dismiss false positives
542
+ - **New**: Dictionary tab in the dashboard with search, bulk delete, import/export
543
+ - **New**: In-memory cache (5-min TTL) for dictionary DB queries
544
+ - **Changed**: `filterFalsePositives` is now async (merges config + DB dictionaries)
545
+ - **Changed**: Fix endpoint accepts `offset` and `length` parameters (falls back to substring search)
546
+
547
+ ### v0.5.0 — v0.7.0
548
+
549
+ - Custom dictionary config, contextual multi-word filtering, background scan
550
+ - Lexical ghost space fix, extended French dictionary
551
+ - Contextual offset, manual edit input, repetition filter
552
+
553
+ <img src="https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/rainbow.png" alt="-----" />
554
+
555
+ ## License
556
+
557
+ MIT License - see [LICENSE](LICENSE) for details.
558
+
559
+ <p align="center">
560
+ <br />
561
+ Made with ❤️ by <a href="https://consilioweb.fr">ConsilioWEB</a>
562
+ <br />
563
+ <br />
564
+ <a href="https://www.linkedin.com/in/christophe-lopez-dev/"><img src="https://img.shields.io/badge/LinkedIn-0A66C2?logo=linkedin&logoColor=white" alt="LinkedIn" /></a>
565
+ <a href="https://github.com/pOwn3d"><img src="https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white" alt="GitHub" /></a>
566
+ <a href="https://consilioweb.fr"><img src="https://img.shields.io/badge/Web-consilioweb.fr-2563eb" alt="Website" /></a>
567
+ </p>