Newsletter
SECTION 10 — NEWSLETTER CREATION FLOW (TEACHER — CANVAS EDITOR)
10.1 Flow Initiation
- Teacher clicks the “Daily Newsletter” entry-point card on their Dashboard.
- A confirmation or direct navigation triggers the Newsletter creation flow.
- A new dedicated page opens styled as a Google Docs-style canvas interface with:
- A top menu bar (formatting tools, action buttons)
- A left sidebar minimap (outline / table of contents — see Section 10.5)
- A main content canvas (block editor powered by Lexical.dev)
10.2 Metadata Sheet (Right Slide-in Panel)
Simultaneously with the canvas opening, a sheet panel slides in from the right side of the screen containing:- A “Skip for Now” button allows the Teacher to dismiss this panel and fill details later.
- The Video URL field is where the Teacher attaches a YouTube video link (see Section 27 for the custom URL-based YouTube video integration — no YouTube API OAuth scope is used).
- This sheet can be re-opened at any time during document creation.
10.3 Block Editor Behaviour (Lexical.dev Canvas)
The canvas uses a block-based structure where content is organised into Categories (nodes) and News Items (child nodes/sub-nodes):Adding Content
- A rounded
+(plus) button is displayed at the Category level and News Item level. - Clicking
+at Category level:- Creates a new Category block with one News Item placeholder auto-added inside it (head start for the user).
- Placeholder fields: Category Name (H1), one News Item with Headline, Image, and Description fields pre-populated as editable placeholders.
- Clicking
+at News Item level:- Creates a new News Item block within the current Category.
- All fields are added together as a unit: Headline block, Image block, Description/Brief block.
Field-Level Controls
Clear Field Button:- A subtle clear button is positioned at the corner of each individual field.
- On click: An alert dialog appears asking the user to confirm the clear action.
- The dialog includes a checkbox: “Don’t ask again — you can re-enable this in Settings.”
- If checked, the alert dialog for that action type is globally suppressed until the user re-enables it in Settings.
- This preference is stored as a boolean in user settings (
clear_field_warning_enabled: true/false).
- A delete icon button is placed at the Category (node) level and News Item (sub-node) level.
- Same alert dialog behaviour as the Clear Field button (with “Don’t ask again” checkbox).
- Deleting a Category (node): Deletes the category AND all news items and their content within it — irreversible after confirmation.
- Deleting a News Item (sub-node): Deletes only that news item and its fields (headline, image, description) without affecting the parent category or sibling news items.
Image Fields
Each News Item supports three image configurations:
Image URLs are uploaded to Cloudinary and the returned Cloudinary URL is stored. Images are not stored as raw file references in the document JSON — only the CDN URL. Thumbnail is an explicit upload action by user (drag-drop or file picker into the dedicated thumbnail slot). Reference images enter via paste into the Brief field — see §10.9.
Text Formatting Support
The Lexical editor must support the following formatting within Brief/content fields:- Headings (H1, H2, H3)
- Paragraph text
- Bold, Italic, Underline
- Bullet lists and numbered lists
- Tables (with optional tabular data for news items where relevant)
- Code blocks (lower priority)
- Separator lines
- Inline links
10.4 Drag-and-Drop Reordering
- Each Category block has a drag handle on its left edge.
- Dragging a Category moves the entire category including all its News Items to a new position in the document order.
- Each News Item has its own drag handle.
- Dragging a News Item can:
- Reorder within the same Category — move it up or down within the parent category.
- Move to a different Category — drag the News Item handle over a different Category’s drop zone to re-parent it. The system removes the link to the old parent category and establishes the link to the new category.
10.5 Sidebar Minimap (Table of Contents)
- A vertical sidebar on the left side of the canvas displays an auto-generated, dynamically updated table of contents / outline view.
- The outline reflects the document hierarchy as it is built: Category names at the top level, News Item headlines indented below.
- Clicking any item in the outline scrolls the canvas to that section.
- The sidebar is drag-scrollable (similar to VSCode’s minimap) — user can drag the viewport indicator to navigate through long documents quickly.
- The outline updates in real-time as the user adds, edits, or reorders blocks.
10.6 Finalisation & Actions
Once the Teacher is satisfied with the document, they have the following options accessible from the top menu bar:Action 1 — Send to Editor
- Submits the document to the Editor’s review queue for the PDF pipeline.
- A confirmation warning dialog appears before submission: “Once submitted, this document will be locked for editing while under review. Do you want to proceed?”
- On confirmation: document
doc-statuschanges toreview, document is locked (read-only for Teacher), and the Editor receives a notification.
Action 2 — Export Document
The Teacher can export the document in the following formats:Action 3 — Launch Presentation Mode
- Converts the structured document JSON to Reveal.js format entirely client-side in the browser (no backend call for the live view).
- The presentation is embedded as an iframe within the app UI shell.
- Controls available in presentation mode:
- Open in New Tab button — opens presentation in a standalone browser tab
- Enter Full Screen button — triggers browser fullscreen on the iframe
- Exit / Escape — returns Teacher to the canvas editor
Action 4 — Translate Document
- Opens a language selection dropdown/modal.
- Teacher selects one or more target languages (e.g. Hindi, Tamil, Marathi).
- Google Translate API is called in the backend to translate the document content.
- A new parallel document version is created, linked to the original document via
doc-id. - The original document is never overwritten or replaced.
- A language switcher appears in the document header to toggle between the original and translated versions.
- See Section 18 for full translation system specification.
10.7 Locked Document Behaviour
After a Teacher submits a document:- The canvas switches to read-only mode for the Teacher.
- A clear banner displays: “This document is currently with the Editor for review. You cannot edit it while it is in the review queue.”
- The Teacher can still view the document in real-time, including watching the Editor’s live changes as they are made (Google Docs collaborative view, read-only for Teacher — see Section 13.4).
- If the Teacher attempts any edit action, the system shows a non-dismissible tooltip: “Document locked for editing.”
10.8 Image Crop (Non-Destructive)
Applies to all image entities in a News Item, with no distinction between source paths:- Thumbnail (explicitly uploaded by the user via the dedicated thumbnail slot).
- Reference images — including those inserted via inline paste into Brief (§10.9). Every image node in the Brief Lexical tree exposes the same crop affordance as the thumbnail. The crop transform attaches to the image node’s underlying
images.reference-images[]entry (matched byatomic_uid).
- Image placeholder displays an edit (crop) icon in the corner.
- Click → in-app crop interface opens (rectangular crop only; aspect ratio free unless template enforces one).
- On crop apply: a reset icon appears next to the edit icon. User can revert the crop at any time before final submission.
- On Teacher “Send to Editor” (document lock): the crop transform is frozen. Reset icon is hidden. Crop is no longer reversible.
- Storage model — non-destructive:
- Original Cloudinary asset is never overwritten.
atomic_uidis never reissued (preserves §11A audit chain).- Crop is stored as a transform record
\{x, y, w, h, applied_at\}on the image entity in the document JSON and in theimagestable. - Renderers (WeasyPrint, PptxGenJS, HTML export) apply the crop at render time via Cloudinary URL transformation parameters (e.g.
c_crop,x_,y_,w_,h_). Zero new infra.
- If the document is unlocked later (e.g. revision queue), the frozen crop remains applied but is still non-destructive — the original asset stays intact and could be re-cropped if Editor edits the image.
10.9 Inline Pasted Reference Images
When a Teacher pastes copied web content (headline body, charts, infographics) into a News Item Brief field, embedded<img> tags must be preserved inline at their original textual position for downstream rendering.
- Editor behaviour: Lexical detects pasted
<img>nodes and inserts them as image nodes in the Brief’s Lexical tree at the cursor/paste position — between paragraph nodes, in the order encountered. - Background upload: Each pasted image is uploaded asynchronously to Cloudinary by the FastAPI backend. Until upload completes, the image node shows a low-opacity preview with a small spinner badge. On upload success,
srcis swapped to the Cloudinary URL andatomic_uidis assigned. - Upload failure handling: If a paste-image upload fails after retries, the image node shows a broken-placeholder badge with a “Retry upload” action. The Teacher cannot finalise the document while broken placeholders exist (blocking validation on “Send to Editor”).
reference-imagesarray: This array in the document JSON becomes derived metadata — built backend-side by walking the Lexical tree of all Brief fields in the document. Used for billing counts, Drive sync naming convention (§26.3), Cloudinary archival (§26.4 / §26A), and audit. The array is not the source of truth for position — the Lexical tree is.- Schema impact:
News-Items[].Briefchanges from a plain string to a serialised Lexical JSON tree. See §11.1 for the updated schema. - Renderer expectation: WeasyPrint, PptxGenJS (client-side, §17.1), and HTML export (§17.7) walk the Brief Lexical tree — paragraph nodes →
<p>, image nodes →<img>— preserving inline order automatically.
10.10 Pre-Submission Q&A Wizard
A pre-submission step appears immediately before the “Send to Editor” confirmation. Skippable — the Teacher can dismiss it and submit without Q&A. If skipped, the Q&A may later be added by a Sub-member (with permission) or by the Editor during Stage 1; see §13.6 for late-add behaviour. Trigger UI: Right-side sheet component, opens on clicking “Generate Q&A” in the top menu bar or via a prompt after clicking “Send to Editor”. Q&A Wizard Steps:- Number of questions: Numeric input. Min 1, max 10. Default 1.
- News item selection grid: After the count is set, the sheet renders a grid view of all News Items currently in the document. Each grid cell shows the news item’s headline, category, and a scrollable preview of the Brief. A rounded checkbox at the corner toggles selection; selected cells get a blue outline. Teacher can select up to
Nitems whereN= the number chosen in step 1. - Question type selection: Default =
subjective.straightforwardfor every question. An edit icon expands per-question customisation, allowing each of the N questions to be set independently to one of the three types. Canonical JSON shapes (see §11.1qa.items[]for full examples):subjective.straightforward:\{ statement, answer \}objective.direct:\{ statement, options: \{ A, B, C, D \}, correct_option \}whereoptionsis a fixed-key map (all four keys required, values are the answer text), andcorrect_option ∈ \{ "A", "B", "C", "D" \}.objective.statement_analysis:\{ topic, statements: [s1, s2, s3], options: \{ A, B, C, D \}, correct_option \}. Backend renders the displayed stem as: “Consider the following statements about {topic}: {s1}, {s2}, {s3}. Which of the above statements is/are true?” The fouroptionsvalues must each be drawn (without repetition) from the allowed set\{ "1", "2", "3", "1+2", "2+3", "1+3", "All of the above", "None" \}. Exactly one option is marked correct viacorrect_option.
- Generate → backend call.
- OpenRouter API. Model resolution per §22B (OpenRouter Q&A Service).
- Only the selected news items’ headlines + briefs are sent in the prompt — never the full document.
- OpenAI-style Structured Outputs mode required. Backend supplies the JSON Schema for the requested question type(s); the response must conform.
- Validation chain on response: parse JSON → schema validate → if any failure, retry up to 3 times on the same model → on continued failure, iterate through the configured fallback chain of 4 models → if all 8 attempts fail, surface error in the wizard with a “Retry” action.
- Spend guardrails: see §22B.4 (per-org monthly token cap + per-request cap).
- Validated Q&A items appear in the wizard as editable cards. Teacher can edit text/options/correct-answer of any item before acceptance.
- Teacher clicks “Accept Q&A” → items written to the document JSON under the
qanode (§11.1). - Teacher returns to the Send-to-Editor confirmation and proceeds normally.
- “Skip for now” button at any wizard step.
- No Q&A node is written. Document proceeds without Q&A. Pipeline is never halted by the absence of Q&A.