CMS · Proposal editor (content, coupon, push, AI images)

The main content-authoring form (800+ lines of controller): multi-language title/description, app/web/totem images with optional AI generation, audio attachment, audience (gender, age range, segments), channels, store or centre scope, date and event windows, category, coupon, an optional push notification sent with the proposal, polls, extra attributes and a shareable public URL.

AreaCMS
Routescms.proposals.new · cms.proposals.edit
Centre modulesai · cms · marketingActivityCampaigns · proposal_ranking · totem_channel
Staff levelsroot · admin · manager · storeManager · commerce · crmmanager · weboperator · content_creator
Modelscampaign · category · commerce · coupon · extra · language · proposal · proposal-extra · proposal-language · push-notification · segment
UI labelcms.proposal.general-data
Coverage7 use cases · 3 happy · 16 failure

Known issues (4)

Missing translations

These keys are used on this screen but do not exist in translations.json, so users see the raw key:

  • cms.proposals.new.image-generation.gif

How it works

Several notable sub-capabilities. (1) AI image generation: openImageGenerationModal → generateImage with options from enums/image-ai-options, results polled over Pusher, then downloadImage. (2) Audio: uploadAudioFile/deleteAudioFile/mountAudio with a 10 MB limit enforced by the error copy. (3) An embedded push notification validated by _isValidPushNotification() only when wantToSendPushNotification — and cross-validated so the push cannot start before the event starts. (4) Coupons: a coupon sub-record with its own validations collected into couponErrors. (5) Extra attributes: requiredProposalExtras are reset and re-checked on each submit, with the same untranslated "<label> is required" message as the store form. (6) copyUrlTemplate copies a public proposal URL built from the centre’s template. Submission is a chain — submit → validate proposal + coupon + push → patchProposal → saveExtras → afterSaved — and errors go through the same mapErrors + user-error/api-error classification as the campaign editor.

Use cases

Why someone opens this (7)

  • Publishing a centre event with images, an event window and a push notification announcing it.
  • A store manager creating a store-scoped promotion with a redeemable coupon.
  • Generating a hero image with AI rather than briefing a designer.
  • Attaching an audio description for accessibility.
  • Running a poll attached to a proposal, with a max-votes cap.
  • Targeting a proposal to a segment and an age/gender range.
  • Sharing a proposal outside the app via its public URL.

Path map

flowchart LR
    F(["Proposal editor content, coupon, push, AI images"]):::feat
    F --> H1["Centre event with push notification"]:::ok
    F --> H2["AI image generated"]:::ok
    F --> H3["Store coupon promotion"]:::ok
    F -.-> X1["Mandatory content missing"]:::bad
    F -.-> X2["Images missing"]:::bad
    F -.-> X3["Store missing on a store proposal"]:::bad
    F -.-> X4["End date before start date"]:::bad
    F -.-> X5["Event dates invalid"]:::bad
    F -.-> X6["Push notification starts before the event"]:::bad
    F -.-> X7["Segment required but missing"]:::bad
    F -.-> X8["Poll without an activity"]:::bad
    F -.-> X9["Images embedded in the description"]:::bad
    F -.-> X10["Coupon incomplete"]:::bad
    F -.-> X11["Audio upload fails or is too large"]:::bad
    F -.-> X12["Required extra attribute empty"]:::bad
    F -.-> X13["API rejection"]:::bad
    F -.-> X14["AI image generation fails"]:::bad
    F -.-> X15["URL copy fails"]:::bad
    F -.-> X16["Raw translation key on screen"]:::bad
    classDef feat fill:#6a4a8f,stroke:#6a4a8f,color:#ffffff,font-weight:bold
    classDef ok fill:#e3f1ea,stroke:#0d6b42,color:#0d4a2e
    classDef bad fill:#f7e6e2,stroke:#9a2d1c,color:#6e1f13

Happy paths

Centre event with push notification

  1. User fills name, description, category, type center, channels and the app image.
  2. Marks it an event and sets event start/end dates within the proposal’s date range.
  3. Audience: gender, min/max age and optionally segments.
  4. Enables the push notification, whose start is not before the event start.
  5. submit validates the proposal, the coupon (if enabled) and the push, saves the proposal, then the extras.
  6. The proposal is created in draft and can be requested/published from the list.

AI image generated

  1. User opens the image-generation modal and picks an AI option.
  2. generateImage requests it; the result arrives over the Pusher channel.
  3. User reviews it and downloads/attaches it as the proposal image.

Store coupon promotion

  1. Type is set to commerce and the store is selected.
  2. Coupon is enabled with text, a usage limit and (for centre-scoped proposals) its stores.
  3. Multi-exchange is enabled with a per-user exchange limit.
  4. Save succeeds and customers can take the coupon in the app.

Failure paths

QA checklist

Tick these off while regression-testing this feature. The boxes are plain Markdown, so progress is visible in git diffs.

  • ✅ Centre event with push notification
  • ✅ AI image generated
  • ✅ Store coupon promotion
  • ⛔ Mandatory content missing
  • ⛔ Images missing
  • ⛔ Store missing on a store proposal
  • ⛔ End date before start date
  • ⛔ Event dates invalid
  • ⛔ Push notification starts before the event
  • ⛔ Segment required but missing
  • ⛔ Poll without an activity
  • ⛔ Images embedded in the description
  • ⛔ Coupon incomplete
  • ⛔ Audio upload fails or is too large
  • ⛔ Required extra attribute empty
  • ⛔ API rejection
  • ⛔ AI image generation fails
  • ⛔ URL copy fails
  • ⛔ Raw translation key on screen

Implementation


Generated from doc/feature-inventory.json · id cms-proposal-editor · commit 276788ca6