Files
stargue-publishing-engine/CLAUDE.md
Angelo B. J. Luidens 1dc1a1a07a Stage 0: governance scaffolding + monorepo bootstrap
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>
2026-04-19 07:22:07 -04:00

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

  1. 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.
  2. This repo (/home/devuser/projects/stargue-publishing-engine/) — code implementation. SSoT for behavior.
  3. stargue-com + stargue-net (/home/devuser/projects/stargue-{com,net}/) — Next.js static sites that consume packages/sanitize + packages/schema as workspace dependencies for build-time content transformation.
  4. 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.sh on ExitPlanMode. 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 with client_secret + CSRF-protected state.
  • Products in Dev Portal (each separately enabled/approved):
    • Sign In with LinkedIn using OpenID Connect → scopes openid profile email
    • Share on LinkedInw_member_social (personal-profile posts)
    • Community Management APIw_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 to urn: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 at publishing.stargue.net, Authentik SSO
  • scheduler — BullMQ worker
  • mcp-linkedin — stdio-only; started on demand by Claude Code via docker exec
  • postgres + 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 approvals for the (content_id, outlet) pair.
  • Kill-switch respected — every dispatch checks outlet_feature_flags before 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.
  • Stargue/Projects/Publishing Engine/Plan - Phase 1 Automated Publishing Engine.md — current plan (SSoT)
  • Stargue/Projects/Publishing Engine/Publishing Engine PRD.md — PRD v2.2
  • Stargue/Projects/Publishing Engine/Design Philosophy - The Nine Laws of the Hearth.md — visual + interaction SSoT
  • Stargue/Projects/Publishing Engine/Outlet Profiles/LinkedIn.md — outlet specs
  • Stargue/Projects/Publishing Engine/7 Cs LinkedIn Series - Continuation Plan.md — first content program
  • Stargue/Projects/Publishing Engine/Implementation Progress.md — running state