Each journey is walked by a named protagonist (BMAD pattern): a concrete persona with a job-to-be-done trigger, so the spec reads as behaviour rather than abstract requirements.
2 personas14 scenariosslugcomment-editor-rebuild
JTBD: When I get a design link, I want to point at exactly what to change so the studio fixes my site without a meeting.
JTBD: When client feedback arrives, I want to fix everything on one working copy and ship a clean version only when I am ready.
Every distinct leaf path, classified happy / edge / failure / recovery. The proposed test-IDs are the bridge that plan-techspec reads from scenario_map.json to seed acceptance checks.
| ID | Scenario | Persona | Path | Steps | Proposed test-IDs |
|---|---|---|---|---|---|
| S1 | Client leaves multi-page feedback and submits once | P1 | 🟢 happy | 9 | T-S1-no-login-open, T-S1-pagecount-badge, T-S1-atomic-image-text, T-S1-no-kesz-toggle, T-S1-crosspage-submit, T-S1-submitted-not-done |
| S2 | Empty-comment guard and image-only comment | P1 | 🟡 edge | 2 | T-S2-empty-guard, T-S2-image-only-single-row |
| S3 | Drafts survive navigation and tab reopen with no duplication | P1 | 🟣 recovery | 4 | T-S3-nav-no-dupe, T-S3-delete-authoritative, T-S3-reopen-restore, T-S3-client-uid-isolation |
| S4 | Autosave fails then recovers — nothing lost or duplicated | P1 | 🔴 failure | 2 | T-S4-autosave-fail-pill, T-S4-retry-idempotent-submit |
| S5 | Client sees results, browses versions, never sees AI internals | P1 | 🟢 happy | 5 | T-S5-auto-advance, T-S5-summary-banner, T-S5-state-badges, T-S5-version-browse-readonly, T-S5-no-ai-leak |
| S6 | Admin receives and triages with correct project-wide count | P2 | 🟢 happy | 6 | T-S6-count-22, T-S6-both-pages, T-S6-notify-deduped, T-S6-question-flag-orthogonal, T-S6-view-toggle, T-S6-filter-by-state |
| S7 | Admin fixes in place on the working version — NO new version; client locks | P2 | 🟢 happy | 5 | T-S7-inplace-no-new-version, T-S7-client-lock-on-edit, T-S7-open-editor-no-lock, T-S7-section-ai-scoped, T-S7-regen-only-not-done |
| S8 | Per-comment AI run / re-run / revert (in place) | P2 | 🟢 happy | 3 | T-S8-per-comment-apply, T-S8-revert-keeps-html, T-S8-rerun-on-top |
| S9 | Reject with note and free state toggling in all directions | P2 | 🟢 happy | 3 | T-S9-reject-note-field, T-S9-elvetve-reversible, T-S9-client-elvetve-text-only |
| S10 | AI run in flight — publish/discard blocked, other sections still editable | P2 | 🔴 failure | 3 | T-S10-publish-blocked-during-ai, T-S10-per-section-concurrency, T-S10-callback-no-clobber |
| S11 | Publish — the only checkpoint that mints a version | P2 | 🟢 happy | 5 | T-S11-publish-only-mints, T-S11-warning-crosspage-counts, T-S11-carry-not-done, T-S11-origin-badge, T-S11-freeze-done-rejected, T-S11-client-unlock-on-publish |
| S12 | Browse a previous version from the version-history dropdown (read-only) | P2 | 🟢 happy | 3 | T-S12-history-load-html-and-comments, T-S12-history-readonly, T-S12-history-nondestructive |
| S13 | Per-edit undo — strict LIFO stack | P2 | 🟣 recovery | 3 | T-S13-undo-lifo, T-S13-undo-restores-before-state |
| S14 | Audit download — exact prompts + raw output (JSON + MD) | P2 | 🟢 happy | 3 | T-S14-editlog-onscreen, T-S14-download-json-prompts, T-S14-download-md-prompts |
Each row is one concrete UI interaction: who acts · the exact element clicked or seen · the copy shown · the system action · the resulting state · where it branches.
Trigger: Réka opens the share link and wants to request changes on two pages.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Open the client share link (no login screen) | First-time hint tooltip | GET /v/{token} | viewing_published | — |
| 2 | user | Click the ✕ on the first-time hint to dismiss it | (hint dismissed) | — | viewing_published | — |
| 3 | user | Open the page dropdown (top bar) showing all 5 pages with per-page unresolved-count badges | Page list with count badges | uses comment_counts (project-wide) | viewing_published | — |
| 4 | user | Click '💬 Megjegyzés', then click a hero section on page A | 💬 Megjegyzés | overlay.js captures anchor | draft_open | — |
| 5 | user | Pick an intent chip 'Szöveg csere' and type the change in the draft card | Szöveg csere / Kép csere / Törlés / Új elem / Új szekció / Egyéb | POST /comments/autosave (idempotent upsert by temp_id) | draft_dirty | — |
| 6 | user | Attach an image to the same draft via the 📎 button (or paste / drag-drop) | (image thumbnail) | presigned PUT to R2; image attached to same temp_id | draft_dirty | — |
| 7 | user | Select text directly on the page → a draft pre-fills as „…" helyett: | ‚…' helyett: | — | draft_dirty | — |
| 8 | user | Switch to page B via the page dropdown and add a '🌐 Oldal-szintű' page-level comment (no pin) | 🌐 Oldal-szintű | — | draft_dirty | — |
| 9 | user | Click the submit button reading 'Beküldés (N · 2 oldal)' | Beküldés (N · 2 oldal) | POST /comments/submit (both pages) | submitted | — |
Proposed acceptance test-IDs: T-S1-no-login-open, T-S1-pagecount-badge, T-S1-atomic-image-text, T-S1-no-kesz-toggle, T-S1-crosspage-submit, T-S1-submitted-not-done
Trigger: Réka opens a draft but has nothing typed, then leaves only an image.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Open a draft card and click submit with no body and no image | (submit disabled / guard message) | — | draft_open | — |
| 2 | user | Attach only an image (no text) to the draft, then submit | (kép) | POST /comments/submit | submitted | — |
Proposed acceptance test-IDs: T-S2-empty-guard, T-S2-image-only-single-row
Trigger: Réka jumps between pages and reopens the tab while drafting.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Create drafts on page A, navigate to page B, then back to page A | — | re-fetch authoritative drafts from server | draft_dirty | — |
| 2 | user | Delete one draft with its ✕ button, then navigate away and back | ✕ | authoritative server-side delete | draft_dirty | — |
| 3 | user | Close the browser tab and reopen the same link in the same browser | — | restore by client_uid | draft_dirty | — |
| 4 | system | A second browser (a different client) opens the same link | — | — | draft_dirty | — |
Proposed acceptance test-IDs: T-S3-nav-no-dupe, T-S3-delete-authoritative, T-S3-reopen-restore, T-S3-client-uid-isolation
Trigger: Réka's autosave requests are blocked (flaky network) while she edits.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | system | Block POST /comments/autosave (DevTools network block) | ⚠️ Mentés sikertelen… | — | draft_dirty_offline | — |
| 2 | user | Restore the network and let autosave retry, then click submit | — | idempotent upsert by temp_id → POST /comments/submit | submitted | — |
Proposed acceptance test-IDs: T-S4-autosave-fail-pill, T-S4-retry-idempotent-submit
Trigger: After Ádám publishes, Réka returns to see what was done.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | system | Client tab auto-advances (~20s poll) to the newly published version labelled '· legújabb' | · legújabb | poll detects new published version | viewing_published_latest | — |
| 2 | user | Read the summary banner '✓ N/M megjegyzés feldolgozva' | ✓ N/M megjegyzés feldolgozva | — | viewing_published_latest | — |
| 3 | user | Open 'Korábbi verziók megjegyzései' and read the per-comment state badges | ✓ Kész · 🤖 (if AI) · Elvetve — <note> | — | viewing_published_latest | — |
| 4 | user | Pick an older version from the version dropdown (read-only browse), then click '↩ Legújabb' | ↩ Legújabb | load frozen version (HTML + frozen comment states) | viewing_old_version | — |
| 5 | user | Scan the whole client view for any rep-only control or AI artefact | — | — | viewing_published_latest | — |
Proposed acceptance test-IDs: T-S5-auto-advance, T-S5-summary-banner, T-S5-state-badges, T-S5-version-browse-readonly, T-S5-no-ai-leak
Trigger: 22 comments arrived across 3 pages; Ádám opens the reviewer.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Open the reviewer; read the 'Új ügyfél-visszajelzés!' popup count | Új ügyfél-visszajelzés! (22) | comment_counts project-wide (mirror _attention_flags) | reviewing | — |
| 2 | user | Switch between the two affected pages and confirm comments appear on both | — | — | reviewing | — |
| 3 | system | Confirm one notification per submit (Slack/email), de-duped | — | one notification per submit session | reviewing | — |
| 4 | user | Open a question-style comment showing the amber 'Kérdés van' flag and 🤖 answer options | Kérdés van | — | reviewing | — |
| 5 | user | Toggle '🔧 Szerkesztő ↔ 👤 Ügyfél nézet' and click '🔗 Ügyfél link' to copy | 🔧 Szerkesztő · 👤 Ügyfél nézet · 🔗 Ügyfél link | — | reviewing | — |
| 6 | user | Use the reviewer filter/sort by page and by state (nincs kész / kész / elvetve / locked) | nincs kész · kész · elvetve · locked | — | reviewing | — |
Proposed acceptance test-IDs: T-S6-count-22, T-S6-both-pages, T-S6-notify-deduped, T-S6-question-flag-orthogonal, T-S6-view-toggle, T-S6-filter-by-state
Trigger: Ádám edits HTML/CSS, reorders, and regenerates — all before publishing.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Open the '</>' HTML editor and edit one section, then save | — | in-place section splice + sha1 manifest recompute (no new Version row) | working_edited | — |
| 2 | system | After this first real edit, the client view shows '🔧 Feldolgozás alatt' and commenting is disabled | 🔧 Feldolgozás alatt | — | client_locked | — |
| 3 | user | Edit global CSS, then drag-reorder a section with the ⋮⋮ handle | ⋮⋮ | in-place CSS save + reorder (deterministic, bypass LLM) | working_edited | — |
| 4 | user | Run a per-section '🤖' free-prompt AI edit on one section | 🤖 (per-section, free prompt) | spawn apply worker; only that section's outerHTML rewritten | working_edited | — |
| 5 | user | Click '♻️ Szekciók újragenerálása' (regenerate-all) and watch the 'fog' | ♻️ Szekciók újragenerálása | AI on only not_done comments; mutate working in place | working_edited | — |
Proposed acceptance test-IDs: T-S7-inplace-no-new-version, T-S7-client-lock-on-edit, T-S7-open-editor-no-lock, T-S7-section-ai-scoped, T-S7-regen-only-not-done
Trigger: Ádám resolves one comment with AI and iterates on it.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | On a single nincs kész comment, click its per-comment AI 'run' button | — | spawn apply for that one comment against the working version | working_edited | — |
| 2 | user | Revert that AI-kész comment back to 'nincs kész' | — | status flip only (HTML kept) | working_edited | — |
| 3 | user | Click per-comment AI 'run' again (re-run) on the now nincs kész comment | — | spawn apply again on current HTML | working_edited | — |
Proposed acceptance test-IDs: T-S8-per-comment-apply, T-S8-revert-keeps-html, T-S8-rerun-on-top
Trigger: Ádám dismisses one comment, then changes his mind.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Click 'Visszautasít' on a comment and type an optional Hungarian note | Visszautasít / Elvetés | set status=rejected + reject_note | working_edited | — |
| 2 | user | Toggle the same 'elvetve' comment back to 'nincs kész', then to 'kész' | nincs kész ⇄ kész ⇄ elvetve | free transition (working version) | working_edited | — |
| 3 | system | Open the client view of the rejected comment | Elvetve — <note> | — | viewing_published | — |
Proposed acceptance test-IDs: T-S9-reject-note-field, T-S9-elvetve-reversible, T-S9-client-elvetve-text-only
Trigger: Ádám tries to publish while an AI run is still going.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Start an AI run on section 1, then immediately click 'Új verzió / Ügyfélnek küldés →' | AI-futtatás zajlik… | per-section guard returns busy for section 1 | ai_running | — |
| 2 | user | While section 1 runs, edit a DIFFERENT section (section 2) | — | per-section guard (not page-wide lock) | working_edited | — |
| 3 | system | Section 1's AI run completes via the HMAC callback | — | POST /internal/jobs/{id}/complete | working_edited | — |
Proposed acceptance test-IDs: T-S10-publish-blocked-during-ai, T-S10-per-section-concurrency, T-S10-callback-no-clobber
Trigger: Ádám is happy with the working copy and ships it to the client.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Click 'Új verzió létrehozása / Ügyfélnek küldés →' | Új verzió létrehozása / Ügyfélnek küldés → | — | publish_confirm | — |
| 2 | user | Read the cross-page warning popup: 'X megjegyzés átkerül (nincs kész), Y lezárul (kész/elvetve)' | X megjegyzés átkerül (nincs kész) · Y lezárul (kész/elvetve) | plan_checkpoint counts across ALL pages | publish_confirm | — |
| 3 | user | Click confirm in the popup | — | freeze working → published; fork working n+1; carry_and_reanchor not_done | published | — |
| 4 | user | Inspect a carried-forward comment on working n+1 | (faint origin badge, e.g. 'V1') | — | working_edited | — |
| 5 | system | The client tab auto-advances (~20s) to published n and unlocks | · legújabb | — | viewing_published_latest | — |
Proposed acceptance test-IDs: T-S11-publish-only-mints, T-S11-warning-crosspage-counts, T-S11-carry-not-done, T-S11-origin-badge, T-S11-freeze-done-rejected, T-S11-client-unlock-on-publish
Trigger: Ádám wants to look back at an earlier shipped version (NOT a destructive restore).
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Open the version-history dropdown and select an earlier published version | — | load that version's frozen blob (HTML) + its frozen comments | viewing_old_version | — |
| 2 | user | Confirm the loaded old version is read-only (no editing/commenting) | — | — | viewing_old_version | — |
| 3 | user | Return to the current working/latest version from the dropdown | — | reselect latest | working_edited | — |
Proposed acceptance test-IDs: T-S12-history-load-html-and-comments, T-S12-history-readonly, T-S12-history-nondestructive
Trigger: Ádám makes three edits then wants the last one gone.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Make three in-place edits (edit A, edit B, edit C) on the working version | — | append EditEvent A, B, C | working_edited | — |
| 2 | user | Click undo once | — | pop EditEvent C; restore its before-state | working_edited | — |
| 3 | user | Confirm undo is LIFO (the next undo would remove B, not A) | — | — | working_edited | — |
Proposed acceptance test-IDs: T-S13-undo-lifo, T-S13-undo-restores-before-state
Trigger: Ádám needs the full AI trail for a version.
| # | Actor | UI element (clicked / seen) | Copy shown | System action | Resulting state | Branch to |
|---|---|---|---|---|---|---|
| 1 | user | Open the version diff page and click '📋 Szerkesztési napló' | 📋 Szerkesztési napló | — | reviewing | — |
| 2 | user | Click the audit 'Letöltés' and choose JSON | Letöltés (JSON) | serialize EditEvents → JSON | reviewing | — |
| 3 | user | Click the audit 'Letöltés' and choose Markdown | Letöltés (MD) | serialize EditEvents → Markdown | reviewing | — |
Proposed acceptance test-IDs: T-S14-editlog-onscreen, T-S14-download-json-prompts, T-S14-download-md-prompts
Conditions on the arrows; colours follow the path-type legend. Per-scenario sub-flows appear inside each scenario above.
flowchart TD
CL["Client opens link"] --> DR["draft (autosave, server-authoritative)"]
DR --> SUB["Beküldés → status=not_done"]
SUB --> REV["Admin reviewer (count project-wide)"]
REV --> TGL{"toggle state (working)"}
TGL -->|nincs kész ⇄ kész ⇄ elvetve| TGL
REV --> FIX["edit in place: HTML/CSS/reorder/AI"]
FIX -->|first real edit| LOCK["client locked: 🔧 Feldolgozás alatt"]
FIX -->|append EditEvent| UNDO["undo: strict LIFO"]
FIX --> PUB["Új verzió / Ügyfélnek küldés →"]
PUB --> WARN{"warning popup: X carry · Y close"}
WARN -->|confirm| FREEZE["freeze → published n"]
FREEZE --> FORK["fork working n+1: not_done carried (origin badge)"]
FREEZE --> CLU["client unlocks, auto-advances ~20s"]
FREEZE -.->|read-only browse| HIST["version-history dropdown: load HTML + frozen comments"]
| Message | Copy / subject | Source | Send / show mode | Status |
|---|---|---|---|---|
| Comment entry button | 💬 Megjegyzés | shell.js | in-page | live |
| Intent chips | Szöveg csere / Kép csere / Törlés / Új elem / Új szekció / Egyéb | shell.js | in-page | live |
| Text-select prefill | ‚…' helyett: | shell.js | in-page | live |
| Image-only label | (kép) | shell.js | in-page | changed |
| Page-level comment | 🌐 Oldal-szintű | shell.js | in-page | live |
| Cross-page submit | Beküldés (N · 2 oldal) | shell.js | in-page | live |
| New-feedback popup | Új ügyfél-visszajelzés! | viewer.py / shell.js | in-page | changed |
| Question flag | Kérdés van | shell.js | in-page | changed |
| View toggle + link | 🔧 Szerkesztő · 👤 Ügyfél nézet · 🔗 Ügyfél link | shell.js | in-page | live |
| Regenerate-all | ♻️ Szekciók újragenerálása | shell.js | in-page | changed |
| Reject action | Visszautasít / Elvetés | shell.js | in-page | live |
| Reject display (client) | Elvetve — <note> | viewer.py:_resolution | in-page | changed |
| Publish / checkpoint | Új verzió létrehozása / Ügyfélnek küldés → | shell.js / revision_api.py | in-page | changed |
| Pre-publish warning | X megjegyzés átkerül (nincs kész) · Y lezárul (kész/elvetve) | shell.js | popup | planned |
| AI-running block | AI-futtatás zajlik… | revision_api.py 409 → shell.js | in-page | changed |
| Client mid-fix lock | 🔧 Feldolgozás alatt | shell.js | in-page | changed |
| Admin 'client watching' | 👁 ügyfél nézi | shell.js | in-page | live |
| Autosave failure pill | ⚠️ Mentés sikertelen… | shell.js | in-page | live |
| Client summary banner | ✓ N/M megjegyzés feldolgozva | shell.js | in-page | live |
| Older comments section | Korábbi verziók megjegyzései | shell.js | in-page | live |
| State badges (client) | ✓ Kész · 🤖 · Elvetve | shell.js | in-page | changed |
| Back to newest | ↩ Legújabb | shell.js | in-page | live |
| Latest label | · legújabb | shell.js | in-page | live |
| Edit log | 📋 Szerkesztési napló | shell.js | in-page | live |
| Audit download | Letöltés (JSON / MD) | revision_api.py | download | planned |
| Carried-comment origin badge | V1 (faint) | shell.js | in-page | planned |
| Mobile gate | 💻 nyisd meg szélesebb képernyőn | shell.js | in-page | live |
| State | Meaning | Entered by | Exits to |
|---|---|---|---|
not_done (nincs kész) | Default for every submitted comment; the only state AI acts on | submit, revert, or toggle while working | done, rejected (free, while working); carried to n+1 on publish |
done (kész) | Resolved manually or by AI (resolved_by=ai → 🤖 badge) | admin toggle or successful AI apply | not_done, rejected (free, while working); freezes to locked on publish |
rejected (elvetve) | Admin-dismissed with an optional note; client sees 'Elvetve — note' | Visszautasít (+ optional note) while working | not_done, done (free, while working); freezes to locked on publish; does NOT carry |
locked (derived) | Any done/rejected comment living in a frozen/published version | publish (checkpoint) of its version | read-only (never edited again; appears in version-history browse) |
working (Version.state) | The single mutable editable copy per page | first version of a page, or fork on publish (n+1) | published on explicit publish |
published (Version.state) | Frozen, client-visible checkpoint with a changelog | explicit 'Új verzió / Ügyfélnek küldés →' | immutable; browsable read-only via version history |
client_locked | Client view disabled for editing after the admin's first real edit | admin's first in-place HTML/CSS/AI edit on the working version | unlocks when the next version is published |
Generated by the user-journeys skill on 2026-06-23 · hosted at https://comment-editor-rebuild-journeys.pages.dev. Rendering: Mermaid flowchart syntax. No screenshots — this is a behavioral spec, not a visual QA artifact.