- 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>
12 KiB
Executable File
created, updated, tags
| created | updated | tags |
|---|---|---|
| 2026-05-13T12:35 | 2026-05-13T12:35 |
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 (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:
- Run
0000_initial_schema.sqlmigration on the new DB - Run
bun run db:migrate:rehearse(script lives atpackages/schema/db/migrations/rehearse.ts) - Wire connection strings into Dokploy secrets
DATABASE_URL,REDIS_URL - 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.1–3.7 live posting, Stage 4 end-to-end publish, Stage 7.4 first scheduled post.
Next steps when resolved:
- Angelo registers app at linkedin.com/developers/ linked to Stargue Company Page
urn:li:organization:2605890 - Enables Sign-In with OpenID Connect + Share on LinkedIn (instant self-service)
- Submits Community Management API + MDP partner-access requests (multi-week review — file ASAP to start the clock)
- Drops
LINKEDIN_CLIENT_ID,LINKEDIN_CLIENT_SECRET,LINKEDIN_TOKEN_ENCRYPTION_KEYinto Dokploy secrets - Update
docs/linkedin-apps.mdregistry 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 (withidempotency_key UNIQUE), approvals, metrics, linkedin_tokens, audit, outlet_feature_flagsrate-limit.ts— token-bucket implementation, pure-functioncsrf.ts— double-submit cookie patternauthz.ts— Cerbos-equivalent policy primitivesapi-contracts.ts— Zod request/response schemas for admin APIdrizzle.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_LIMITSerrors.ts— SanitizeError with codes: PRIVATE_PATH_BLOCKED, PRIVATE_TAG_BLOCKED, WIKILINK_TO_PRIVATE_PATH, OUTLET_LENGTH_EXCEEDEDindex.ts—sanitize(markdown, opts)returns{ body, contentHash, warnings }— strips wikilinks/embeds/dataview/callouts, enforces blocklist + tag firewall + length, computes SHA-256 hashcorpus.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; respectsLinkedIn-Version: 202404+X-Restli-Protocol-Version: 2.0.0token-store.ts— encrypted persistence; uses AES-256-GCM vianode:crypto(NOT libsodium — see D-001 indocs/deferred-gates.mdfor 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—createServerfactory pattern, injectable deps (KillSwitch, AdvisoryLock); MCP_SPEC_VERSION pinned2024-11-05;validateToolCall,listTools,outletForAuthorUrnhelperstools.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_statsoauth.ts— auth-code URL builder + HMAC-protected state parameter (no PKCE — LinkedIn 3LO doesn't support it)kill-switch.ts—outlet_feature_flagsreader with cache invalidationrefresh-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 functionpending→queued→dispatching→published, retry-vs-DLQ branch, cancellation pathworker.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
- D-001 token cipher: AES-256-GCM, not libsodium secretbox. Bun ESM bug in
libsodium-wrappers. Same AEAD security profile. Documented indocs/deferred-gates.md. Remediation path noted if libsodium fixes the bug. - Scheduler imports
linkedin-clientdirectly — MCP transport is stdio-only for interactive Claude Code use. No HTTP MCP transport in Phase 1 (architect gap 2). apps/apicollapsed intoapps/admin— Next.js App Router route handlers cover the API surface; less infra (architect gap 1).- LinkedIn Posts API
/rest/posts— NOT the legacy/v2/ugcPosts. Headers:LinkedIn-Version: 202404,X-Restli-Protocol-Version: 2.0.0. - No PKCE in OAuth — LinkedIn 3LO doesn't document it; confidential-client with HMAC
stateparameter is what we use. idempotency_key UNIQUEonpublications— sha256(content_id || outlet || scheduled_at). Prevents double-post on retry.- Kill-switch via
outlet_feature_flagstable — 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)
- Gate 0.8 — Dokploy MCP query → provision Postgres + Redis in
stargue-publishing-engineproject onsg-paas-s1.stargue.net - 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)
- With both gates open, unblock Stages 2.6, 3.4–3.9, 4.1–4.3 live integration tests
- Move to Stage 5 (admin dashboard)
Path B: Continue parallel work (if gates remain blocked)
- 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. - Stage 6 — Add
@stargue/sanitize+@stargue/schemaas workspace deps to stargue-com + stargue-net; replace ad-hoc frontmatter parsing; assert zero wikilinks in rendered HTML. - Stage 7.1 — Run
/market auditbaseline on stargue.com + stargue.net; save todocs/marketing-baseline-2026-05.json. - Stage 7.2 — Draft 7 Cs posts 2–8 (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
- MDP + Community Management API timeline — once filed, track approval state weekly. MDP rejection is the trigger for the 60-day-re-auth fallback.
- Authentik instance reachability — plan §8 q3 said "shared instance for all Stargue services"; needs runtime verification before Stage 5.2.
- Neon free-tier mirror — Stage 7.5 DR test pending. Set up nightly
pg_dump → Neoncron when gate 0.8 resolved. - stargue-com/.net package.json sync — collision was fixed (commit
fd43214on stargue-net) — verify both repos still align before Stage 6. - 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:
- This handoff
docs/plans/2026-04-19-phase1-plan.md(in the repo) — full plan v2docs/deferred-gates.md— for D-001 + gate statusCLAUDE.mdin the repo — for governance + canonical LinkedIn facts- Last 4 commits via
git log— for exact stage progress 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
# 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