docs: record Gate 0.8 resolution + Gate 0.9 LinkedIn app / CMA progress

- deferred-gates.md: Gate 0.8 RESOLVED — clean-room Postgres 17 + Redis 7 in a
  dedicated Dokploy project; service names, hosts, env-var locations recorded.
- linkedin-apps.md: app created (Client ID 78s8f53y5spyo4), company-page +
  business-email verified, Community Management API Development Tier submitted
  (review in progress). Notes that other products grey out while CMA is pending.
- docs/handoffs/2026-05-13-handoff.md: committed (was untracked).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Angelo B. J. Luidens
2026-06-03 15:31:02 -04:00
parent 1d1494a77c
commit c24ea815f3
3 changed files with 300 additions and 33 deletions
+30 -8
View File
@@ -4,15 +4,37 @@ Items that could not be completed in the Stage 0 execution window and must be re
## Gate 0.8 — Postgres + Redis on PaaS ## Gate 0.8 — Postgres + Redis on PaaS
**Status:** Deferred 2026-04-19. **Status:** ✅ RESOLVED 2026-06-03 (via Dokploy MCP, resolution option 3 — clean-room stack).
**Reason:** Dokploy MCP tools (`mcp__dokploy__*`) were not loaded in the Stage 0 session, and `DOKPLOY_API_KEY` was not in the WSL environment. Direct API query not possible in-session. **Reason (historical):** Dokploy MCP tools (`mcp__dokploy__*`) were not loaded in the Stage 0 session, and `DOKPLOY_API_KEY` was not in the WSL environment. Direct API query not possible in-session.
**Blocks:** Stage 2 (database + API) — the scheduler and admin cannot run without a Postgres + Redis pair. **Blocks (now cleared):** Stage 2 (database + API) — the scheduler and admin cannot run without a Postgres + Redis pair.
**Resolution options:**
1. **Recommended:** Restart Claude Code with the vault's `.mcp.json` Dokploy MCP attached; run `mcp__dokploy__list_applications` / equivalent against `sg-paas-s1.stargue.net` to verify or provision.
2. Angelo confirms via Dokploy web UI and reports service names + connection hostnames.
3. Provision fresh Postgres + Redis services in the `stargue-publishing-engine` Dokploy stack (clean room; isolates blast radius from other PaaS apps).
**Acceptance when resolved:** this file updated with service names, hostnames, and connection-string env-var locations (Dokploy secrets). ### Resolution (2026-06-03)
Provisioned a dedicated clean-room Dokploy project on `sg-paas-s1.stargue.net`, isolating blast radius from other PaaS apps (option 3).
| Item | Value |
|---|---|
| Dokploy project | `stargue-publishing-engine` (`projectId: Y6R_4ML2N0Vsztk0UVi1W`) |
| Environment | `production` (`environmentId: hkvob7vx02lzkn3GhpHMD`) |
| Postgres service | "Publishing Engine Database" (`postgresId: O_BjqkxljdMU3xLb3q09M`) — image `postgres:17`, status `done` |
| Postgres internal host | `stargue-pubeng-postgres-n9c1gc` (Docker network alias) port `5432` |
| Postgres db / user | `publishing_engine` / `publishing_engine` |
| Postgres volume | `stargue-pubeng-postgres-n9c1gc-data``/var/lib/postgresql/data` |
| Redis service | "Publishing Engine Redis" (`redisId: fZR9Bdx8-3d99uOrrqFe5`) — image `redis:7`, status `done` |
| Redis internal host | `stargue-pubeng-redis-9tebfd` (Docker network alias) port `6379` |
| Redis volume | `stargue-pubeng-redis-9tebfd-data``/data` |
**Connection-string env-var locations (NOT stored in git):**
- `DATABASE_URL` = `postgres://publishing_engine:<PG_PASSWORD>@stargue-pubeng-postgres-n9c1gc:5432/publishing_engine`
- `REDIS_URL` = `redis://default:<REDIS_PASSWORD>@stargue-pubeng-redis-9tebfd:6379`
- Secret **values** live in Dokploy (retrieve via `mcp__dokploy__postgres-one` / `mcp__dokploy__redis-one`). They will be injected as Dokploy secrets on the **app** services (`apps/mcp-linkedin`, `apps/scheduler`, `apps/admin`) once those are created in Stage 5+. No app service exists yet, so there is nowhere to attach them today.
**Remaining to fully unblock live DB tests:**
1. Run `0000_initial_schema.sql` against the new DB. The internal hostname is only resolvable inside the Dokploy Docker network, so either (a) temporarily add an external port via `mcp__dokploy__postgres-saveExternalPort` and run `bun run db:migrate` from WSL with the external `DATABASE_URL`, then remove the port; or (b) run the migration from a one-shot container inside the stack.
2. Run `bun run db:migrate:rehearse` (forward-then-rollback row-count hash check).
3. Re-enable `INTEGRATION=1`-gated tests with the connection strings wired.
**Acceptance (met):** service names, hostnames, and connection-string env-var locations recorded above; secret values held in Dokploy, not committed.
## Gate 0.9 — LinkedIn Developer Portal apps ## Gate 0.9 — LinkedIn Developer Portal apps
+197
View File
@@ -0,0 +1,197 @@
---
created: 2026-05-13T12:35
updated: 2026-05-13T12:35
tags:
---
# Publishing Engine — Session Handoff 2026-05-13
**Purpose:** let the next session pick up cold with full state of the Stargue Publishing Engine build. Source: this vault note + mirror at `docs/handoffs/2026-05-13-handoff.md` in the repo.
**Repo:** `https://git.stargue.net/admin/stargue-publishing-engine` (local: `/home/devuser/projects/stargue-publishing-engine/` via WSL Debian)
**Plan v2 (SSoT):** [[Plan - Phase 1 Automated Publishing Engine|Plan - Phase 1 Automated Publishing Engine.md]] (vault) + `docs/plans/2026-04-19-phase1-plan.md` (repo mirror)
**PRD:** [[Publishing Engine PRD]]
**Panel verdicts:** `docs/plans/bmad-panel-verdicts-publishing-engine-phase1-20260419.json` (1 APPROVE, 6 REVISE, 0 REJECT — all principles ≥3)
**Doctrine:** `.clinerules/12-foundational-principles.md` adopted from DQMS
---
## Where we stand — quick read
| Stage | Status | Commit | Tests | Notes |
|---|---|---|---|---|
| 0 — Governance + scaffolding | ✅ Complete | `1dc1a1a` (2026-04-19) | n/a | 11 workspaces typecheck clean |
| 1 — Shared packages | ✅ Complete | `e529651` (2026-04-26) | 50/50 | 4 packages: schema, sanitize, linkedin-client (stubs), observability |
| 2 — DB + middleware + API | 🟡 Partial | `c73b7e4` (2026-04-26) | 79/79 cumulative | Live-DB integration tests blocked by **gate 0.8** |
| 3 — LinkedIn MCP server | 🟡 Partial | `7aa3137` (2026-04-26) | 106/106 cumulative | Live-LinkedIn blocked by **gate 0.9** |
| 4 — Scheduler + cadence | 🟡 Partial | `a4e4306` (2026-04-26) | 117/117 cumulative | BullMQ + integration blocked by **gates 0.8 + 0.9** |
| 5 — Admin dashboard (Next.js + A11y) | ❌ Not started | — | — | Independent of gates; can start anytime |
| 6 — stargue-com/.net integration | ❌ Not started | — | — | Independent of gates |
| 7 — Content + metrics bootstrap | ❌ Not started | — | — | 7.1 + 7.2 independent of gates |
**Last activity:** 2026-04-26 (commit `a4e4306`). Repo idle since. Today is 2026-05-13 — ~2.5 weeks of pause.
---
## Deferred gates (the real blockers)
### Gate 0.8 — Postgres + Redis on PaaS
**Status:** Dokploy MCP was loaded in the 2026-04-19 session but verification not completed before pause. **Resume action:** with Dokploy MCP attached, run `mcp__dokploy__project-all` → identify Stargue PaaS project → `mcp__dokploy__postgres-search` + `mcp__dokploy__redis-search` to see existing instances; provision new ones in a `stargue-publishing-engine` project if none are shareable.
**Why it blocks:** Stage 2 live-DB integration tests, Stage 3 token-store live tests, Stage 4 BullMQ worker, Stage 5 admin auth flow.
**Next steps when resolved:**
1. Run `0000_initial_schema.sql` migration on the new DB
2. Run `bun run db:migrate:rehearse` (script lives at `packages/schema/db/migrations/rehearse.ts`)
3. Wire connection strings into Dokploy secrets `DATABASE_URL`, `REDIS_URL`
4. Re-enable the integration tests gated behind `INTEGRATION=1`
### Gate 0.9 — LinkedIn Developer Portal apps
**Status:** Pending Angelo's manual action. Checklist ready at `docs/linkedin-apps.md`.
**Why it blocks:** Stage 3.13.7 live posting, Stage 4 end-to-end publish, Stage 7.4 first scheduled post.
**Next steps when resolved:**
1. Angelo registers app at linkedin.com/developers/ linked to Stargue Company Page `urn:li:organization:2605890`
2. Enables Sign-In with OpenID Connect + Share on LinkedIn (instant self-service)
3. Submits Community Management API + MDP partner-access requests (multi-week review — file ASAP to start the clock)
4. Drops `LINKEDIN_CLIENT_ID`, `LINKEDIN_CLIENT_SECRET`, `LINKEDIN_TOKEN_ENCRYPTION_KEY` into Dokploy secrets
5. Update `docs/linkedin-apps.md` registry with app IDs
---
## What's already built (don't re-invent)
### `packages/schema` (full SSoT for data shapes)
- `frontmatter.ts` — Zod schema for vault frontmatter (status, language, outlets[], sanitize, scheduled, version)
- `db.ts` — Drizzle schema for 7 tables: content, publications (with `idempotency_key UNIQUE`), approvals, metrics, linkedin_tokens, audit, outlet_feature_flags
- `rate-limit.ts` — token-bucket implementation, pure-function
- `csrf.ts` — double-submit cookie pattern
- `authz.ts` — Cerbos-equivalent policy primitives
- `api-contracts.ts` — Zod request/response schemas for admin API
- `drizzle.config.ts` + `db/migrations/0000_initial_schema.sql` + `0000_initial_schema.down.sql` + `db/migrations/rehearse.ts`
### `packages/sanitize` (fail-closed content pipeline)
- `rules.ts` — PRIVATE_PATH_PREFIXES (Family Matters, Financial Matters, Journal, Clients NDA…), PRIVATE_PATH_PATTERNS, PRIVATE_TAGS (`#private`, `#heal-internal`, `#confidential`), OUTLET_LENGTH_LIMITS
- `errors.ts` — SanitizeError with codes: PRIVATE_PATH_BLOCKED, PRIVATE_TAG_BLOCKED, WIKILINK_TO_PRIVATE_PATH, OUTLET_LENGTH_EXCEEDED
- `index.ts``sanitize(markdown, opts)` returns `{ body, contentHash, warnings }` — strips wikilinks/embeds/dataview/callouts, enforces blocklist + tag firewall + length, computes SHA-256 hash
- `corpus.test.ts` — Stage 1.2 DoD test: 12 private + 6 clean fixtures round-trip correctly
### `packages/linkedin-client` (Posts API client + token store)
- `types.ts` — LinkedIn Posts API request/response types (Posts API v202404, not legacy UGC)
- `client.ts` — HTTP client; respects `LinkedIn-Version: 202404` + `X-Restli-Protocol-Version: 2.0.0`
- `token-store.ts` — encrypted persistence; **uses AES-256-GCM via `node:crypto`** (NOT libsodium — see D-001 in `docs/deferred-gates.md` for the deviation rationale: libsodium-wrappers ESM bug under Bun)
- `client.test.ts` + `token-store.test.ts` — 4/4 round-trip tests pass
### `packages/observability` (Pino + correlation IDs)
- `index.ts` — Pino logger with PII-redaction paths (access_token, refresh_token, client_secret, *_ct fields), `newCorrelationId()`, `child(bindings)` helper
### `apps/mcp-linkedin` (Stage 3 partial — structural complete, live blocked)
- `server.ts``createServer` factory pattern, injectable deps (KillSwitch, AdvisoryLock); MCP_SPEC_VERSION pinned `2024-11-05`; `validateToolCall`, `listTools`, `outletForAuthorUrn` helpers
- `tools.ts` — 9 Zod tool schemas: whoami, auth_status, create_post, create_article, upload_media, create_post_with_media, delete_post, get_post_metrics, get_profile_stats
- `oauth.ts` — auth-code URL builder + HMAC-protected state parameter (no PKCE — LinkedIn 3LO doesn't support it)
- `kill-switch.ts``outlet_feature_flags` reader with cache invalidation
- `refresh-lock.ts` — Postgres advisory-lock primitive; **4-concurrent rotation test passes** (TEA gap 3 closed)
### `apps/scheduler` (Stage 4 partial — pure pieces complete)
- `cadence.ts` — Beta(1,19) posterior optimizer, `propose(history, config) → [Proposal]`; all 4 thresholds verified (≥8 samples, ≥4 weeks, ≥20% ratio, disjoint 95% CIs); never auto-applies (RBR)
- `publish-loop.ts` — state-machine transition function `pending→queued→dispatching→published`, retry-vs-DLQ branch, cancellation path
- `worker.ts` — entry stub (BullMQ wiring blocked by Redis on gate 0.8)
### `apps/admin` (not started)
- `src/index.ts` — stub only. Next.js scaffold + Authentik SSO + queue/publications/auth/metrics pages all pending.
---
## Architecture decisions worth remembering
1. **D-001 token cipher: AES-256-GCM, not libsodium secretbox.** Bun ESM bug in `libsodium-wrappers`. Same AEAD security profile. Documented in `docs/deferred-gates.md`. Remediation path noted if libsodium fixes the bug.
2. **Scheduler imports `linkedin-client` directly** — MCP transport is stdio-only for interactive Claude Code use. No HTTP MCP transport in Phase 1 (architect gap 2).
3. **`apps/api` collapsed into `apps/admin`** — Next.js App Router route handlers cover the API surface; less infra (architect gap 1).
4. **LinkedIn Posts API `/rest/posts`** — NOT the legacy `/v2/ugcPosts`. Headers: `LinkedIn-Version: 202404`, `X-Restli-Protocol-Version: 2.0.0`.
5. **No PKCE in OAuth** — LinkedIn 3LO doesn't document it; confidential-client with HMAC `state` parameter is what we use.
6. **`idempotency_key UNIQUE` on `publications`** — sha256(content_id || outlet || scheduled_at). Prevents double-post on retry.
7. **Kill-switch via `outlet_feature_flags` table** — fast disable without redeploy. Cached at MCP server with invalidation on table change.
---
## Next session — priority order
### Path A: Resolve gates first (recommended if Angelo + Dokploy access available)
1. **Gate 0.8** — Dokploy MCP query → provision Postgres + Redis in `stargue-publishing-engine` project on `sg-paas-s1.stargue.net`
2. **Gate 0.9** — Angelo files LinkedIn Dev Portal apps (~30 min for OIDC + Share; submit Community Management API + MDP requests to start the partner-approval clock)
3. With both gates open, unblock Stages 2.6, 3.43.9, 4.14.3 live integration tests
4. Move to Stage 5 (admin dashboard)
### Path B: Continue parallel work (if gates remain blocked)
1. **Stage 5** — Admin dashboard scaffold: Next.js App Router + shadcn/ui + Nine Laws design tokens; pages `/queue`, `/publications/:id`, `/auth/linkedin`, `/metrics`; A11y CI (axe-core + @axe-core/playwright). Authentik stub for local dev.
2. **Stage 6** — Add `@stargue/sanitize` + `@stargue/schema` as workspace deps to stargue-com + stargue-net; replace ad-hoc frontmatter parsing; assert zero wikilinks in rendered HTML.
3. **Stage 7.1** — Run `/market audit` baseline on stargue.com + stargue.net; save to `docs/marketing-baseline-2026-05.json`.
4. **Stage 7.2** — Draft 7 Cs posts 28 (Commitment, Co-Creation, Connection, Communication, Celebration & Course Correction, Caring & Crossing, Synthesis) — long-form for stargue.com + LinkedIn-optimized variants. Source content from `7 Cs LinkedIn Series - Continuation Plan.md`. Run each through autoresearch optimization to composite ≥8.
### Path C: Mixed (most realistic)
- Angelo does Gate 0.9 in parallel (~30 min self-service; partner approvals run async for weeks)
- Claude provisions Gate 0.8 via Dokploy MCP
- Concurrently start Stage 5 and 7.2
---
## Open items / things to verify
1. **MDP + Community Management API timeline** — once filed, track approval state weekly. MDP rejection is the trigger for the 60-day-re-auth fallback.
2. **Authentik instance reachability** — plan §8 q3 said "shared instance for all Stargue services"; needs runtime verification before Stage 5.2.
3. **Neon free-tier mirror** — Stage 7.5 DR test pending. Set up nightly `pg_dump → Neon` cron when gate 0.8 resolved.
4. **stargue-com/.net package.json sync** — collision was fixed (commit `fd43214` on stargue-net) — verify both repos still align before Stage 6.
5. **LinkedIn algorithm-reach risk** — plan §9 row added by analyst panel. Once first 4 posts ship, monitor engagement-delta vs Angelo's existing manual baseline; if suppression detected, fall back to draft-and-prompt workflow.
---
## Files to read first in next session
In order, for cold start:
1. This handoff
2. `docs/plans/2026-04-19-phase1-plan.md` (in the repo) — full plan v2
3. `docs/deferred-gates.md` — for D-001 + gate status
4. `CLAUDE.md` in the repo — for governance + canonical LinkedIn facts
5. Last 4 commits via `git log` — for exact stage progress
6. `docs/linkedin-apps.md` — for Angelo's manual checklist
---
## Memory notes already saved
- `project_publishing_engine.md` — overall project state
- D-001 cipher deviation is in `docs/deferred-gates.md` (in repo) — no separate memory note needed since the deviation is project-local
- BMAD panel verdicts cached at `docs/plans/bmad-panel-verdicts-publishing-engine-phase1-20260419.json`
---
## Commands cheatsheet
```bash
# WSL Debian — always run there
wsl -d Debian -- bash -c 'cd /home/devuser/projects/stargue-publishing-engine && <cmd>'
bun install # workspace deps
bun run typecheck # all 11 workspaces
bun run test # 117/117 currently passing
bun run db:migrate # apply Drizzle migrations (needs DATABASE_URL)
bun run db:migrate:rehearse # expand-then-contract rehearsal
# Gitea
git push # auto-deploys via Dokploy webhook (Phase 0 sites);
# Publishing Engine apps deploy on separate Dokploy stack (Stage 5+)
```
---
## Related
- [[Publishing Engine PRD]]
- [[Plan - Phase 1 Automated Publishing Engine]]
- [[7 Cs LinkedIn Series - Continuation Plan]]
- [[Design Philosophy - The Nine Laws of the Hearth]]
- [[Outlet Profiles/LinkedIn]]
- [[Implementation Progress]] — update with this handoff's status table after the next session
+73 -25
View File
@@ -2,45 +2,93 @@
**Status tracker for Stargue's LinkedIn apps.** Every row must stay current — Claude Code verifies against this file during Stage 0 DoD 0.9. **Status tracker for Stargue's LinkedIn apps.** Every row must stay current — Claude Code verifies against this file during Stage 0 DoD 0.9.
## Applications ## App: Stargue Publishing Engine (created 2026-06-03)
| App | Product | Purpose | Scopes granted | State | App ID | Approval date | Notes | - **Client ID:** `78s8f53y5spyo4`
|---|---|---|---|---|---|---|---| - **Client Secret:** present on Auth tab (Primary Client Secret) — copy to Dokploy secret `LINKEDIN_CLIENT_SECRET`, never commit
| Stargue Publishing Engine — Sign In | Sign In with LinkedIn using OpenID Connect | Identity / `whoami` | `openid profile email` | **TODO: register** | — | — | Standard — no approval required beyond Dev Portal self-service | - **App type:** Standalone app
| Stargue Publishing Engine — Member Share | Share on LinkedIn | Personal-profile posts (Angelo) | `w_member_social` | **TODO: register** | — | — | Standard — attached to the same app as Sign In | - **LinkedIn Page:** Stargue (`urn:li:organization:2605890`) — association is permanent, **NOT yet verified** (see below)
| Stargue Publishing Engine — Org Share | Community Management API | Company-page posts (`urn:li:organization:2605890`) | `w_organization_social`, `r_organization_social` | **TODO: apply** | — | — | Requires LinkedIn partner approval; submit via Dev Portal "Request access" | - **Privacy policy URL:** https://stargue.com/privacy (live 2026-06-03) ✅
| Stargue Publishing Engine — Refresh | Marketing Developer Platform (MDP) | Programmatic refresh tokens (eliminates 60-day re-auth) | (extends above) | **TODO: apply** | — | — | Requires LinkedIn partner approval; multi-week review | - **Business email:** `info@stargue.com`**verified 2026-06-03** ✅ (required for CMA)
- **Access-token TTL:** 2 months / 5,184,000 s (confirms the 60-day re-auth design; programmatic refresh is MDP-gated)
- **Authorized redirect URLs:** none added yet
- **OAuth scopes:** none yet
## Status update — 2026-06-03 13:15
**Community Management API (Development Tier) = SUBMITTED → "Review in progress."** Access form completed (legal name `Stargue N.V.`, Curaçao address Dwarsweg 9 Julianadorp LP71, website stargue.com, 3 use cases: Page management + Page analytics + Profile management, first-party compliance description). Decision comes by email to `info@stargue.com`. (Note: the Qualtrics "session expired" end-screen was a false alarm — it did submit.)
**⚠️ NEW OBSERVATION — once CMA was requested, ALL other products greyed out** (Share on LinkedIn, Sign In with OpenID Connect, etc. now show disabled "Request access"). **Uncertain (not yet confirmed) whether this is:**
- (a) **temporary** — a lock while CMA is in review, that lifts on approval; or
- (b) **permanent** — CMA apps are meant to be CMA-only (consistent with FAQ #1/#2 treating CMA + other products as a separate-app pattern).
**Architecture decision deferred pending CMA outcome:**
- If other products **un-grey** after CMA approval → keep single app, add Sign In + Share here.
- If they **stay greyed****two-app split** after all: this app = CMA (company + profile posting via CMA), a **second app** = Sign In (OIDC identity) + Share on LinkedIn (`w_member_social`).
- **Possible simplification:** CMA's *Profile management* use case may already cover posting to Angelo's own profile, reducing/eliminating the need for a separate "Share on LinkedIn" product. Confirm when wiring OAuth scopes.
## ⚠️ Why the Community Management API is greyed — VERIFIED (2026-06-03)
The app has **no other products**, so FAQ #4 ("greyed because the app already has other products") is **not** the cause here. The real prerequisites — confirmed against LinkedIn docs and visible on the app's **Settings** tab — are:
1. **Company-Page verification (PRIMARY GATE).** Settings shows *"This app is not verified as being associated with this company"* + a **Verify** button. A **super-admin of the Stargue Company Page** must approve the app↔page association. CMA stays greyed until done. **Dependency: Angelo must be, or have access to, a super-admin of the Stargue Page.**
2. **Business-email verification.** Settings banner: *"Update your business email…"*. The CMA access form requires a **verified business email**.
3. **Access-form requirements.** CMA is for **registered legal organizations, commercial use only**. Form asks for: legal org name, registered address (Curaçao), website, **privacy policy URL** (✅ live), verified business email.
4. **Secondary — product order (FAQ #4).** If an app *already has* other products, the CMA request greys out. Not our cause today (clean app), but it means: **request CMA before adding Share/Sign In**, or keep CMA on its own app.
### Corrected recommendation: single app, CMA-first
1. **Verify** the app ↔ Stargue Page (super-admin approves).
2. **Set + verify** the business email.
3. Request **Community Management API first** → complete access form → **Development Tier** (limits: 500 req/app, 100 req/member).
4. Apply **Standard Tier** (access form + screencast demonstrating each use case).
5. **Then** add **Share on LinkedIn** + **Sign In with OpenID Connect** (instant) for personal posting + identity.
(Two-app split — CMA on its own app, Share/Sign In on another — remains a fallback if Page verification cannot be completed on this app.)
## Products — observed state (2026-06-03 Products tab)
| Product | Needed for | Self-service? | State on this app |
|---|---|---|---|
| Community Management API | Company-page posts (`w_organization_social`, `r_organization_social`) | No — needs verification + Dev→Standard | **🔒 Greyed** — pending Page verification + business email |
| Sign In with OpenID Connect | Identity / `whoami` (`openid profile email`) | Yes (instant) | Available — request AFTER CMA |
| Share on LinkedIn | Personal-profile posts (`w_member_social`) | Yes (instant) | Available — request AFTER CMA |
| Marketing Developer Platform / Advertising / Lead / Conversions | Programmatic refresh tokens; marketing | No (partner review) | Greyed; optional (60-day re-auth fallback exists) |
Other products present but not needed: LinkedIn Ad Library, Verified on LinkedIn (available); Live Events, Events Mgmt, Member/Pages Data Portability (greyed).
## OAuth redirect URIs ## OAuth redirect URIs
- Production: `https://publishing.stargue.net/auth/linkedin/callback` Add under the app's **Auth** tab (not yet done):
- Production: `https://publishing.stargue.net/auth/linkedin/callback` (note: `publishing.stargue.net` subdomain is Stage 5+; admin app not built yet)
- Local dev: `http://localhost:3002/auth/linkedin/callback` - Local dev: `http://localhost:3002/auth/linkedin/callback`
## Client credentials ## Client credentials
Stored in Dokploy secrets on `sg-paas-s1.stargue.net`: Dokploy secrets on `sg-paas-s1.stargue.net` (project `stargue-publishing-engine`, once app services exist in Stage 5+):
- `LINKEDIN_CLIENT_ID` - `LINKEDIN_CLIENT_ID` = `78s8f53y5spyo4`
- `LINKEDIN_CLIENT_SECRET` - `LINKEDIN_CLIENT_SECRET` = (from Auth tab — pending copy)
- `LINKEDIN_TOKEN_ENCRYPTION_KEY` (32-byte key for `crypto_secretbox`) - `LINKEDIN_TOKEN_ENCRYPTION_KEY` (32-byte; **AES-256-GCM** per D-001 — see `deferred-gates.md`)
## Manual setup checklist (Stage 0.9) ## Manual setup checklist (Stage 0.9)
1. Sign in to `https://www.linkedin.com/developers/` as Angelo (personal account). 1. Sign in to `https://www.linkedin.com/developers/` as Angelo.
2. Create app "Stargue Publishing Engine" linked to Stargue Company Page `urn:li:organization:2605890` (required for Community Management API eligibility). 2. Create app "Stargue Publishing Engine" linked to Page `urn:li:organization:2605890` (Client ID `78s8f53y5spyo4`).
3. Under **Products**, request: 3. ✅ Privacy policy URL live at https://stargue.com/privacy.
- Sign In with LinkedIn using OpenID Connect (self-service; instant) 4.**Verify app ↔ Company Page** (done 2026-06-03 — un-greyed all products). PRIMARY gate for CMA.
- Share on LinkedIn (self-service; instant) 5.**Business email verified**`info@stargue.com` (2026-06-03).
- Community Management API (submit partner-access request — fill in use-case: "Programmatic posting of original content to Stargue Company Page for knowledge-management-as-a-service practice") 6.**← NEXT:** Request **Community Management API FIRST**: add product → complete access form (legal name Stargue Inc., Curaçao address, website, privacy URL, business email `info@stargue.com`) → Dev Tier → apply Standard Tier later (screencast).
- Marketing Developer Platform (separate partner-access request — fill in use-case: "Automate posting and engagement-metric collection for owned content from a self-hosted publishing pipeline") 7. ☐ THEN request **Sign In + Share on LinkedIn** (instant).
4. Under **Auth**, add redirect URIs above. 8. **Auth tab:** add redirect URIs above.
5. Copy Client ID and Client Secret to Dokploy secrets (never commit). 9. Copy **Client Secret** Dokploy secret `LINKEDIN_CLIENT_SECRET` (never commit).
6. Update this file with the app ID. 10. ☐ Keep this file current with app IDs + states.
7. Re-request Community Management API + MDP if denied initially, with more detailed use-case.
## References ## References
- [LinkedIn Developer Portal](https://www.linkedin.com/developers/) - [LinkedIn Developer Portal](https://www.linkedin.com/developers/)
- [Community Management — Overview + FAQ (Microsoft Learn)](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/community-management-overview)
- [Organizations & Brands Overview (Microsoft Learn)](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/organizations)
- [Increasing Access — tiers & app review](https://learn.microsoft.com/en-us/linkedin/marketing/increasing-access)
- [Quick Start — Apply for API Access](https://learn.microsoft.com/en-us/linkedin/marketing/quick-start)
- [Posts API](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/posts-api) - [Posts API](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/posts-api)
- [3-Legged OAuth Flow](https://learn.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow)
- [Programmatic Refresh Tokens](https://learn.microsoft.com/en-us/linkedin/shared/authentication/programmatic-refresh-tokens) - [Programmatic Refresh Tokens](https://learn.microsoft.com/en-us/linkedin/shared/authentication/programmatic-refresh-tokens)
- [Community Management API overview](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/)