CMS · Proposal list & publication workflow
Lists the centre’s content proposals (news, events, promotions) with type, category, segment, store, date range and status, and drives the full editorial workflow: request publication, publish, reject publication, unpublish, expire, duplicate, preview, delete and drag-to-reorder.
| Area | CMS |
| Routes | cms.proposals · cms.proposals.index |
| Centre modules | cms · proposal_inbox · proposal_ranking |
| Staff levels | root · admin · manager · storeManager · commerce · crmmanager · weboperator · content_creator |
| Models | coupon · language · proposal |
| UI label | title.header.proposals / menu.navbar.proposal.show |
| Coverage | 6 use cases · 3 happy · 7 failure |
Known issues (1)
Missing translations
These keys are used on this screen but do not exist in
translations.json, so users see the raw key:
want_reject_publish
How it works
The editorial state machine spans five statuses (draft, pending, scheduled, active, expired) and six transitions, each with its own ability (canPublish, canRequestPublish, canRejectPublication, canUnpublish, canExpire, canDuplicate) so a content creator can request publication while only a manager can approve it. All transitions funnel through one saveProposal(proposal, type) helper driven by a messageProposal map of success/error copy, with per-action in-flight flags (isPublishing, isRequesting, isRejecting, isExpiring, isUnpublishing) guarding double submission, and loadCollection() re-running afterwards. expire is implemented by setting endDate to today rather than by a status field. Note the finally block derives the flag name by running the action verb through the nlp library to build a gerund — a clever but fragile way to reset is<Verb>ing, which is why every flag is also reset explicitly. Drag-to-reorder (onDroppedRow) only accepts active and scheduled proposals.
Use cases
Why someone opens this (6)
- A content creator drafting a promotion and requesting publication.
- A manager reviewing the pending queue and approving or rejecting it.
- Taking a live proposal down immediately (unpublish) or ending it today (expire).
- Reordering the proposals shown on the app home screen.
- Duplicating a recurring event rather than re-entering it.
- Previewing exactly how a proposal will look in the app before publishing.
Path map
flowchart LR F(["Proposal list and publication workflow"]):::feat F --> H1["Request → approve → live"]:::ok F --> H2["Taken down"]:::ok F --> H3["Reordered on the home screen"]:::ok F -.-> X1["Publish fails"]:::bad F -.-> X2["Request / reject / unpublish / expire fails"]:::bad F -.-> X3["Duplication fails"]:::bad F -.-> X4["Dragging a non-movable proposal"]:::bad F -.-> X5["Transition not permitted"]:::bad F -.-> X6["Double submission"]:::bad F -.-> X7["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
Request → approve → live
- Content creator finishes a draft and clicks request;
cms.proposals.request-successconfirms and the status becomes pending.- A manager opens the pending proposal, previews it and clicks publish.
publishedis set true, saved, andcms.proposals.publish-successis shown.- The proposal becomes scheduled or active depending on its start date and appears in the app.
Taken down
- Manager clicks unpublish on a live proposal and confirms.
cms.proposals.unpublish-successis shown and the proposal leaves the app.
Reordered on the home screen
- User drags an active proposal to a new position.
onDroppedRowpersists the new order.
Failure paths
Publish fails
Cause — API error on save.
What happens —
cms.proposals.publish-error; state set to error, and the collection reloads so the row reflects reality.
Request / reject / unpublish / expire fails
Cause — API error on the respective transition.
What happens —
cms.proposals.request-error,cms.proposals.reject-publication-error,cms.proposals.unpublish-error,cms.proposals.expire-error.
Duplication fails
Cause — API error while copying.
What happens —
cms.proposals.proposal-duplicated-error.
Dragging a non-movable proposal
Cause — Row is draft, pending or expired.
What happens —
cms.proposals.error-dragging(‘Only active and scheduled proposals can be moved’).
Transition not permitted
Cause — The role’s ability for that transition is false.
What happens — The icon is not rendered for that row.
Double submission
Cause — User clicks publish twice quickly.
What happens — The
isPublishingguard returns a resolved promise instead of firing a second save.
Raw translation key on screen
Cause — The code references
want_reject_publishbut the key does not exist in translations.json.What happens — ember-intl renders the missing key (or its missing-message placeholder) instead of text — visible to every user of this screen until the key is added.
QA checklist
Tick these off while regression-testing this feature. The boxes are plain Markdown, so progress is visible in git diffs.
- ✅ Request → approve → live
- ✅ Taken down
- ✅ Reordered on the home screen
- ⛔ Publish fails
- ⛔ Request / reject / unpublish / expire fails
- ⛔ Duplication fails
- ⛔ Dragging a non-movable proposal
- ⛔ Transition not permitted
- ⛔ Double submission
- ⛔ Raw translation key on screen
Implementation
app/controllers/cms/proposals/index.jsapp/routes/cms/proposals/index.jsapp/enums/proposal-status.jsapp/enums/proposal-filters.jsapp/abilities/proposal.js
Translation keys (27)
Key English title.header.proposalsProposals menu.navbar.proposal.showProposals cms.new-proposalNew proposal cms.proposal.draftDraft cms.proposal.pendingPending cms.proposal.scheduledScheduled cms.proposal.activeActive cms.proposal.expiredExpired publishPublish unpublishUnpublish expireExpire requestRequest reject-publishingReject the publication previewPreview cms.proposals.publish-successThe proposal has been published successfully cms.proposals.publish-errorError on publishing proposal cms.proposals.request-successThe proposal has been requested to publish successfully cms.proposals.request-errorError on requesting the publication of the proposal cms.proposals.reject-publication-successThe proposal has been reject to publish successfully cms.proposals.reject-publication-errorError on rejecting the publication of the proposal cms.proposals.unpublish-successThe proposal has been unpublished successfully cms.proposals.unpublish-errorError on unpublishing proposal cms.proposals.expire-successThe proposal has been expired successfully cms.proposals.expire-errorError on expiring proposal cms.proposals.error-draggingOnly active and scheduled proposals can be moved cms.proposals.proposal-duplicatedThe proposal has been duplicated successfully cms.proposals.proposal-duplicated-errorError on duplicating proposal
Related
- Same area — Proposal editor (content, coupon, push, AI images) · Push notification list & publishing · Push notification editor (scheduling, geofencing, deep links) · Content categories · App button manager (MOFs) · Multicentre proposals
- Shares data with — Activity campaigns (programme grouping) · Customer loyalty — coupon exchanges · Store create & edit · Activity editor (loyalty mechanics, rules & targeting) · Centre editor (modules, app config, integrations) · Extra attributes · Multi-language content authoring · Realtime updates (Pusher)
- Behind the same module — Proposal editor (content, coupon, push, AI images)
Generated from doc/feature-inventory.json · id cms-proposal-list · commit 276788ca6