Skip to content

feat(web): caption approval before FetLife email publish#53

Merged
dhirmadi merged 1 commit into
mainfrom
feature/publish-review
Feb 25, 2026
Merged

feat(web): caption approval before FetLife email publish#53
dhirmadi merged 1 commit into
mainfrom
feature/publish-review

Conversation

@dhirmadi
Copy link
Copy Markdown
Owner

Description

Allow web UI users to review, edit, and confirm AI-generated captions before publishing to FetLife via email. Previously, clicking "Publish" re-ran AI caption generation from scratch, discarding the caption the user had reviewed after "Analyze & Caption". The FetLife email was sent with a caption the user never approved.

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📝 Documentation update
  • 🔧 Configuration change
  • 🎨 Code style update (formatting, renaming)
  • ♻️ Code refactoring (no functional changes)
  • ⚡ Performance improvement
  • ✅ Test update
  • 🔒 Security fix

Related Issue

Addresses user feedback: "cannot approve the caption needed to send emails to FetLife before publishing."

Changes Made

  • workflow.py: Added caption_override parameter to WorkflowOrchestrator.execute(). When provided (and non-whitespace), skips AI caption generation and uses the override. Logs caption_override_used for audit trail.
  • models.py: Added optional caption field to PublishRequest (backward-compatible, defaults to None).
  • app.py: Route handler extracts and normalizes body.caption (whitespace-only → None), passes through to service.
  • service.py: publish_image() accepts caption_override and forwards to orchestrator. Logs when override is received.
  • index.html (CSS): Textarea styling, character counter, edited badge — all matching existing dark theme.
  • index.html (HTML): Replaced read-only caption <div> with editable <textarea>, added N / 240 character counter and "(edited)" indicator.
  • index.html (JS): Updated setCaption() for textarea, added updateCaptionMeta() with live counter, added XSS-safe inline confirmation modal (showPublishConfirm()), updated apiPublish() to send caption in POST body.
  • test_workflow_feature_toggles.py: 5 new tests — override happy path, empty string fallthrough, whitespace-only fallthrough, sanitization by format_caption, and None preserving default behavior. Enhanced _StubPublisher to capture received captions.
  • test_web_app_additional.py / test_web_service.py: Updated stubs to accept new caption_override parameter.

Testing

  • All existing tests pass (448 passed, 0 failed)
  • Added new tests for new functionality (5 tests)
  • Tested manually with the following scenarios:
    • Publish with AI-generated caption (no edit) — caption sent as-is
    • Edit caption, confirm, publish — edited caption used, AI skipped
    • Cancel confirmation modal — publish aborted
    • Empty/whitespace caption falls through to AI generation
    • Character counter turns red above 240 chars
    • "(edited)" badge appears when caption is modified

Security Considerations

  • No sensitive data exposed in code or logs (caption length logged, not content)
  • Credentials properly handled (not hardcoded)
  • Input validation added where necessary (whitespace normalization, server-side format_caption sanitization still enforced)
  • No new security vulnerabilities introduced (confirmation modal uses textContent DOM API, not innerHTML — XSS-safe)

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

Additional Notes

  • Backward-compatible: All existing callers (CLI, cron, orchestrator) that don't provide caption_override get the existing AI generation flow unchanged.
  • Defense-in-depth: Caption normalization is guarded at three layers — frontend (isPlaceholder check), route handler (strip() or None), and workflow (caption_override.strip() check).
  • Character counter is informational: The 240-char limit matches _MAX_LEN["email"] in captions.py. Server-side format_caption still enforces the hard trim — the counter provides user feedback, not the enforcement.
  • Out of scope: Caption editing for non-email platforms, caption history/undo, hard client-side length block.

Allow web UI users to review, edit, and confirm AI-generated captions
before publishing to FetLife via email. Previously the publish action
re-ran caption generation from scratch, discarding the displayed caption.

- Add caption_override parameter to WorkflowOrchestrator.execute()
- Thread optional caption through PublishRequest, route, and service
- Replace read-only caption div with editable textarea
- Add live character counter (N/240) and "(edited)" indicator
- Add inline confirmation modal before publish (XSS-safe, DOM API)
- Normalize whitespace-only captions to None (falls through to AI)
- Add 5 tests covering override, fallthrough, and sanitization

Co-authored-by: Cursor <cursoragent@cursor.com>
@dhirmadi dhirmadi merged commit 443d8ac into main Feb 25, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant