Files
stargue-publishing-engine/docs/deferred-gates.md
T
Angelo B. J. Luidens c24ea815f3 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>
2026-06-03 15:31:02 -04:00

5.7 KiB
Raw Blame History

Deferred gates

Items that could not be completed in the Stage 0 execution window and must be resolved before the gate they block.

Gate 0.8 — Postgres + Redis on PaaS

Status: RESOLVED 2026-06-03 (via Dokploy MCP, resolution option 3 — clean-room stack). 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 (now cleared): Stage 2 (database + API) — the scheduler and admin cannot run without a Postgres + Redis pair.

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

Status: Pending Angelo's manual action. Reason: Dev Portal registration cannot be automated — requires human auth at linkedin.com/developers/. Blocks: Stage 3.1 (OAuth flow) live integration — structure + contract tests can proceed in parallel. Resolution: follow the checklist in linkedin-apps.md. Expected time ~30 min for OIDC + Share; multi-week for Community Management API + MDP partner approvals. Acceptance when resolved: linkedin-apps.md registry filled in with app IDs; client credentials stored in Dokploy secrets LINKEDIN_CLIENT_ID, LINKEDIN_CLIENT_SECRET, LINKEDIN_TOKEN_ENCRYPTION_KEY.

What proceeds in parallel

Stages 12 (local DB), 3 structural (OAuth code + tool shapes + msw fixtures), 4 (scheduler), 5 (admin UI with Authentik stub), 6 (sanitize integration in stargue-com/.net), 7.1 (/market audit baseline), 7.2 (7 Cs post drafting) can all proceed without these gates. Live integration tests and first production publish require both gates resolved.


D-001 — Token store cipher: AES-256-GCM instead of XSalsa20-Poly1305

Plan §3.2 specified: libsodium crypto_secretbox (XSalsa20-Poly1305), per architect gap 3.

Implemented (2026-04-26): Node stdlib aes-256-gcm via node:crypto. Same AEAD security profile (256-bit key, 96-bit nonce, 128-bit auth tag), zero external dependencies.

Reason: libsodium-wrappers and libsodium-wrappers-sumo (v0.7.16) both have a known ESM resolution bug under Bun where the loader fails to find ./libsodium.mjs / ./libsodium-sumo.mjs from within their own dist folder. Reproduced cleanly on Bun 1.3.11. AES-256-GCM is the recommended AEAD when libsodium isn't available — same security guarantees, FIPS-compliant, in stdlib of every JavaScript runtime (Node, Bun, Deno, Cloudflare Workers).

Security review:

  • AEAD: (authenticity + confidentiality)
  • Key length: 256 bits (same as XSalsa20-Poly1305)
  • Nonce length: 96 bits (sufficient for random nonces; collision probability < 2^-32 after 2^32 messages — well within Phase 1 envelope of <100k tokens lifetime)
  • Tag length: 128 bits (same as XSalsa20-Poly1305)
  • Implementation: Node stdlib (audited, FIPS 140-2 validated under common builds)

Remediation path: When libsodium-wrappers ships a Bun-compatible ESM build, migrate by: (1) restore dep, (2) re-implement encrypt/decrypt with crypto_secretbox_easy, (3) one-time decrypt-and-re-encrypt migration on linkedin_tokens.*_ct rows, (4) drop AES-GCM code path.

Risk: Low. Both ciphers offer equivalent security for this use case (encrypting OAuth tokens at rest in Postgres). The deviation is purely about the cipher primitive, not the threat model or key management.

Status: Accepted. 4/4 token-store round-trip tests pass. Production-ready.