Phase 1 foundation for the Stargue Publishing Engine (plan v2, BMAD
panel-reviewed 2026-04-19 — 1 APPROVE, 6 REVISE, 0 REJECT; all principles >=3).
- Governance doctrine adopted from DQMS
(.clinerules/12-foundational-principles.md,
.claude/hooks/gate-plan-exit.sh, .claude/skills/bmad-plan/SKILL.md)
- Bun workspaces + Turbo; apps/{mcp-linkedin,scheduler,admin};
packages/{schema,sanitize,linkedin-client,observability}
- Drizzle schema (content, publications, approvals, metrics,
linkedin_tokens, audit, outlet_feature_flags) with idempotency_key
UNIQUE and kill-switch table per TEA/dev panel revisions
- LinkedIn API canon: Posts API /rest/posts (not legacy UGC); OAuth
auth-code without PKCE; secretbox (not sealed-box); Community
Management API as separate approval gate from MDP
- Frontmatter Zod schema (status, language, outlets[], sanitize,
scheduled, version)
- Pino observability with PII redaction
- Expand-then-contract migration runbook
- Plan + panel verdicts mirrored to docs/plans/
- Deferred gates logged (Dokploy PaaS verification, LinkedIn Dev
Portal app registration)
bun install + bun run typecheck both exit 0 across 11 workspaces.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6.7 KiB
CLAUDE.md — Stargue Publishing Engine
Project-level context for Claude Code. Loaded every turn.
Purpose
Automated two-channel Publishing Engine: Obsidian vault → stargue.com/.net + LinkedIn (personal profile + Stargue Company Page) via a Stargue-owned LinkedIn MCP server. Phase 1 scope is tracked in docs/plans/2026-04-19-phase1-plan.md (mirrored from the vault SSoT at Stargue/Projects/Publishing Engine/Plan - Phase 1 Automated Publishing Engine.md).
Source-of-Truth Precedence
- Vault (
c:\Users\aluid\OneDrive\Documents\Obsidian\Angelo'sSBO\) — content notes, design philosophy (Nine Laws of the Hearth), outlet profiles, PRDs, plans. SSoT for intent. - This repo (
/home/devuser/projects/stargue-publishing-engine/) — code implementation. SSoT for behavior. - stargue-com + stargue-net (
/home/devuser/projects/stargue-{com,net}/) — Next.js static sites that consumepackages/sanitize+packages/schemaas workspace dependencies for build-time content transformation. - Production state (Dokploy on sg-paas-s1.stargue.net, Postgres, Redis, LinkedIn) — SSoT for runtime. Never assume; always verify via Dokploy MCP, DB query, or LinkedIn
whoami.
Governance
- Foundational principles (Tier-1 always + declared Tier-2):
.clinerules/12-foundational-principles.md— adopted 2026-04-19 from DQMS (ref:/home/devuser/projects/dqms/.clinerules/12-foundational-principles.md). DQMS is the evolving SSoT for Stargue's BMAD application; this file is a dated snapshot. - Plan-review gate (7-agent BMAD panel): enforced by
.claude/hooks/gate-plan-exit.shonExitPlanMode. Runs the verdicts validator against/tmp/bmad-panel-verdicts-${CLAUDE_SESSION_ID}.json. - Panel charters (roles for analyst, architect, pm, sm, ux-designer, dev, tea): referenced by path from DQMS at
/home/devuser/projects/dqms/_bmad/bmm/agents/*.md. No local install in Phase 1 (per user directive 2026-04-19). - Tier-2 applicability: every plan declares
applicable_tier2 = [RBR | A11y | Testability]. See.clinerules/12-foundational-principles.md > Tier-2 Principles.
Architecture
Monorepo (Bun workspaces + Turbo):
apps/mcp-linkedin/ MCP server (stdio transport) for Claude Code to drive LinkedIn operations
apps/scheduler/ BullMQ worker — imports packages/linkedin-client directly; no HTTP to MCP
apps/admin/ Next.js App Router — UI + /api/* route handlers
packages/sanitize/ remark plugin + blocklist + length validation + test corpus
packages/schema/ Zod schemas, Drizzle DB schema, frontmatter parser (SSoT for data shapes)
packages/linkedin-client/ LinkedIn Posts API client + encrypted token store
packages/observability/ Pino + OTel + correlation IDs
Scheduler imports packages/linkedin-client directly — MCP is not on the scheduler's hot path. MCP exists so Claude Code can invoke LinkedIn operations interactively (posting, metrics queries, auth status). HTTP MCP transport is deliberately deferred.
LinkedIn — canonical facts (verified 2026-04-19)
- API: Posts API
https://api.linkedin.com/rest/posts(the UGC Posts API is legacy — do not use). Required headers:LinkedIn-Version: 202404(YYYYMM, update on cadence),X-Restli-Protocol-Version: 2.0.0,Authorization: Bearer <token>. - Auth: OAuth 2.0 Authorization Code flow. PKCE is NOT supported by LinkedIn 3LO per
https://learn.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow. Use confidential-client withclient_secret+ CSRF-protectedstate. - Products in Dev Portal (each separately enabled/approved):
Sign In with LinkedIn using OpenID Connect→ scopesopenid profile emailShare on LinkedIn→w_member_social(personal-profile posts)Community Management API→w_organization_social,r_organization_social(organization posts — requires LinkedIn partner approval)Marketing Developer Platform (MDP)→ programmatic refresh tokens (requires LinkedIn partner approval; without it, access tokens expire in 60 days with no refresh — re-auth required)
- Stargue Company Page URN:
urn:li:organization:2605890 - Primary identity: Angelo personal profile (
angeloluidens), resolved at OAuth time tourn:li:person:<id> - Token encryption:
libsodium crypto_secretbox(symmetric XSalsa20-Poly1305) — not sealed-box. Key stored in Dokploy secrets.
Commands
bun install # install workspace deps
bun run typecheck # workspace-wide tsc --noEmit
bun run lint # workspace-wide lint
bun run test # workspace-wide vitest
bun run build # turbo build
bun run dev # turbo dev (admin, scheduler, mcp-linkedin)
# Migration commands
bun run db:migrate # drizzle-kit migrate
bun run db:migrate:rehearse # expand-then-contract rehearsal on staging
# MCP invocation (stdio)
docker exec -i mcp-linkedin node apps/mcp-linkedin/dist/server.js
Deployment
Dokploy stack stargue-publishing-engine on sg-paas-s1.stargue.net:
admin— Next.js standalone, Traefik atpublishing.stargue.net, Authentik SSOscheduler— BullMQ workermcp-linkedin— stdio-only; started on demand by Claude Code viadocker execpostgres+redis— shared PaaS cluster
DR: nightly pg_dump to Neon free tier. RPO ~24h.
Rules
- Additive by default — never delete production data or published content without explicit user confirmation.
- No PII in logs — content body is hashed, not logged; tokens never printed.
- Every publish is approval-gated — no auto-publish without a row in
approvalsfor the (content_id, outlet) pair. - Kill-switch respected — every dispatch checks
outlet_feature_flagsbefore making LinkedIn calls. - Idempotency enforced — every LinkedIn API call carries an idempotency key derived from (content_id, outlet, scheduled_at).
- Expand-then-contract migrations — every schema change has a rollback runbook in
db/migrations/README.md. - All operations in WSL Debian — per vault-level rule.
wsl -d Debian -- bash -c '…'for any shell invocation from Windows.
Related (vault paths)
Stargue/Projects/Publishing Engine/Plan - Phase 1 Automated Publishing Engine.md— current plan (SSoT)Stargue/Projects/Publishing Engine/Publishing Engine PRD.md— PRD v2.2Stargue/Projects/Publishing Engine/Design Philosophy - The Nine Laws of the Hearth.md— visual + interaction SSoTStargue/Projects/Publishing Engine/Outlet Profiles/LinkedIn.md— outlet specsStargue/Projects/Publishing Engine/7 Cs LinkedIn Series - Continuation Plan.md— first content programStargue/Projects/Publishing Engine/Implementation Progress.md— running state