Skip to content

feat(docs): community Q&A widget on every page — MERGE AFTER api#262 DEPLOYS - #13

Draft
CosmoBlk wants to merge 2 commits into
mainfrom
feature/community-qa
Draft

feat(docs): community Q&A widget on every page — MERGE AFTER api#262 DEPLOYS#13
CosmoBlk wants to merge 2 commits into
mainfrom
feature/community-qa

Conversation

@CosmoBlk

Copy link
Copy Markdown
Member

⚠️ DO NOT MERGE until nitrosend/api#262 is deployed and verified

GET https://api.nitrosend.com/v1/public/questions?page_key=/quickstart must return 200 {"questions":[]} live BEFORE this merges. Cloudflare negative-caches 404s for a year — a docs deploy ahead of the API route poisons the cache. Rollback is docs-first for the same reason.

Summary

  • Post-build injector (scripts/inject-qa.js) appends a self-contained Q&A widget before </body> on every built page — the only repo-controlled every-page injection point Sourcey allows (templates live in node_modules)
  • Widget: vanilla JS, textContent-only rendering (XSS-hardened with hostile fixtures), .dark-aware, page_key from pathname, quiet empty state, "Ask a question" deep-links to app.nitrosend.com/my/learn?ask=1&page_key=…, any failure removes only the widget
  • verify-qa-injection.mjs gates the build: every generated HTML file must carry exactly one marker (54/54 today)
  • vercel.json buildCommand chains build → inject → verify

Test plan

17 node-stdlib tests (idempotency, marker guard, empty-dist failure, hand-rolled DOM stub proving <img onerror>, split-</script>, <svg onload> render as text) + full real build verified twice (idempotent re-run: 0 injected, 54 skipped).

Reviews

  • scafld cross-model review: Codex (GPT-5.6) — PASS (docs surface clean across all 4 rounds; XSS + failure isolation adversarially verified).

Built with /dev pipeline: scafld spec → codex plan review → harden → TDD → codex adversarial gate

CosmoBlk added 2 commits July 22, 2026 16:08
Post-build injector (the only repo-controlled every-page injection point —
Sourcey templates live in node_modules): inject-qa.js appends a marker-
idempotent, self-contained vanilla-JS widget before </body> on every dist
HTML file and fails loudly on a missing or empty dist. The widget reads
the normalized pathname as page_key (matrix mirrors the API: decode once,
lowercase, collapse slashes, strip trailing slash and .html, / ->
/introduction), fetches GET /v1/public/questions, renders in the docs
theme (.dark-aware), URL-encodes the Ask deep link into the app, and
removes only its own container on any fetch/render failure. Every
user/LLM-originated string is inserted via createTextNode only — no
innerHTML or attribute sinks (the DOM test's innerHTML setter throws).

verify-qa-injection.mjs gates the Vercel build: every generated HTML file
must carry exactly one marker (zero and 2+ both fail), with an explicit
allowlist for any future </body>-less files. inject-qa.test.mjs covers
the injector, the verifier, and the widget XSS/normalization contract
with node stdlib only.

MERGE NOTE (binding release order): deploy only after the api release is
verified live returning 200-empty on GET /v1/public/questions —
Cloudflare negative-caches 404s for a year.
The community-qa contract's deep link is
https://app.nitrosend.com/my/learn?ask=1&page_key=<encoded> (LC route
name my-learn) — /learning/community/ask does not exist and is not
planned. Tests now pin the full href.
@CosmoBlk
CosmoBlk requested a review from auscaster July 22, 2026 08:24
@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nitrosend-docs Ready Ready Preview, Comment Jul 22, 2026 8:24am

Request Review

@CosmoBlk
CosmoBlk marked this pull request as draft July 22, 2026 11:17
@CosmoBlk

Copy link
Copy Markdown
Member Author

⏸️ Hold — not ready for review yet. George wants to test this on staging first. Converting to draft; will mark ready + re-ping once staging QA clears. (Applies to the whole batch: api#261, app#149, api#262, docs#13, app#150.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant