[object Object]

← back to Marketing Command Center

submissions: Facebook pages_manage_posts App Review package (dashboard steps + use-case + screencast script + reviewer repro)

2becbe5ac915d294adf61a0b2cc1e7939d061d27 · 2026-07-21 16:33:12 -0700 · Steve

Files touched

Diff

commit 2becbe5ac915d294adf61a0b2cc1e7939d061d27
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jul 21 16:33:12 2026 -0700

    submissions: Facebook pages_manage_posts App Review package (dashboard steps + use-case + screencast script + reviewer repro)
---
 docs/submissions/facebook-app-review.md | 244 ++++++++++++++++++++++++++++++++
 1 file changed, 244 insertions(+)

diff --git a/docs/submissions/facebook-app-review.md b/docs/submissions/facebook-app-review.md
new file mode 100644
index 0000000..ef6e8ec
--- /dev/null
+++ b/docs/submissions/facebook-app-review.md
@@ -0,0 +1,244 @@
+# Facebook App Review — `pages_manage_posts` (Advanced Access)
+
+**Submission-ready package** to get **`pages_manage_posts`** approved for **Advanced
+Access** on the **DW Marketing** Meta app, so the Marketing Command Center (MCC) can
+publish first-party posts to Designer Wallcoverings' own Facebook Pages.
+
+| Field | Value |
+|---|---|
+| App name | **DW Marketing** |
+| App ID | `985142067843357` |
+| Business portfolio | Designer Wallcoverings (`214184499265528`) — **business-verified** |
+| Permission requested | **`pages_manage_posts`** → **Advanced Access** |
+| Already granted (Advanced Access) | `instagram_content_publish` (proven live via the MCC → @designerwallcoverings) |
+| Current token scopes (read-level page access, **no page posting**) | `pages_show_list`, `pages_read_engagement`, `business_management`, `instagram_content_publish`, `instagram_basic`, `instagram_manage_*`, `ads_management`, `ads_read`, … (19 total) |
+| Live surface | https://marketing.designerwallcoverings.com (the MCC) |
+| Adapter that uses the permission | `modules/channels/index.js` → `postFacebook()` (POSTs to `/{page-id}/photos`, `/{page-id}/feed`, `/{page-id}/videos` with each Page's own token) |
+| Privacy Policy URL (verified 200) | https://designerwallcoverings.com/policies/privacy-policy |
+| Terms of Service URL (verified 200) | https://designerwallcoverings.com/policies/terms-of-service |
+
+> **Why this is needed:** In Graph API Explorer, `pages_manage_posts` is **not even
+> offered** for this app — it is gated behind App Review for Advanced Access. Without
+> it, every Page token the MCC mints comes back read-only, so `postFacebook()` returns
+> `(#200) The permission(s) pages_manage_posts … need to be approved by App Review`.
+> Instagram publishing already works because `instagram_content_publish` was approved.
+
+---
+
+## 1. Exact Meta App Dashboard path to request Advanced Access
+
+**Prerequisites (verify once, before requesting):**
+
+1. **Business verification complete.** Business Settings → **Security Center** → the
+   Designer Wallcoverings business must show **Verified**. (DW is business-verified —
+   just confirm the green state; Advanced Access for page-management permissions
+   requires it.)
+2. **App is Live**, not in Development. App Dashboard → top toggle → **Live**. (An app
+   in Development mode can't be *submitted* for review — but see §3, dev mode is how
+   you record the screencast.)
+3. **App detail complete** (App Dashboard → **Settings → Basic**):
+   - **Privacy Policy URL** = `https://designerwallcoverings.com/policies/privacy-policy` ✅ 200
+   - **Terms of Service URL** = `https://designerwallcoverings.com/policies/terms-of-service` ✅ 200
+   - **App Icon** (1024×1024), **Category** = *Business & Pages*, **App Domain** =
+     `designerwallcoverings.com`.
+   - The app stays inside the DW business portfolio (it already is).
+
+**The request path:**
+
+> **App Dashboard** (developers.facebook.com/apps/**985142067843357**)
+> → left nav **App Review → Permissions and Features**
+> → search / find **`pages_manage_posts`**
+> → click **Request Advanced Access** (it currently shows *Standard Access* only)
+> → complete the **use-case form** (paste §2 below) + attach the **screencast** (§3)
+> + fill the **reviewer instructions** box (§4)
+> → **App Review → Requests** → review the bundle → **Submit for review**.
+
+You can request `pages_read_engagement` Advanced Access in the same submission if the
+dashboard shows it as Standard-only, but the **blocker permission is
+`pages_manage_posts`** — that's the one that gates Facebook Page posting.
+
+---
+
+## 2. Use-case justification (paste-ready, reviewer-facing)
+
+> **How our app uses `pages_manage_posts`**
+>
+> Designer Wallcoverings operates the **Marketing Command Center (MCC)**, a first-party
+> internal marketing dashboard at marketing.designerwallcoverings.com. The MCC
+> publishes **our own** wallcovering product photos, new-arrival announcements, and
+> room-setting design imagery — each with a caption and a link back to the
+> corresponding product page on our store — to **Facebook Pages that our business owns
+> and administers** (the Designer Wallcoverings Page and our sister-brand Pages, all
+> under our verified business portfolio).
+>
+> `pages_manage_posts` is used **solely** to create these first-party marketing posts
+> on Pages we own and admin. A marketer opens the MCC's Composer, selects a product
+> post we generated, chooses one of our own Pages as the target, and clicks Publish;
+> the app calls `POST /{page-id}/photos` (or `/feed` for text) using that Page's own
+> access token to create the post.
+>
+> **We do not** manage, post to, or access any third-party Pages. **We do not** post
+> user-generated content, and no end user other than our own staff ever authenticates.
+> Every target Page is owned and administered by our business.
+>
+> **Value to our Page followers:** our Facebook audiences get timely **new-arrival
+> announcements**, **design inspiration** (room settings showing our wallcoverings in
+> context), and direct links to shop the featured product — the same first-party
+> product marketing we already publish to our Instagram Business account
+> @designerwallcoverings via the already-approved `instagram_content_publish`
+> permission. `pages_manage_posts` simply extends that identical first-party workflow
+> to our owned Facebook Pages.
+
+---
+
+## 3. Screencast script / shot-list
+
+Meta requires a video showing the **real** flow that exercises the permission —
+creating a post on a Page. Record **landscape 1280×720+**, **60–120 s**, cursor
+visible, narrated.
+
+### ⚠️ The chicken-and-egg problem (read first)
+
+`pages_manage_posts` posting **fails until the permission is approved** — but the
+screencast must **show a successful Page post**. Meta's intended resolution:
+
+> **Development-mode / app-admin grant.** An app in **Development mode grants the
+> requested permissions to the app's own admins/developers/testers WITHOUT App
+> Review.** So you (the app admin) can generate a Page token that *does* carry
+> `pages_manage_posts`, run the real MCC publish flow, and it will **actually post** —
+> giving you a genuine, passing screencast of the exact flow the reviewer wants.
+
+**Recommended approach (honest):**
+
+1. Flip the app to **Development mode** (App Dashboard toggle).
+2. As an app admin, mint a Page token in **Graph API Explorer** for the DW Page with
+   `pages_manage_posts` + `pages_show_list` + `pages_read_engagement` checked (in dev
+   mode these are grantable to admins). Save it as the MCC's `FB_PAGE_ACCESS_TOKEN`, or
+   let the Pages picker cache it.
+3. **Record the real flow** below — the post publishes for real to the DW Page.
+4. Flip the app back to **Live** and submit the recording.
+
+If for any reason a live dev-mode Page post can't be produced in time, the **fallback**
+is to record the **identical MCC flow driving the already-working Instagram publish**
+(same Composer, same Page picker, same Publish button — `instagram_content_publish` is
+approved and posts live to @designerwallcoverings) and **narrate** that the Facebook
+path is byte-for-byte the same `postFacebook()`/`postInstagram()` pipeline awaiting
+only this permission. This is weaker (reviewers strongly prefer seeing the actual
+permission fire), so **use the dev-mode real-post path if at all possible.**
+
+### Shot-list
+
+| # | On screen | Narration |
+|---|-----------|-----------|
+| 1 | Browser → `marketing.designerwallcoverings.com`, basic-auth prompt, then the MCC dashboard loads. | "This is Designer Wallcoverings' internal Marketing Command Center — a first-party tool only our staff use." |
+| 2 | The **Engine / Composer** panel; a DW **product / new-arrival post** (product photo + caption + product link) is selected. | "I'm selecting one of our own wallcovering product posts — our photo, our caption, a link to that product on our store." |
+| 3 | The **Facebook Page picker** — show the list of **owned/admin Pages**, select the **Designer Wallcoverings** Page. | "I choose one of the Facebook Pages our business owns and administers as the publish target." |
+| 4 | Click **Publish**; the UI shows success (post id returned by `postFacebook()`). | "I publish. The app calls the Pages API to create this post on our own Page — this is exactly the `pages_manage_posts` action." |
+| 5 | Open **facebook.com/DesignerWallcoverings** in a new tab; show the **new post live** on the Page (photo + caption + link). | "And here's the post live on our Facebook Page — the new-arrival announcement our followers now see." |
+
+Clearly show step 4→5: the create-post action and the resulting live post. That is the
+`pages_manage_posts` proof the reviewer needs.
+
+### Recording tools
+
+- `~/.claude/skills/app-demo-video` — narrated Playwright click-through demo generator
+  (drives the URL, highlights clicks, adds TTS voiceover, renders MP4). Good for a
+  clean, repeatable capture of steps 1–4.
+- macOS **`screencapture`/QuickTime screen recording** or the `screenrecord` skill for
+  a straight human-driven capture (best when you need to hop to the live Facebook tab
+  in step 5).
+- Trim to ≤120 s, keep the cursor and the Publish→live-post transition visible.
+
+---
+
+## 4. Step-by-step reproduction instructions (paste-ready, for the reviewer)
+
+> **Reviewer test instructions — DW Marketing (`pages_manage_posts`)**
+>
+> This is an **internal, first-party marketing tool**; only Designer Wallcoverings
+> staff authenticate, and it only posts to Facebook Pages our business owns. It is not
+> a public app, so it sits behind HTTP Basic Auth. The attached screencast demonstrates
+> the full publish flow end-to-end on our own owned Page.
+>
+> To reproduce:
+> 1. Open **https://marketing.designerwallcoverings.com**.
+> 2. At the Basic-Auth prompt, sign in with **username `admin`** and the password we
+>    provide in the App Review notes field (the MCC's `MCC_PASS` — a review-specific
+>    credential; the app **fails closed** if it's unset). *(Steve: paste the current
+>    `MCC_PASS` value from this project's `.env` into the reviewer notes at submission
+>    time — do not commit it here.)*
+> 3. In the **Composer / Engine** panel, select any Designer Wallcoverings product /
+>    new-arrival post (product image + caption + product link).
+> 4. In the **Facebook Page picker**, choose the **Designer Wallcoverings** Page (one of
+>    the Pages our business owns and administers). Click **↻ refresh** on the picker if
+>    the Page list is empty, to load our owned Pages.
+> 5. Click **Publish**. The app calls `POST /{page-id}/photos` (or `/feed`) with that
+>    Page's own token — this is the `pages_manage_posts` action.
+> 6. Open **facebook.com/DesignerWallcoverings** and confirm the new post is live on the
+>    Page.
+
+> **Note on access:** if the reviewer cannot use the basic-auth surface, the identical
+> flow is shown in the attached screencast, and the app already publishes live to our
+> Instagram Business account @designerwallcoverings via the approved
+> `instagram_content_publish` permission using the same code path.
+
+---
+
+## 5. Checklist
+
+### Done / verified this session
+- [x] Confirmed the app **lacks** `pages_manage_posts` (not offered in Graph Explorer →
+      needs App Review for Advanced Access).
+- [x] Confirmed `instagram_content_publish` **is** approved & posts live (precedent for
+      the identical first-party use-case).
+- [x] Identified the exact adapter: `modules/channels/index.js` → `postFacebook()`
+      (`/photos`, `/feed`, `/videos`).
+- [x] Verified Privacy Policy URL returns **200**:
+      `https://designerwallcoverings.com/policies/privacy-policy`.
+- [x] Verified Terms of Service URL returns **200**:
+      `https://designerwallcoverings.com/policies/terms-of-service`.
+- [x] Confirmed the MCC **fails closed** on basic auth (`admin` / `MCC_PASS`) — so the
+      reviewer needs a provided credential (not a hardcoded default).
+- [x] Authored: use-case justification, screencast script, reviewer repro, dashboard path.
+
+### To do (needs a human — Steve)
+- [ ] **Confirm business verification** shows **Verified** in Security Center.
+- [ ] Confirm **App detail** complete (icon 1024×1024, category *Business & Pages*,
+      privacy + ToS URLs pasted into Settings → Basic).
+- [ ] Set the app **Live** for submission.
+- [ ] **Record the screencast** — dev-mode real-post path preferred (§3).
+- [ ] **Request Advanced Access** for `pages_manage_posts` and paste §2 into the form.
+- [ ] Paste the **`MCC_PASS`** review credential into the App Review notes field (§4).
+- [ ] **Submit** (App Review → Requests → Submit).
+
+---
+
+## 6. What needs a human vs what's done
+
+**Done (in this doc):** the reviewer-facing use-case text, the screencast shot-list +
+recommended recording path, the reviewer reproduction steps, the exact dashboard
+navigation, and verification that the policy URLs 200.
+
+**Needs Steve (cannot be automated — Meta-side, gated, or credential-bearing):**
+1. Confirm **business verification** is green.
+2. Complete **app detail** + flip **Live**.
+3. **Record the screencast** (ideally via the dev-mode grant so a real Page post fires).
+4. **Request Advanced Access** for `pages_manage_posts` in the App Dashboard and submit.
+5. Provide the **`MCC_PASS`** review credential to Meta in the notes field.
+
+---
+
+## Honesty notes
+
+- **Timeline:** `pages_manage_posts` Advanced Access review commonly takes **days to a
+  few weeks**, and Meta frequently **rejects** first attempts if the screencast doesn't
+  clearly show the permission *actually creating a post*. Budget for one round of
+  back-and-forth.
+- **Screencast chicken/egg (biggest gotcha):** you cannot post to a Page until the
+  permission is approved — so record the screencast with the app in **Development mode**
+  (or with an app-admin/tester token), where `pages_manage_posts` is granted to admins
+  **without** review, letting the flow post for real. That real post is what gets the
+  submission approved. Recording only the Instagram proxy is a fallback, not the plan.
+- **Basic auth:** the MCC fails closed, so a reviewer literally cannot open it without
+  the `MCC_PASS` credential — it **must** go in the reviewer-notes field, and the
+  screencast is the primary evidence regardless.

← eb16f00 submissions: LinkedIn dedicated-app + Community Management A  ·  back to Marketing Command Center  ·  LinkedIn: record CMA self-serve blocker (auto-added default aae7c9c →