logicspike/docs

Engagement

Engagement — Backlog

Last Updated: 2026-09-05 · Status: Active

What's built is in implementation-plan.md. This is what isn't.

Deploy-time work owed

These are not code changes — they're steps someone has to take before the built code does anything.

# What Why it's blocking
D1 wrangler.toml is gitignored repo-wide (9 workers). Engagement's COLLECTIONS_SERVICE and SITE_SYNC bindings, and collections' secret documentation, are local-only. The bindings must be re-applied on whatever machine deploys.
D2 Set ENGAGEMENT_INTERNAL_TOKEN on collections-service to engagement's existing value. entry: targets fail open (accepted but unverified) until this exists.
D3 Set SITE_SYNC_INTERNAL_TOKEN and PLATFORM_ADMIN_TOKEN on engagement; PLATFORM_ADMIN_TOKEN + an ENGAGEMENT_SERVICE binding on internal-api. Done (2026-09-09) — all four secrets/bindings confirmed present. What's still outstanding is the deploy: internal-api's own wrangler.toml already has the binding committed, but internal-api hasn't been redeployed since, so it isn't live yet. Site-sync integration and the blocklist are code-complete but not live until that redeploy ships.
D4 Set CF_ACCOUNT_ID (done) and CF_AE_TOKEN (Account Analytics:Read — still unset as of 2026-09-09). The Sources panel shows "not available"; everything else works.
D5 Apply migrations 0004 (eng_members) and 0005 (eng_platform_blocklist). Done (2026-09-09) — confirmed live against the prod DB.
D6 Merge the changesets "Version Packages" PR to publish @vlozi/blog@2.2.0, then bump apps/website and set a real NEXT_PUBLIC_ENGAGE_SITE_ID. vlozi.app can't dogfood until then.
D7 Users must re-login for Engagement to appear in their sidebar. JWTs carry the service list.

Known gaps

No edge cache in front of /e/*. The plan's Phase 1 called for cachedPublicProxy (B12/B35) with per-route TTLs at the gateway. It was never built; engagement.proxy.ts is a plain forward. The worker's Cache-Control headers are honoured by browsers only, so every distinct visitor's page load hits the worker for /summary. Fine at current scale; the first thing to build when it isn't. (Found by the final audit — the docs had claimed edge caching that didn't exist; corrected.)

Comment IPs are stored raw, not hashed. eng_comments.source_ip is the actual address, because a tenant's ban-by-IP and the platform blocklist's ip_hash kind both compare against it verbatim (the kind's name is a misnomer). Hashing would need every comparison point to hash too. The 30-day purge (/cron/purge-comment-ips) now exists and bounds the exposure; hashing is a follow-up decision. The purge cron needs scheduling alongside send-digests and weekly-summary — same 5-cron blocker.

Digest and weekly-summary crons need scheduling. /cron/send-digests and /cron/weekly-summary exist and are tested, but nothing calls them on a schedule yet. Cloudflare's 5-cron account limit is already reached (see the flows-service memory note), so this needs either a slot freed or billing-crons' DO to fan them out.

Load test has never been run. scripts/load-test.mjs is written and refuses to run against production. The 10k-beacons/minute claim is untested against a real deployment, and the batching half of it can only be confirmed from worker logs afterwards.

entry: targets have no dashboard drawer detail. The Content table filters by type and shows entries, but the drawer's series view was built around posts. Entries render, they just don't get the same context.

Deliberately not doing

Why
Hosted blog Dropped 2026-09-04; site-sync covers publish-to-live.
Reader profiles / follows / a social graph A member exists to prove control of an email address. Every field beyond that is one we'd have to protect, export and delete.
Nested replies beyond one level Deep threads need collapse UI, "load more", and moderation of subtrees. One level covers the actual use case (an owner answering a reader).
Rating markup on articles Self-serving review markup. productRatingJsonLd exists for the Product case that isn't.
DO sharding on by default Splits the dedup set, so uniques inflate. Implemented and off — see lib/counter-shard.ts.
Reactions in the DO They need read-before-write and immediate visibility. Batching them would buy nothing and cost correctness.

Follow-ups from the platform audit (Phase 14)

Tracked in the implementation plan §2 bug table. Not engagement bugs — things engagement's audit surfaced elsewhere:

  • B2 forms' lenient origin check on writes (engagement uses strict from day one; forms should adopt it)
  • B7 the two seed files disagree on service names, limits and addons
  • B8 rebuildEntitlements skips services with no plan-limit rows — collections and flows were never backfilled
  • B15 the enabled && !userDisabled rule exists in three helpers and five inline copies
  • B16 chat-engine still emits the legacy widget.logicspike.com host
  • B19 four pairs of wrangler [dev] port collisions
  • B26 forms' .dev.vars lacks CORE_DATABASE_URL, so local dev runs unbilled silently
  • B27 a hardcoded content-engine → content breadcrumb special case
  • B28 blog-sdk's README hardcodes sizes and test counts that drift
  • B29 competitive-audit.md is an empty checklist
  • B31 ?api_key= in query strings lands in logs; redact it at the gateway
Engagement