Scientific Editor
The Zemna.AI Scientific Editor is a Tiptap-based rich text editor built for academic writing. It includes LaTeX equation support, automatic saving, version history, and publication persistence via the Ring Platform database layer.
Status: Phase 2 (Sprints 2.1–2.3) complete. Figure/table support and export are planned for Sprints 2.4–2.5.
Overview
| Feature | Description |
|---|---|
| Rich text | Headings (H1–H6), bold, italic, underline, lists, block quotes, code blocks, tables, links, images |
| LaTeX | Inline and display math via KaTeX; equation modal with live preview and templates |
| Auto-save | 30-second debounced save; first save creates a publication, then updates via PUT |
| Version history | Snapshot and restore versions; list versions with timestamps and optional summaries |
| Publications | Content stored as Tiptap JSON; load by URL ?id=... or create new |
Editor Features
Rich Text (Tiptap)
The editor uses Tiptap with StarterKit and extensions for scientific writing:
- Formatting: Bold, italic, underline, strikethrough, superscript, subscript, highlight
- Structure: Headings H1–H6, ordered/unordered lists, block quotes
- Blocks: Code blocks (syntax highlighting via lowlight), tables (rows, columns, header)
- Inline: Links, images (placeholder support)
- Typography: Smart quotes and typography improvements
Content is stored as Tiptap JSON in the publication content field; the editor accepts initial content as either HTML string or JSON for loading saved publications.
LaTeX Equations
- Block math: Insert display-mode equations via the toolbar (Calculator icon) or equation modal.
- Rendering: KaTeX renders equations in the editor; click to edit opens the equation modal.
- Modal: LaTeX textarea, display/inline toggle, live preview, template buttons (fraction, sum, integral, matrix), Insert/Cancel.
Equations are stored as custom Tiptap nodes (mathBlock) with latex and display attributes.
Auto-Save & Publications
- New document: No
?id=in URL; first Save or first auto-save creates a publication viaPOST /api/publicationsand sets the publication id for subsequent saves. - Existing document: Open with
?id=<publicationId>; the page loads the publication and sets title and content (JSON). Auto-save and manual Save usePUT /api/publications/:id. - Debounce: Changes to title or content trigger a 30-second debounced save; manual Save triggers an immediate save.
- Save indicator: Toolbar shows "Saved" with timestamp when the last save completed successfully.
Version History
- Panel: Version History button in the toolbar opens a dialog listing versions (version number, date, optional summary).
- Snapshot: "Save snapshot" creates a new version with the current content (optional change summary).
- Restore: "Restore" on a version updates the publication content to that version and refetches the editor; the panel closes and the editor shows the restored content.
Architecture
Publication schema
Publications and versions use the Ring Platform database abstraction (PostgreSQL with JSONB):
publications:id,data(JSONB),created_at,updated_at.
dataholds:user_id,title,content(Tiptap JSON),status,template_id.publication_versions:id,data(JSONB),created_at,updated_at.
dataholds:publication_id,version_number,content,change_summary,created_by.
Schema is defined in data/schema.sql; the PostgreSQL adapter has fieldMappings for both collections.
Save flow
sequenceDiagram
participant User
participant Editor
participant useAutoSave
participant API
participant DB
User->>Editor: Edit content / title
Editor->>useAutoSave: touch(publicationId, payload)
useAutoSave->>useAutoSave: Debounce 30s
Note over useAutoSave: Timer fires
useAutoSave->>API: POST /api/publications (new) or PUT /api/publications/:id
API->>DB: create() or update()
DB-->>API: publication
API-->>useAutoSave: 200 + publication
useAutoSave->>Editor: onFirstSave(id) if new
useAutoSave->>Editor: lastSaved updated
Version history flow
sequenceDiagram
participant User
participant Panel
participant API
participant DB
User->>Panel: Open Version History
Panel->>API: GET /api/publications/:id/versions
API->>DB: findByField(publication_versions, publication_id, id)
DB-->>API: versions[]
API-->>Panel: versions
User->>Panel: Restore version V
Panel->>API: POST /api/publications/:id/versions { action: 'restore', versionId: V }
API->>DB: updatePublication(id, content from V)
DB-->>API: publication
API-->>Panel: 200
Panel->>User: onRestore() → refetch publication, set editor content
API routes
| Method | Path | Description |
|---|---|---|
| GET | /api/publications | List current user's publications |
| POST | /api/publications | Create publication (body: title, content, status, template_id) |
| GET | /api/publications/[id] | Get publication (ownership checked) |
| PUT | /api/publications/[id] | Update publication (ownership checked) |
| DELETE | /api/publications/[id] | Delete publication (ownership checked) |
| GET | /api/publications/[id]/versions | List versions for publication |
| POST | /api/publications/[id]/versions | Snapshot (action: snapshot) or restore (action: restore, versionId) |
All routes require authentication; ownership is enforced for get/update/delete and versions.
Key files
| Area | Path |
|---|---|
| Editor page | app/(authenticated)/[locale]/editor/page.tsx |
| Scientific editor | components/editor/scientific-editor.tsx |
| Toolbar | components/editor/editor-toolbar.tsx |
| LaTeX extension | components/editor/extensions/latex-extension.tsx |
| Equation modal | components/editor/equation-editor.tsx |
| Version history panel | components/editor/version-history-panel.tsx |
| Auto-save hook | hooks/use-auto-save.ts |
| Publication types | features/publications/types/index.ts |
| Publication service | features/publications/services/publication-service.ts |
| API routes | app/(public)/api/publications/ |
| Schema | data/schema.sql |
Usage
Opening the editor
- New publication: Go to
/editor(or/[locale]/editor). The editor loads with the default scientific template; publication id is set on first save. - Existing publication: Go to
/editor?id=<publicationId>. The page fetches the publication and sets the title and content (Tiptap JSON) in the editor.
Saving
- Manual: Click Save in the toolbar. For a new document this creates a publication and sets the id; for an existing document it updates via PUT.
- Auto-save: After 30 seconds without further changes, the current title and content are saved automatically (POST for new, PUT for existing).
Version history
- Click Version History (History icon) in the toolbar.
- Use Save snapshot to create a new version with the current content.
- Use Restore on a version to set the publication content to that version and reload the editor.
Restore does not delete versions; it updates the publication content and leaves the version history intact.
Roadmap (Phase 2 remaining)
- Sprint 2.4: Figure upload component, table editor enhancements, cross-reference extension, FileService integration for images.
- Sprint 2.5: Export (PDF, Word, Markdown) services, export dialog, export button and shortcut.
See Phase 2: Scientific Editor Enhancement for the full sprint breakdown.
Scientific Editor
The Zemna.AI Scientific Editor is a Tiptap-based rich text editor built for academic writing. It includes LaTeX equation support, automatic saving, version history, and publication persistence via the Ring Platform database layer.
Status: Phase 2 (Sprints 2.1–2.3) complete. Figure/table support and export are planned for Sprints 2.4–2.5.
Overview
| Feature | Description |
|---|---|
| Rich text | Headings (H1–H6), bold, italic, underline, lists, block quotes, code blocks, tables, links, images |
| LaTeX | Inline and display math via KaTeX; equation modal with live preview and templates |
| Auto-save | 30-second debounced save; first save creates a publication, then updates via PUT |
| Version history | Snapshot and restore versions; list versions with timestamps and optional summaries |
| Publications | Content stored as Tiptap JSON; load by URL ?id=... or create new |
Editor Features
Rich Text (Tiptap)
The editor uses Tiptap with StarterKit and extensions for scientific writing:
- Formatting: Bold, italic, underline, strikethrough, superscript, subscript, highlight
- Structure: Headings H1–H6, ordered/unordered lists, block quotes
- Blocks: Code blocks (syntax highlighting via lowlight), tables (rows, columns, header)
- Inline: Links, images (placeholder support)
- Typography: Smart quotes and typography improvements
Content is stored as Tiptap JSON in the publication content field; the editor accepts initial content as either HTML string or JSON for loading saved publications.
LaTeX Equations
- Block math: Insert display-mode equations via the toolbar (Calculator icon) or equation modal.
- Rendering: KaTeX renders equations in the editor; click to edit opens the equation modal.
- Modal: LaTeX textarea, display/inline toggle, live preview, template buttons (fraction, sum, integral, matrix), Insert/Cancel.
Equations are stored as custom Tiptap nodes (mathBlock) with latex and display attributes.
Auto-Save & Publications
- New document: No
?id=in URL; first Save or first auto-save creates a publication viaPOST /api/publicationsand sets the publication id for subsequent saves. - Existing document: Open with
?id=<publicationId>; the page loads the publication and sets title and content (JSON). Auto-save and manual Save usePUT /api/publications/:id. - Debounce: Changes to title or content trigger a 30-second debounced save; manual Save triggers an immediate save.
- Save indicator: Toolbar shows "Saved" with timestamp when the last save completed successfully.
Version History
- Panel: Version History button in the toolbar opens a dialog listing versions (version number, date, optional summary).
- Snapshot: "Save snapshot" creates a new version with the current content (optional change summary).
- Restore: "Restore" on a version updates the publication content to that version and refetches the editor; the panel closes and the editor shows the restored content.
Architecture
Publication schema
Publications and versions use the Ring Platform database abstraction (PostgreSQL with JSONB):
publications:id,data(JSONB),created_at,updated_at.
dataholds:user_id,title,content(Tiptap JSON),status,template_id.publication_versions:id,data(JSONB),created_at,updated_at.
dataholds:publication_id,version_number,content,change_summary,created_by.
Schema is defined in data/schema.sql; the PostgreSQL adapter has fieldMappings for both collections.
Save flow
sequenceDiagram
participant User
participant Editor
participant useAutoSave
participant API
participant DB
User->>Editor: Edit content / title
Editor->>useAutoSave: touch(publicationId, payload)
useAutoSave->>useAutoSave: Debounce 30s
Note over useAutoSave: Timer fires
useAutoSave->>API: POST /api/publications (new) or PUT /api/publications/:id
API->>DB: create() or update()
DB-->>API: publication
API-->>useAutoSave: 200 + publication
useAutoSave->>Editor: onFirstSave(id) if new
useAutoSave->>Editor: lastSaved updated
Version history flow
sequenceDiagram
participant User
participant Panel
participant API
participant DB
User->>Panel: Open Version History
Panel->>API: GET /api/publications/:id/versions
API->>DB: findByField(publication_versions, publication_id, id)
DB-->>API: versions[]
API-->>Panel: versions
User->>Panel: Restore version V
Panel->>API: POST /api/publications/:id/versions { action: 'restore', versionId: V }
API->>DB: updatePublication(id, content from V)
DB-->>API: publication
API-->>Panel: 200
Panel->>User: onRestore() → refetch publication, set editor content
API routes
| Method | Path | Description |
|---|---|---|
| GET | /api/publications | List current user's publications |
| POST | /api/publications | Create publication (body: title, content, status, template_id) |
| GET | /api/publications/[id] | Get publication (ownership checked) |
| PUT | /api/publications/[id] | Update publication (ownership checked) |
| DELETE | /api/publications/[id] | Delete publication (ownership checked) |
| GET | /api/publications/[id]/versions | List versions for publication |
| POST | /api/publications/[id]/versions | Snapshot (action: snapshot) or restore (action: restore, versionId) |
All routes require authentication; ownership is enforced for get/update/delete and versions.
Key files
| Area | Path |
|---|---|
| Editor page | app/(authenticated)/[locale]/editor/page.tsx |
| Scientific editor | components/editor/scientific-editor.tsx |
| Toolbar | components/editor/editor-toolbar.tsx |
| LaTeX extension | components/editor/extensions/latex-extension.tsx |
| Equation modal | components/editor/equation-editor.tsx |
| Version history panel | components/editor/version-history-panel.tsx |
| Auto-save hook | hooks/use-auto-save.ts |
| Publication types | features/publications/types/index.ts |
| Publication service | features/publications/services/publication-service.ts |
| API routes | app/(public)/api/publications/ |
| Schema | data/schema.sql |
Usage
Opening the editor
- New publication: Go to
/editor(or/[locale]/editor). The editor loads with the default scientific template; publication id is set on first save. - Existing publication: Go to
/editor?id=<publicationId>. The page fetches the publication and sets the title and content (Tiptap JSON) in the editor.
Saving
- Manual: Click Save in the toolbar. For a new document this creates a publication and sets the id; for an existing document it updates via PUT.
- Auto-save: After 30 seconds without further changes, the current title and content are saved automatically (POST for new, PUT for existing).
Version history
- Click Version History (History icon) in the toolbar.
- Use Save snapshot to create a new version with the current content.
- Use Restore on a version to set the publication content to that version and reload the editor.
Restore does not delete versions; it updates the publication content and leaves the version history intact.
Roadmap (Phase 2 remaining)
- Sprint 2.4: Figure upload component, table editor enhancements, cross-reference extension, FileService integration for images.
- Sprint 2.5: Export (PDF, Word, Markdown) services, export dialog, export button and shortcut.
See Phase 2: Scientific Editor Enhancement for the full sprint breakdown.
Scientific Editor
The Zemna.AI Scientific Editor is a Tiptap-based rich text editor built for academic writing. It includes LaTeX equation support, automatic saving, version history, and publication persistence via the Ring Platform database layer.
Status: Phase 2 (Sprints 2.1–2.3) complete. Figure/table support and export are planned for Sprints 2.4–2.5.
Overview
| Feature | Description |
|---|---|
| Rich text | Headings (H1–H6), bold, italic, underline, lists, block quotes, code blocks, tables, links, images |
| LaTeX | Inline and display math via KaTeX; equation modal with live preview and templates |
| Auto-save | 30-second debounced save; first save creates a publication, then updates via PUT |
| Version history | Snapshot and restore versions; list versions with timestamps and optional summaries |
| Publications | Content stored as Tiptap JSON; load by URL ?id=... or create new |
Editor Features
Rich Text (Tiptap)
The editor uses Tiptap with StarterKit and extensions for scientific writing:
- Formatting: Bold, italic, underline, strikethrough, superscript, subscript, highlight
- Structure: Headings H1–H6, ordered/unordered lists, block quotes
- Blocks: Code blocks (syntax highlighting via lowlight), tables (rows, columns, header)
- Inline: Links, images (placeholder support)
- Typography: Smart quotes and typography improvements
Content is stored as Tiptap JSON in the publication content field; the editor accepts initial content as either HTML string or JSON for loading saved publications.
LaTeX Equations
- Block math: Insert display-mode equations via the toolbar (Calculator icon) or equation modal.
- Rendering: KaTeX renders equations in the editor; click to edit opens the equation modal.
- Modal: LaTeX textarea, display/inline toggle, live preview, template buttons (fraction, sum, integral, matrix), Insert/Cancel.
Equations are stored as custom Tiptap nodes (mathBlock) with latex and display attributes.
Auto-Save & Publications
- New document: No
?id=in URL; first Save or first auto-save creates a publication viaPOST /api/publicationsand sets the publication id for subsequent saves. - Existing document: Open with
?id=<publicationId>; the page loads the publication and sets title and content (JSON). Auto-save and manual Save usePUT /api/publications/:id. - Debounce: Changes to title or content trigger a 30-second debounced save; manual Save triggers an immediate save.
- Save indicator: Toolbar shows "Saved" with timestamp when the last save completed successfully.
Version History
- Panel: Version History button in the toolbar opens a dialog listing versions (version number, date, optional summary).
- Snapshot: "Save snapshot" creates a new version with the current content (optional change summary).
- Restore: "Restore" on a version updates the publication content to that version and refetches the editor; the panel closes and the editor shows the restored content.
Architecture
Publication schema
Publications and versions use the Ring Platform database abstraction (PostgreSQL with JSONB):
publications:id,data(JSONB),created_at,updated_at.
dataholds:user_id,title,content(Tiptap JSON),status,template_id.publication_versions:id,data(JSONB),created_at,updated_at.
dataholds:publication_id,version_number,content,change_summary,created_by.
Schema is defined in data/schema.sql; the PostgreSQL adapter has fieldMappings for both collections.
Save flow
sequenceDiagram
participant User
participant Editor
participant useAutoSave
participant API
participant DB
User->>Editor: Edit content / title
Editor->>useAutoSave: touch(publicationId, payload)
useAutoSave->>useAutoSave: Debounce 30s
Note over useAutoSave: Timer fires
useAutoSave->>API: POST /api/publications (new) or PUT /api/publications/:id
API->>DB: create() or update()
DB-->>API: publication
API-->>useAutoSave: 200 + publication
useAutoSave->>Editor: onFirstSave(id) if new
useAutoSave->>Editor: lastSaved updated
Version history flow
sequenceDiagram
participant User
participant Panel
participant API
participant DB
User->>Panel: Open Version History
Panel->>API: GET /api/publications/:id/versions
API->>DB: findByField(publication_versions, publication_id, id)
DB-->>API: versions[]
API-->>Panel: versions
User->>Panel: Restore version V
Panel->>API: POST /api/publications/:id/versions { action: 'restore', versionId: V }
API->>DB: updatePublication(id, content from V)
DB-->>API: publication
API-->>Panel: 200
Panel->>User: onRestore() → refetch publication, set editor content
API routes
| Method | Path | Description |
|---|---|---|
| GET | /api/publications | List current user's publications |
| POST | /api/publications | Create publication (body: title, content, status, template_id) |
| GET | /api/publications/[id] | Get publication (ownership checked) |
| PUT | /api/publications/[id] | Update publication (ownership checked) |
| DELETE | /api/publications/[id] | Delete publication (ownership checked) |
| GET | /api/publications/[id]/versions | List versions for publication |
| POST | /api/publications/[id]/versions | Snapshot (action: snapshot) or restore (action: restore, versionId) |
All routes require authentication; ownership is enforced for get/update/delete and versions.
Key files
| Area | Path |
|---|---|
| Editor page | app/(authenticated)/[locale]/editor/page.tsx |
| Scientific editor | components/editor/scientific-editor.tsx |
| Toolbar | components/editor/editor-toolbar.tsx |
| LaTeX extension | components/editor/extensions/latex-extension.tsx |
| Equation modal | components/editor/equation-editor.tsx |
| Version history panel | components/editor/version-history-panel.tsx |
| Auto-save hook | hooks/use-auto-save.ts |
| Publication types | features/publications/types/index.ts |
| Publication service | features/publications/services/publication-service.ts |
| API routes | app/(public)/api/publications/ |
| Schema | data/schema.sql |
Usage
Opening the editor
- New publication: Go to
/editor(or/[locale]/editor). The editor loads with the default scientific template; publication id is set on first save. - Existing publication: Go to
/editor?id=<publicationId>. The page fetches the publication and sets the title and content (Tiptap JSON) in the editor.
Saving
- Manual: Click Save in the toolbar. For a new document this creates a publication and sets the id; for an existing document it updates via PUT.
- Auto-save: After 30 seconds without further changes, the current title and content are saved automatically (POST for new, PUT for existing).
Version history
- Click Version History (History icon) in the toolbar.
- Use Save snapshot to create a new version with the current content.
- Use Restore on a version to set the publication content to that version and reload the editor.
Restore does not delete versions; it updates the publication content and leaves the version history intact.
Roadmap (Phase 2 remaining)
- Sprint 2.4: Figure upload component, table editor enhancements, cross-reference extension, FileService integration for images.
- Sprint 2.5: Export (PDF, Word, Markdown) services, export dialog, export button and shortcut.
See Phase 2: Scientific Editor Enhancement for the full sprint breakdown.
Scientific Editor
The Zemna.AI Scientific Editor is a Tiptap-based rich text editor built for academic writing. It includes LaTeX equation support, automatic saving, version history, and publication persistence via the Ring Platform database layer.
Status: Phase 2 (Sprints 2.1–2.3) complete. Figure/table support and export are planned for Sprints 2.4–2.5.
Overview
| Feature | Description |
|---|---|
| Rich text | Headings (H1–H6), bold, italic, underline, lists, block quotes, code blocks, tables, links, images |
| LaTeX | Inline and display math via KaTeX; equation modal with live preview and templates |
| Auto-save | 30-second debounced save; first save creates a publication, then updates via PUT |
| Version history | Snapshot and restore versions; list versions with timestamps and optional summaries |
| Publications | Content stored as Tiptap JSON; load by URL ?id=... or create new |
Editor Features
Rich Text (Tiptap)
The editor uses Tiptap with StarterKit and extensions for scientific writing:
- Formatting: Bold, italic, underline, strikethrough, superscript, subscript, highlight
- Structure: Headings H1–H6, ordered/unordered lists, block quotes
- Blocks: Code blocks (syntax highlighting via lowlight), tables (rows, columns, header)
- Inline: Links, images (placeholder support)
- Typography: Smart quotes and typography improvements
Content is stored as Tiptap JSON in the publication content field; the editor accepts initial content as either HTML string or JSON for loading saved publications.
LaTeX Equations
- Block math: Insert display-mode equations via the toolbar (Calculator icon) or equation modal.
- Rendering: KaTeX renders equations in the editor; click to edit opens the equation modal.
- Modal: LaTeX textarea, display/inline toggle, live preview, template buttons (fraction, sum, integral, matrix), Insert/Cancel.
Equations are stored as custom Tiptap nodes (mathBlock) with latex and display attributes.
Auto-Save & Publications
- New document: No
?id=in URL; first Save or first auto-save creates a publication viaPOST /api/publicationsand sets the publication id for subsequent saves. - Existing document: Open with
?id=<publicationId>; the page loads the publication and sets title and content (JSON). Auto-save and manual Save usePUT /api/publications/:id. - Debounce: Changes to title or content trigger a 30-second debounced save; manual Save triggers an immediate save.
- Save indicator: Toolbar shows "Saved" with timestamp when the last save completed successfully.
Version History
- Panel: Version History button in the toolbar opens a dialog listing versions (version number, date, optional summary).
- Snapshot: "Save snapshot" creates a new version with the current content (optional change summary).
- Restore: "Restore" on a version updates the publication content to that version and refetches the editor; the panel closes and the editor shows the restored content.
Architecture
Publication schema
Publications and versions use the Ring Platform database abstraction (PostgreSQL with JSONB):
publications:id,data(JSONB),created_at,updated_at.
dataholds:user_id,title,content(Tiptap JSON),status,template_id.publication_versions:id,data(JSONB),created_at,updated_at.
dataholds:publication_id,version_number,content,change_summary,created_by.
Schema is defined in data/schema.sql; the PostgreSQL adapter has fieldMappings for both collections.
Save flow
sequenceDiagram
participant User
participant Editor
participant useAutoSave
participant API
participant DB
User->>Editor: Edit content / title
Editor->>useAutoSave: touch(publicationId, payload)
useAutoSave->>useAutoSave: Debounce 30s
Note over useAutoSave: Timer fires
useAutoSave->>API: POST /api/publications (new) or PUT /api/publications/:id
API->>DB: create() or update()
DB-->>API: publication
API-->>useAutoSave: 200 + publication
useAutoSave->>Editor: onFirstSave(id) if new
useAutoSave->>Editor: lastSaved updated
Version history flow
sequenceDiagram
participant User
participant Panel
participant API
participant DB
User->>Panel: Open Version History
Panel->>API: GET /api/publications/:id/versions
API->>DB: findByField(publication_versions, publication_id, id)
DB-->>API: versions[]
API-->>Panel: versions
User->>Panel: Restore version V
Panel->>API: POST /api/publications/:id/versions { action: 'restore', versionId: V }
API->>DB: updatePublication(id, content from V)
DB-->>API: publication
API-->>Panel: 200
Panel->>User: onRestore() → refetch publication, set editor content
API routes
| Method | Path | Description |
|---|---|---|
| GET | /api/publications | List current user's publications |
| POST | /api/publications | Create publication (body: title, content, status, template_id) |
| GET | /api/publications/[id] | Get publication (ownership checked) |
| PUT | /api/publications/[id] | Update publication (ownership checked) |
| DELETE | /api/publications/[id] | Delete publication (ownership checked) |
| GET | /api/publications/[id]/versions | List versions for publication |
| POST | /api/publications/[id]/versions | Snapshot (action: snapshot) or restore (action: restore, versionId) |
All routes require authentication; ownership is enforced for get/update/delete and versions.
Key files
| Area | Path |
|---|---|
| Editor page | app/(authenticated)/[locale]/editor/page.tsx |
| Scientific editor | components/editor/scientific-editor.tsx |
| Toolbar | components/editor/editor-toolbar.tsx |
| LaTeX extension | components/editor/extensions/latex-extension.tsx |
| Equation modal | components/editor/equation-editor.tsx |
| Version history panel | components/editor/version-history-panel.tsx |
| Auto-save hook | hooks/use-auto-save.ts |
| Publication types | features/publications/types/index.ts |
| Publication service | features/publications/services/publication-service.ts |
| API routes | app/(public)/api/publications/ |
| Schema | data/schema.sql |
Usage
Opening the editor
- New publication: Go to
/editor(or/[locale]/editor). The editor loads with the default scientific template; publication id is set on first save. - Existing publication: Go to
/editor?id=<publicationId>. The page fetches the publication and sets the title and content (Tiptap JSON) in the editor.
Saving
- Manual: Click Save in the toolbar. For a new document this creates a publication and sets the id; for an existing document it updates via PUT.
- Auto-save: After 30 seconds without further changes, the current title and content are saved automatically (POST for new, PUT for existing).
Version history
- Click Version History (History icon) in the toolbar.
- Use Save snapshot to create a new version with the current content.
- Use Restore on a version to set the publication content to that version and reload the editor.
Restore does not delete versions; it updates the publication content and leaves the version history intact.
Roadmap (Phase 2 remaining)
- Sprint 2.4: Figure upload component, table editor enhancements, cross-reference extension, FileService integration for images.
- Sprint 2.5: Export (PDF, Word, Markdown) services, export dialog, export button and shortcut.
See Phase 2: Scientific Editor Enhancement for the full sprint breakdown.
Scientific Editor
The Zemna.AI Scientific Editor is a Tiptap-based rich text editor built for academic writing. It includes LaTeX equation support, automatic saving, version history, and publication persistence via the Ring Platform database layer.
Status: Phase 2 (Sprints 2.1–2.3) complete. Figure/table support and export are planned for Sprints 2.4–2.5.
Overview
| Feature | Description |
|---|---|
| Rich text | Headings (H1–H6), bold, italic, underline, lists, block quotes, code blocks, tables, links, images |
| LaTeX | Inline and display math via KaTeX; equation modal with live preview and templates |
| Auto-save | 30-second debounced save; first save creates a publication, then updates via PUT |
| Version history | Snapshot and restore versions; list versions with timestamps and optional summaries |
| Publications | Content stored as Tiptap JSON; load by URL ?id=... or create new |
Editor Features
Rich Text (Tiptap)
The editor uses Tiptap with StarterKit and extensions for scientific writing:
- Formatting: Bold, italic, underline, strikethrough, superscript, subscript, highlight
- Structure: Headings H1–H6, ordered/unordered lists, block quotes
- Blocks: Code blocks (syntax highlighting via lowlight), tables (rows, columns, header)
- Inline: Links, images (placeholder support)
- Typography: Smart quotes and typography improvements
Content is stored as Tiptap JSON in the publication content field; the editor accepts initial content as either HTML string or JSON for loading saved publications.
LaTeX Equations
- Block math: Insert display-mode equations via the toolbar (Calculator icon) or equation modal.
- Rendering: KaTeX renders equations in the editor; click to edit opens the equation modal.
- Modal: LaTeX textarea, display/inline toggle, live preview, template buttons (fraction, sum, integral, matrix), Insert/Cancel.
Equations are stored as custom Tiptap nodes (mathBlock) with latex and display attributes.
Auto-Save & Publications
- New document: No
?id=in URL; first Save or first auto-save creates a publication viaPOST /api/publicationsand sets the publication id for subsequent saves. - Existing document: Open with
?id=<publicationId>; the page loads the publication and sets title and content (JSON). Auto-save and manual Save usePUT /api/publications/:id. - Debounce: Changes to title or content trigger a 30-second debounced save; manual Save triggers an immediate save.
- Save indicator: Toolbar shows "Saved" with timestamp when the last save completed successfully.
Version History
- Panel: Version History button in the toolbar opens a dialog listing versions (version number, date, optional summary).
- Snapshot: "Save snapshot" creates a new version with the current content (optional change summary).
- Restore: "Restore" on a version updates the publication content to that version and refetches the editor; the panel closes and the editor shows the restored content.
Architecture
Publication schema
Publications and versions use the Ring Platform database abstraction (PostgreSQL with JSONB):
publications:id,data(JSONB),created_at,updated_at.
dataholds:user_id,title,content(Tiptap JSON),status,template_id.publication_versions:id,data(JSONB),created_at,updated_at.
dataholds:publication_id,version_number,content,change_summary,created_by.
Schema is defined in data/schema.sql; the PostgreSQL adapter has fieldMappings for both collections.
Save flow
sequenceDiagram
participant User
participant Editor
participant useAutoSave
participant API
participant DB
User->>Editor: Edit content / title
Editor->>useAutoSave: touch(publicationId, payload)
useAutoSave->>useAutoSave: Debounce 30s
Note over useAutoSave: Timer fires
useAutoSave->>API: POST /api/publications (new) or PUT /api/publications/:id
API->>DB: create() or update()
DB-->>API: publication
API-->>useAutoSave: 200 + publication
useAutoSave->>Editor: onFirstSave(id) if new
useAutoSave->>Editor: lastSaved updated
Version history flow
sequenceDiagram
participant User
participant Panel
participant API
participant DB
User->>Panel: Open Version History
Panel->>API: GET /api/publications/:id/versions
API->>DB: findByField(publication_versions, publication_id, id)
DB-->>API: versions[]
API-->>Panel: versions
User->>Panel: Restore version V
Panel->>API: POST /api/publications/:id/versions { action: 'restore', versionId: V }
API->>DB: updatePublication(id, content from V)
DB-->>API: publication
API-->>Panel: 200
Panel->>User: onRestore() → refetch publication, set editor content
API routes
| Method | Path | Description |
|---|---|---|
| GET | /api/publications | List current user's publications |
| POST | /api/publications | Create publication (body: title, content, status, template_id) |
| GET | /api/publications/[id] | Get publication (ownership checked) |
| PUT | /api/publications/[id] | Update publication (ownership checked) |
| DELETE | /api/publications/[id] | Delete publication (ownership checked) |
| GET | /api/publications/[id]/versions | List versions for publication |
| POST | /api/publications/[id]/versions | Snapshot (action: snapshot) or restore (action: restore, versionId) |
All routes require authentication; ownership is enforced for get/update/delete and versions.
Key files
| Area | Path |
|---|---|
| Editor page | app/(authenticated)/[locale]/editor/page.tsx |
| Scientific editor | components/editor/scientific-editor.tsx |
| Toolbar | components/editor/editor-toolbar.tsx |
| LaTeX extension | components/editor/extensions/latex-extension.tsx |
| Equation modal | components/editor/equation-editor.tsx |
| Version history panel | components/editor/version-history-panel.tsx |
| Auto-save hook | hooks/use-auto-save.ts |
| Publication types | features/publications/types/index.ts |
| Publication service | features/publications/services/publication-service.ts |
| API routes | app/(public)/api/publications/ |
| Schema | data/schema.sql |
Usage
Opening the editor
- New publication: Go to
/editor(or/[locale]/editor). The editor loads with the default scientific template; publication id is set on first save. - Existing publication: Go to
/editor?id=<publicationId>. The page fetches the publication and sets the title and content (Tiptap JSON) in the editor.
Saving
- Manual: Click Save in the toolbar. For a new document this creates a publication and sets the id; for an existing document it updates via PUT.
- Auto-save: After 30 seconds without further changes, the current title and content are saved automatically (POST for new, PUT for existing).
Version history
- Click Version History (History icon) in the toolbar.
- Use Save snapshot to create a new version with the current content.
- Use Restore on a version to set the publication content to that version and reload the editor.
Restore does not delete versions; it updates the publication content and leaves the version history intact.
Roadmap (Phase 2 remaining)
- Sprint 2.4: Figure upload component, table editor enhancements, cross-reference extension, FileService integration for images.
- Sprint 2.5: Export (PDF, Word, Markdown) services, export dialog, export button and shortcut.
See Phase 2: Scientific Editor Enhancement for the full sprint breakdown.
Scientific Editor
The Zemna.AI Scientific Editor is a Tiptap-based rich text editor built for academic writing. It includes LaTeX equation support, automatic saving, version history, and publication persistence via the Ring Platform database layer.
Status: Phase 2 (Sprints 2.1–2.3) complete. Figure/table support and export are planned for Sprints 2.4–2.5.
Overview
| Feature | Description |
|---|---|
| Rich text | Headings (H1–H6), bold, italic, underline, lists, block quotes, code blocks, tables, links, images |
| LaTeX | Inline and display math via KaTeX; equation modal with live preview and templates |
| Auto-save | 30-second debounced save; first save creates a publication, then updates via PUT |
| Version history | Snapshot and restore versions; list versions with timestamps and optional summaries |
| Publications | Content stored as Tiptap JSON; load by URL ?id=... or create new |
Editor Features
Rich Text (Tiptap)
The editor uses Tiptap with StarterKit and extensions for scientific writing:
- Formatting: Bold, italic, underline, strikethrough, superscript, subscript, highlight
- Structure: Headings H1–H6, ordered/unordered lists, block quotes
- Blocks: Code blocks (syntax highlighting via lowlight), tables (rows, columns, header)
- Inline: Links, images (placeholder support)
- Typography: Smart quotes and typography improvements
Content is stored as Tiptap JSON in the publication content field; the editor accepts initial content as either HTML string or JSON for loading saved publications.
LaTeX Equations
- Block math: Insert display-mode equations via the toolbar (Calculator icon) or equation modal.
- Rendering: KaTeX renders equations in the editor; click to edit opens the equation modal.
- Modal: LaTeX textarea, display/inline toggle, live preview, template buttons (fraction, sum, integral, matrix), Insert/Cancel.
Equations are stored as custom Tiptap nodes (mathBlock) with latex and display attributes.
Auto-Save & Publications
- New document: No
?id=in URL; first Save or first auto-save creates a publication viaPOST /api/publicationsand sets the publication id for subsequent saves. - Existing document: Open with
?id=<publicationId>; the page loads the publication and sets title and content (JSON). Auto-save and manual Save usePUT /api/publications/:id. - Debounce: Changes to title or content trigger a 30-second debounced save; manual Save triggers an immediate save.
- Save indicator: Toolbar shows "Saved" with timestamp when the last save completed successfully.
Version History
- Panel: Version History button in the toolbar opens a dialog listing versions (version number, date, optional summary).
- Snapshot: "Save snapshot" creates a new version with the current content (optional change summary).
- Restore: "Restore" on a version updates the publication content to that version and refetches the editor; the panel closes and the editor shows the restored content.
Architecture
Publication schema
Publications and versions use the Ring Platform database abstraction (PostgreSQL with JSONB):
publications:id,data(JSONB),created_at,updated_at.
dataholds:user_id,title,content(Tiptap JSON),status,template_id.publication_versions:id,data(JSONB),created_at,updated_at.
dataholds:publication_id,version_number,content,change_summary,created_by.
Schema is defined in data/schema.sql; the PostgreSQL adapter has fieldMappings for both collections.
Save flow
sequenceDiagram
participant User
participant Editor
participant useAutoSave
participant API
participant DB
User->>Editor: Edit content / title
Editor->>useAutoSave: touch(publicationId, payload)
useAutoSave->>useAutoSave: Debounce 30s
Note over useAutoSave: Timer fires
useAutoSave->>API: POST /api/publications (new) or PUT /api/publications/:id
API->>DB: create() or update()
DB-->>API: publication
API-->>useAutoSave: 200 + publication
useAutoSave->>Editor: onFirstSave(id) if new
useAutoSave->>Editor: lastSaved updated
Version history flow
sequenceDiagram
participant User
participant Panel
participant API
participant DB
User->>Panel: Open Version History
Panel->>API: GET /api/publications/:id/versions
API->>DB: findByField(publication_versions, publication_id, id)
DB-->>API: versions[]
API-->>Panel: versions
User->>Panel: Restore version V
Panel->>API: POST /api/publications/:id/versions { action: 'restore', versionId: V }
API->>DB: updatePublication(id, content from V)
DB-->>API: publication
API-->>Panel: 200
Panel->>User: onRestore() → refetch publication, set editor content
API routes
| Method | Path | Description |
|---|---|---|
| GET | /api/publications | List current user's publications |
| POST | /api/publications | Create publication (body: title, content, status, template_id) |
| GET | /api/publications/[id] | Get publication (ownership checked) |
| PUT | /api/publications/[id] | Update publication (ownership checked) |
| DELETE | /api/publications/[id] | Delete publication (ownership checked) |
| GET | /api/publications/[id]/versions | List versions for publication |
| POST | /api/publications/[id]/versions | Snapshot (action: snapshot) or restore (action: restore, versionId) |
All routes require authentication; ownership is enforced for get/update/delete and versions.
Key files
| Area | Path |
|---|---|
| Editor page | app/(authenticated)/[locale]/editor/page.tsx |
| Scientific editor | components/editor/scientific-editor.tsx |
| Toolbar | components/editor/editor-toolbar.tsx |
| LaTeX extension | components/editor/extensions/latex-extension.tsx |
| Equation modal | components/editor/equation-editor.tsx |
| Version history panel | components/editor/version-history-panel.tsx |
| Auto-save hook | hooks/use-auto-save.ts |
| Publication types | features/publications/types/index.ts |
| Publication service | features/publications/services/publication-service.ts |
| API routes | app/(public)/api/publications/ |
| Schema | data/schema.sql |
Usage
Opening the editor
- New publication: Go to
/editor(or/[locale]/editor). The editor loads with the default scientific template; publication id is set on first save. - Existing publication: Go to
/editor?id=<publicationId>. The page fetches the publication and sets the title and content (Tiptap JSON) in the editor.
Saving
- Manual: Click Save in the toolbar. For a new document this creates a publication and sets the id; for an existing document it updates via PUT.
- Auto-save: After 30 seconds without further changes, the current title and content are saved automatically (POST for new, PUT for existing).
Version history
- Click Version History (History icon) in the toolbar.
- Use Save snapshot to create a new version with the current content.
- Use Restore on a version to set the publication content to that version and reload the editor.
Restore does not delete versions; it updates the publication content and leaves the version history intact.
Roadmap (Phase 2 remaining)
- Sprint 2.4: Figure upload component, table editor enhancements, cross-reference extension, FileService integration for images.
- Sprint 2.5: Export (PDF, Word, Markdown) services, export dialog, export button and shortcut.
See Phase 2: Scientific Editor Enhancement for the full sprint breakdown.
Documentation
📚 Documentation
Scientific Editor
The Zemna.AI Scientific Editor is a Tiptap-based rich text editor built for academic writing. It includes LaTeX equation support, automatic saving, version history, and publication persistence via the Ring Platform database layer.
Status: Phase 2 (Sprints 2.1–2.3) complete. Figure/table support and export are planned for Sprints 2.4–2.5.
Overview
| Feature | Description |
|---|---|
| Rich text | Headings (H1–H6), bold, italic, underline, lists, block quotes, code blocks, tables, links, images |
| LaTeX | Inline and display math via KaTeX; equation modal with live preview and templates |
| Auto-save | 30-second debounced save; first save creates a publication, then updates via PUT |
| Version history | Snapshot and restore versions; list versions with timestamps and optional summaries |
| Publications | Content stored as Tiptap JSON; load by URL ?id=... or create new |
Editor Features
Rich Text (Tiptap)
The editor uses Tiptap with StarterKit and extensions for scientific writing:
- Formatting: Bold, italic, underline, strikethrough, superscript, subscript, highlight
- Structure: Headings H1–H6, ordered/unordered lists, block quotes
- Blocks: Code blocks (syntax highlighting via lowlight), tables (rows, columns, header)
- Inline: Links, images (placeholder support)
- Typography: Smart quotes and typography improvements
Content is stored as Tiptap JSON in the publication content field; the editor accepts initial content as either HTML string or JSON for loading saved publications.
LaTeX Equations
- Block math: Insert display-mode equations via the toolbar (Calculator icon) or equation modal.
- Rendering: KaTeX renders equations in the editor; click to edit opens the equation modal.
- Modal: LaTeX textarea, display/inline toggle, live preview, template buttons (fraction, sum, integral, matrix), Insert/Cancel.
Equations are stored as custom Tiptap nodes (mathBlock) with latex and display attributes.
Auto-Save & Publications
- New document: No
?id=in URL; first Save or first auto-save creates a publication viaPOST /api/publicationsand sets the publication id for subsequent saves. - Existing document: Open with
?id=<publicationId>; the page loads the publication and sets title and content (JSON). Auto-save and manual Save usePUT /api/publications/:id. - Debounce: Changes to title or content trigger a 30-second debounced save; manual Save triggers an immediate save.
- Save indicator: Toolbar shows "Saved" with timestamp when the last save completed successfully.
Version History
- Panel: Version History button in the toolbar opens a dialog listing versions (version number, date, optional summary).
- Snapshot: "Save snapshot" creates a new version with the current content (optional change summary).
- Restore: "Restore" on a version updates the publication content to that version and refetches the editor; the panel closes and the editor shows the restored content.
Architecture
Publication schema
Publications and versions use the Ring Platform database abstraction (PostgreSQL with JSONB):
publications:id,data(JSONB),created_at,updated_at.
dataholds:user_id,title,content(Tiptap JSON),status,template_id.publication_versions:id,data(JSONB),created_at,updated_at.
dataholds:publication_id,version_number,content,change_summary,created_by.
Schema is defined in data/schema.sql; the PostgreSQL adapter has fieldMappings for both collections.
Save flow
sequenceDiagram
participant User
participant Editor
participant useAutoSave
participant API
participant DB
User->>Editor: Edit content / title
Editor->>useAutoSave: touch(publicationId, payload)
useAutoSave->>useAutoSave: Debounce 30s
Note over useAutoSave: Timer fires
useAutoSave->>API: POST /api/publications (new) or PUT /api/publications/:id
API->>DB: create() or update()
DB-->>API: publication
API-->>useAutoSave: 200 + publication
useAutoSave->>Editor: onFirstSave(id) if new
useAutoSave->>Editor: lastSaved updated
Version history flow
sequenceDiagram
participant User
participant Panel
participant API
participant DB
User->>Panel: Open Version History
Panel->>API: GET /api/publications/:id/versions
API->>DB: findByField(publication_versions, publication_id, id)
DB-->>API: versions[]
API-->>Panel: versions
User->>Panel: Restore version V
Panel->>API: POST /api/publications/:id/versions { action: 'restore', versionId: V }
API->>DB: updatePublication(id, content from V)
DB-->>API: publication
API-->>Panel: 200
Panel->>User: onRestore() → refetch publication, set editor content
API routes
| Method | Path | Description |
|---|---|---|
| GET | /api/publications | List current user's publications |
| POST | /api/publications | Create publication (body: title, content, status, template_id) |
| GET | /api/publications/[id] | Get publication (ownership checked) |
| PUT | /api/publications/[id] | Update publication (ownership checked) |
| DELETE | /api/publications/[id] | Delete publication (ownership checked) |
| GET | /api/publications/[id]/versions | List versions for publication |
| POST | /api/publications/[id]/versions | Snapshot (action: snapshot) or restore (action: restore, versionId) |
All routes require authentication; ownership is enforced for get/update/delete and versions.
Key files
| Area | Path |
|---|---|
| Editor page | app/(authenticated)/[locale]/editor/page.tsx |
| Scientific editor | components/editor/scientific-editor.tsx |
| Toolbar | components/editor/editor-toolbar.tsx |
| LaTeX extension | components/editor/extensions/latex-extension.tsx |
| Equation modal | components/editor/equation-editor.tsx |
| Version history panel | components/editor/version-history-panel.tsx |
| Auto-save hook | hooks/use-auto-save.ts |
| Publication types | features/publications/types/index.ts |
| Publication service | features/publications/services/publication-service.ts |
| API routes | app/(public)/api/publications/ |
| Schema | data/schema.sql |
Usage
Opening the editor
- New publication: Go to
/editor(or/[locale]/editor). The editor loads with the default scientific template; publication id is set on first save. - Existing publication: Go to
/editor?id=<publicationId>. The page fetches the publication and sets the title and content (Tiptap JSON) in the editor.
Saving
- Manual: Click Save in the toolbar. For a new document this creates a publication and sets the id; for an existing document it updates via PUT.
- Auto-save: After 30 seconds without further changes, the current title and content are saved automatically (POST for new, PUT for existing).
Version history
- Click Version History (History icon) in the toolbar.
- Use Save snapshot to create a new version with the current content.
- Use Restore on a version to set the publication content to that version and reload the editor.
Restore does not delete versions; it updates the publication content and leaves the version history intact.
Roadmap (Phase 2 remaining)
- Sprint 2.4: Figure upload component, table editor enhancements, cross-reference extension, FileService integration for images.
- Sprint 2.5: Export (PDF, Word, Markdown) services, export dialog, export button and shortcut.
See Phase 2: Scientific Editor Enhancement for the full sprint breakdown.
Scientific Editor
The Zemna.AI Scientific Editor is a Tiptap-based rich text editor built for academic writing. It includes LaTeX equation support, automatic saving, version history, and publication persistence via the Ring Platform database layer.
Status: Phase 2 (Sprints 2.1–2.3) complete. Figure/table support and export are planned for Sprints 2.4–2.5.
Overview
| Feature | Description |
|---|---|
| Rich text | Headings (H1–H6), bold, italic, underline, lists, block quotes, code blocks, tables, links, images |
| LaTeX | Inline and display math via KaTeX; equation modal with live preview and templates |
| Auto-save | 30-second debounced save; first save creates a publication, then updates via PUT |
| Version history | Snapshot and restore versions; list versions with timestamps and optional summaries |
| Publications | Content stored as Tiptap JSON; load by URL ?id=... or create new |
Editor Features
Rich Text (Tiptap)
The editor uses Tiptap with StarterKit and extensions for scientific writing:
- Formatting: Bold, italic, underline, strikethrough, superscript, subscript, highlight
- Structure: Headings H1–H6, ordered/unordered lists, block quotes
- Blocks: Code blocks (syntax highlighting via lowlight), tables (rows, columns, header)
- Inline: Links, images (placeholder support)
- Typography: Smart quotes and typography improvements
Content is stored as Tiptap JSON in the publication content field; the editor accepts initial content as either HTML string or JSON for loading saved publications.
LaTeX Equations
- Block math: Insert display-mode equations via the toolbar (Calculator icon) or equation modal.
- Rendering: KaTeX renders equations in the editor; click to edit opens the equation modal.
- Modal: LaTeX textarea, display/inline toggle, live preview, template buttons (fraction, sum, integral, matrix), Insert/Cancel.
Equations are stored as custom Tiptap nodes (mathBlock) with latex and display attributes.
Auto-Save & Publications
- New document: No
?id=in URL; first Save or first auto-save creates a publication viaPOST /api/publicationsand sets the publication id for subsequent saves. - Existing document: Open with
?id=<publicationId>; the page loads the publication and sets title and content (JSON). Auto-save and manual Save usePUT /api/publications/:id. - Debounce: Changes to title or content trigger a 30-second debounced save; manual Save triggers an immediate save.
- Save indicator: Toolbar shows "Saved" with timestamp when the last save completed successfully.
Version History
- Panel: Version History button in the toolbar opens a dialog listing versions (version number, date, optional summary).
- Snapshot: "Save snapshot" creates a new version with the current content (optional change summary).
- Restore: "Restore" on a version updates the publication content to that version and refetches the editor; the panel closes and the editor shows the restored content.
Architecture
Publication schema
Publications and versions use the Ring Platform database abstraction (PostgreSQL with JSONB):
publications:id,data(JSONB),created_at,updated_at.
dataholds:user_id,title,content(Tiptap JSON),status,template_id.publication_versions:id,data(JSONB),created_at,updated_at.
dataholds:publication_id,version_number,content,change_summary,created_by.
Schema is defined in data/schema.sql; the PostgreSQL adapter has fieldMappings for both collections.
Save flow
sequenceDiagram
participant User
participant Editor
participant useAutoSave
participant API
participant DB
User->>Editor: Edit content / title
Editor->>useAutoSave: touch(publicationId, payload)
useAutoSave->>useAutoSave: Debounce 30s
Note over useAutoSave: Timer fires
useAutoSave->>API: POST /api/publications (new) or PUT /api/publications/:id
API->>DB: create() or update()
DB-->>API: publication
API-->>useAutoSave: 200 + publication
useAutoSave->>Editor: onFirstSave(id) if new
useAutoSave->>Editor: lastSaved updated
Version history flow
sequenceDiagram
participant User
participant Panel
participant API
participant DB
User->>Panel: Open Version History
Panel->>API: GET /api/publications/:id/versions
API->>DB: findByField(publication_versions, publication_id, id)
DB-->>API: versions[]
API-->>Panel: versions
User->>Panel: Restore version V
Panel->>API: POST /api/publications/:id/versions { action: 'restore', versionId: V }
API->>DB: updatePublication(id, content from V)
DB-->>API: publication
API-->>Panel: 200
Panel->>User: onRestore() → refetch publication, set editor content
API routes
| Method | Path | Description |
|---|---|---|
| GET | /api/publications | List current user's publications |
| POST | /api/publications | Create publication (body: title, content, status, template_id) |
| GET | /api/publications/[id] | Get publication (ownership checked) |
| PUT | /api/publications/[id] | Update publication (ownership checked) |
| DELETE | /api/publications/[id] | Delete publication (ownership checked) |
| GET | /api/publications/[id]/versions | List versions for publication |
| POST | /api/publications/[id]/versions | Snapshot (action: snapshot) or restore (action: restore, versionId) |
All routes require authentication; ownership is enforced for get/update/delete and versions.
Key files
| Area | Path |
|---|---|
| Editor page | app/(authenticated)/[locale]/editor/page.tsx |
| Scientific editor | components/editor/scientific-editor.tsx |
| Toolbar | components/editor/editor-toolbar.tsx |
| LaTeX extension | components/editor/extensions/latex-extension.tsx |
| Equation modal | components/editor/equation-editor.tsx |
| Version history panel | components/editor/version-history-panel.tsx |
| Auto-save hook | hooks/use-auto-save.ts |
| Publication types | features/publications/types/index.ts |
| Publication service | features/publications/services/publication-service.ts |
| API routes | app/(public)/api/publications/ |
| Schema | data/schema.sql |
Usage
Opening the editor
- New publication: Go to
/editor(or/[locale]/editor). The editor loads with the default scientific template; publication id is set on first save. - Existing publication: Go to
/editor?id=<publicationId>. The page fetches the publication and sets the title and content (Tiptap JSON) in the editor.
Saving
- Manual: Click Save in the toolbar. For a new document this creates a publication and sets the id; for an existing document it updates via PUT.
- Auto-save: After 30 seconds without further changes, the current title and content are saved automatically (POST for new, PUT for existing).
Version history
- Click Version History (History icon) in the toolbar.
- Use Save snapshot to create a new version with the current content.
- Use Restore on a version to set the publication content to that version and reload the editor.
Restore does not delete versions; it updates the publication content and leaves the version history intact.
Roadmap (Phase 2 remaining)
- Sprint 2.4: Figure upload component, table editor enhancements, cross-reference extension, FileService integration for images.
- Sprint 2.5: Export (PDF, Word, Markdown) services, export dialog, export button and shortcut.
See Phase 2: Scientific Editor Enhancement for the full sprint breakdown.
Scientific Editor
The Zemna.AI Scientific Editor is a Tiptap-based rich text editor built for academic writing. It includes LaTeX equation support, automatic saving, version history, and publication persistence via the Ring Platform database layer.
Status: Phase 2 (Sprints 2.1–2.3) complete. Figure/table support and export are planned for Sprints 2.4–2.5.
Overview
| Feature | Description |
|---|---|
| Rich text | Headings (H1–H6), bold, italic, underline, lists, block quotes, code blocks, tables, links, images |
| LaTeX | Inline and display math via KaTeX; equation modal with live preview and templates |
| Auto-save | 30-second debounced save; first save creates a publication, then updates via PUT |
| Version history | Snapshot and restore versions; list versions with timestamps and optional summaries |
| Publications | Content stored as Tiptap JSON; load by URL ?id=... or create new |
Editor Features
Rich Text (Tiptap)
The editor uses Tiptap with StarterKit and extensions for scientific writing:
- Formatting: Bold, italic, underline, strikethrough, superscript, subscript, highlight
- Structure: Headings H1–H6, ordered/unordered lists, block quotes
- Blocks: Code blocks (syntax highlighting via lowlight), tables (rows, columns, header)
- Inline: Links, images (placeholder support)
- Typography: Smart quotes and typography improvements
Content is stored as Tiptap JSON in the publication content field; the editor accepts initial content as either HTML string or JSON for loading saved publications.
LaTeX Equations
- Block math: Insert display-mode equations via the toolbar (Calculator icon) or equation modal.
- Rendering: KaTeX renders equations in the editor; click to edit opens the equation modal.
- Modal: LaTeX textarea, display/inline toggle, live preview, template buttons (fraction, sum, integral, matrix), Insert/Cancel.
Equations are stored as custom Tiptap nodes (mathBlock) with latex and display attributes.
Auto-Save & Publications
- New document: No
?id=in URL; first Save or first auto-save creates a publication viaPOST /api/publicationsand sets the publication id for subsequent saves. - Existing document: Open with
?id=<publicationId>; the page loads the publication and sets title and content (JSON). Auto-save and manual Save usePUT /api/publications/:id. - Debounce: Changes to title or content trigger a 30-second debounced save; manual Save triggers an immediate save.
- Save indicator: Toolbar shows "Saved" with timestamp when the last save completed successfully.
Version History
- Panel: Version History button in the toolbar opens a dialog listing versions (version number, date, optional summary).
- Snapshot: "Save snapshot" creates a new version with the current content (optional change summary).
- Restore: "Restore" on a version updates the publication content to that version and refetches the editor; the panel closes and the editor shows the restored content.
Architecture
Publication schema
Publications and versions use the Ring Platform database abstraction (PostgreSQL with JSONB):
publications:id,data(JSONB),created_at,updated_at.
dataholds:user_id,title,content(Tiptap JSON),status,template_id.publication_versions:id,data(JSONB),created_at,updated_at.
dataholds:publication_id,version_number,content,change_summary,created_by.
Schema is defined in data/schema.sql; the PostgreSQL adapter has fieldMappings for both collections.
Save flow
sequenceDiagram
participant User
participant Editor
participant useAutoSave
participant API
participant DB
User->>Editor: Edit content / title
Editor->>useAutoSave: touch(publicationId, payload)
useAutoSave->>useAutoSave: Debounce 30s
Note over useAutoSave: Timer fires
useAutoSave->>API: POST /api/publications (new) or PUT /api/publications/:id
API->>DB: create() or update()
DB-->>API: publication
API-->>useAutoSave: 200 + publication
useAutoSave->>Editor: onFirstSave(id) if new
useAutoSave->>Editor: lastSaved updated
Version history flow
sequenceDiagram
participant User
participant Panel
participant API
participant DB
User->>Panel: Open Version History
Panel->>API: GET /api/publications/:id/versions
API->>DB: findByField(publication_versions, publication_id, id)
DB-->>API: versions[]
API-->>Panel: versions
User->>Panel: Restore version V
Panel->>API: POST /api/publications/:id/versions { action: 'restore', versionId: V }
API->>DB: updatePublication(id, content from V)
DB-->>API: publication
API-->>Panel: 200
Panel->>User: onRestore() → refetch publication, set editor content
API routes
| Method | Path | Description |
|---|---|---|
| GET | /api/publications | List current user's publications |
| POST | /api/publications | Create publication (body: title, content, status, template_id) |
| GET | /api/publications/[id] | Get publication (ownership checked) |
| PUT | /api/publications/[id] | Update publication (ownership checked) |
| DELETE | /api/publications/[id] | Delete publication (ownership checked) |
| GET | /api/publications/[id]/versions | List versions for publication |
| POST | /api/publications/[id]/versions | Snapshot (action: snapshot) or restore (action: restore, versionId) |
All routes require authentication; ownership is enforced for get/update/delete and versions.
Key files
| Area | Path |
|---|---|
| Editor page | app/(authenticated)/[locale]/editor/page.tsx |
| Scientific editor | components/editor/scientific-editor.tsx |
| Toolbar | components/editor/editor-toolbar.tsx |
| LaTeX extension | components/editor/extensions/latex-extension.tsx |
| Equation modal | components/editor/equation-editor.tsx |
| Version history panel | components/editor/version-history-panel.tsx |
| Auto-save hook | hooks/use-auto-save.ts |
| Publication types | features/publications/types/index.ts |
| Publication service | features/publications/services/publication-service.ts |
| API routes | app/(public)/api/publications/ |
| Schema | data/schema.sql |
Usage
Opening the editor
- New publication: Go to
/editor(or/[locale]/editor). The editor loads with the default scientific template; publication id is set on first save. - Existing publication: Go to
/editor?id=<publicationId>. The page fetches the publication and sets the title and content (Tiptap JSON) in the editor.
Saving
- Manual: Click Save in the toolbar. For a new document this creates a publication and sets the id; for an existing document it updates via PUT.
- Auto-save: After 30 seconds without further changes, the current title and content are saved automatically (POST for new, PUT for existing).
Version history
- Click Version History (History icon) in the toolbar.
- Use Save snapshot to create a new version with the current content.
- Use Restore on a version to set the publication content to that version and reload the editor.
Restore does not delete versions; it updates the publication content and leaves the version history intact.
Roadmap (Phase 2 remaining)
- Sprint 2.4: Figure upload component, table editor enhancements, cross-reference extension, FileService integration for images.
- Sprint 2.5: Export (PDF, Word, Markdown) services, export dialog, export button and shortcut.
See Phase 2: Scientific Editor Enhancement for the full sprint breakdown.