NowPage Issue Tracker

Deep Infrastructure Review — Feb 20, 2026 — 17 files reviewed, 57 tests run
4
CRITICAL
6
HIGH
7
MEDIUM
57/57
TESTS PASS

Critical Issues — Fix Before Next Deploy

C1 Permissive auth defaults — empty scopes grant full access
lib/auth/api-key.ts:61,68
Impact: hasAccessToDomain() returns true if domain_ids is empty. hasPermission() returns true if permissions is empty. Any API key with empty scopes effectively has god-mode access to all domains and all operations. May be intentional (convenience) but is a security risk if keys are leaked.
C2 JSON parse failure returns wrong regex match group
lib/publish/core.ts:~325
Impact: In updateRegistryMetadata(), the catch block returns _ (the captured group) instead of fullMatch. When hc-metadata JSON is malformed, this silently corrupts the registry HTML by replacing the entire script tag with just its content, stripping the wrapping tags.
C3 Null domain crashes registry update endpoint
app/api/hc/update-registry/route.ts:~61
Impact: No null check on registryPage.domain before accessing .user_id. If the domain relation is null (orphaned page), the endpoint throws a 500 error instead of a meaningful response.
C4 URL used in regex without escaping
app/api/hc/update-registry/route.ts:~933
Impact: Page URLs containing regex special characters (., ?, +, *) will break the regex pattern used to find and update existing registry entries. Since most URLs contain ., this is a latent bug that could cause duplicate entries or failed updates for certain URL patterns.

High Priority Issues — Fix Soon

H1 Stat counter regex requires exact CSS class order
lib/publish/core.ts:99-100
Impact: Regex /class="blocker-item urgent"/g won't match if class order is reversed ("urgent blocker-item"), has extra whitespace, or uses single quotes. Stat counters could show incorrect numbers on registry dashboards.
H2 Concurrent publishes can lose version history
lib/publish/core.ts:490-505
Impact: Two simultaneous publishes of the same page both read the same version number, increment to the same value, and both try to insert. Second insert fails silently. No data loss on the page itself (last write wins) but version history has a gap.
H3 Domain lookup uses .single() — throws on 0 or 2+ rows
app/api/publish/route.ts:49
Impact: If domain not found, .single() throws a Supabase 406 error that isn't caught, returning a confusing 500 to the caller. Should use .maybeSingle() and handle null explicitly.
H4 Tag retry loop has no max iteration guard
scripts/hc-publish.js:~446
Impact: If tag creation consistently fails (e.g., DB connection issue), the retry loop runs indefinitely. Could hang the publish process or consume resources. Add a max retry count (3-5 attempts).
H5 Day streak calculation breaks at year boundary
app/api/hc/update-registry/route.ts:732-748
Impact: EOD registry day streak computation assumes all reports are in the same year. Dec 31 → Jan 1 transition breaks the streak even if reporting was consecutive. Only affects the aggregate_metrics display.
H6 Domain access check short-circuits on not-found
app/api/publish/route.ts:51
Impact: The check domainData && !hasAccessToDomain(...) evaluates to false if domain is not found (domainData is null), so execution continues instead of returning 404. The publish then fails later with a more confusing error from publishPage().

Medium Priority Issues

M1 Dashboard injection: blockers OR actions, not both
lib/publish/core.ts:~158
If a meeting has both blockers and actions, only blockers are injected into the registry dashboard. Action items are skipped when blockers exist. Intentional but limits visibility.
M2 Blocker/action dedup only in HTML, not hc-metadata
lib/publish/core.ts:353-376
The <!-- src:slug --> dedup markers only work in the visual HTML. Re-publishing the same page appends duplicate entries to the hc-metadata JSON arrays. Affects AI consumers reading structured metadata.
M3 Registry fallback may register in wrong registry type
lib/publish/core.ts:564-587
If detectRegistryType returns 'eod' but no matching registry is found, it falls back to the first available registry — which could be a meeting registry. Cross-type contamination is possible.
M4 .env.local parser breaks on values containing = or quotes
scripts/hc-publish.js:~43
match[2].trim() only captures text after the first =. Values like URL=https://x.com?a=b lose everything after the second =.
M5 No SSRF protection on webhook URLs
lib/webhooks/fire.ts:58
Webhook URLs are fetched without validation. A malicious user could set a webhook URL to http://localhost:5432 or internal IPs, potentially probing internal services. Low risk for single-user deployments.
M6 Tag splitting can produce empty strings
app/api/publish/route.ts:64
"a,,b".split(',').map(t => t.trim()) produces ["a", "", "b"]. The empty string gets created as a tag with name "". Should filter with .filter(Boolean).
M7 null expires_at treated as expired via Date(null)
lib/auth/api-key.ts:41
new Date(null) creates epoch date (1970), which is always less than new Date(). Keys with null expiry could be wrongly rejected. Currently mitigated by the outer null check but fragile if refactored.

Registry Versioning — Verdict

The uncommitted changes (now committed as ca2d846) add version snapshots at all 3 registry mutation paths:

FileWhat it doesStatus
lib/publish/core.tsSaves registry HTML before publish injectionCORRECT
update-registry/route.tsSaves registry + meta-registry HTML before API updateCORRECT
scripts/hc-publish.jsSaves registry HTML before CLI injectionCORRECT

Verified Working (57 automated tests)

API Tests (31/31 pass)

MCP Tests (26/26 pass)

Not Yet Tested (Needs Session Auth / Manual)

Feature Requests (New)

F1 GUI Page Builder HIGH
Impact: One-click page creation flow replacing CLI workflow. Select domain → pick template → drag content → select registry → publish → opens live page.
F2 Notification System HIGH
Impact: Get notified when pages are published. Configurable per-build or saved as defaults.
F3 Template Organization Schema MEDIUM
Impact: Templates currently flat in templates/ folder. Need structured organization.
F4 Folder Cleanup & Organization MEDIUM
Impact: Published pages stored in flat structure. Need organized folders sorted by neural registry.

Future Roadmap (API/Architecture Required)

High-level items requiring design and API work. Details TBD.

F5 OAuth / Auth Gate for Embedded Agents HIGH
Impact: Embedded chat agents (registry bots) currently use name-based passwords. Need real OAuth so we can control who accesses bots, revoke access, and audit usage. Required before any public-facing registry with an embedded agent.
F6 BYOK (Bring Your Own Key) MEDIUM
Impact: Allow external users to use their own Anthropic/OpenAI API keys for agent queries instead of consuming our quota. Enables self-service scaling without cost risk.
F7 Registry Auth & Public/Private Split HIGH
Impact: Registry pages are fully public. Need to split into public-facing summary and authenticated full-access view. Links can download content or reach embedded bots — must control who gets access.
F8 Bot/Robot Access Control (Allowlist) HIGH
Impact: Automated agents (Forge VPS, crawlers) can access page content and APIs. Need an allowlist so Forge works but random bots/scrapers are blocked. Prevents unauthorized data extraction.
F9 Notification Routing & Recipient Management MEDIUM
Impact: Extends F2 (Notification System). Define who gets notified for which registries, templates, and events. Connects to file organization (F4) and template schema (F3).
F10 Forge VPS LLM Proxy (Local Ollama via Tunnel) MEDIUM
Impact: Enables the registry chat agent to use a self-hosted LLM instead of paid API calls. Unblocks the "local" model toggle that currently fails on Vercel (localhost:11434 unreachable in serverless).
Effort: ~2 hours infra + 1 hour testing  |  Depends on: VPS access, Ollama install
F11 Chat-to-Publish: Create & Publish HC Pages from Embedded Agent HIGH
Impact: Transforms the registry chat agent from read-only intelligence into a full authoring tool. Users can instruct the agent to draft, preview, and publish new HC pages directly from the chat widget — no CLI, no code editor needed. This is the natural next step after F10 (LLM proxy) and closes the loop on the agent being a complete registry operator.
Effort: ~6-8 hours (agent tool + preview UI + metadata schema + tab)  |  Depends on: Existing publish API (ready), registry-agent tool loop (ready), auth (ready)  |  Phases: P1 = create_page tool + preview gate (3h), P2 = created_by field + My Pages tab (2h), P3 = edit + template selection (2h)

Related Resources

ResourceURL
API Manualideas.asapai.net/nowpage-api-manual
Meta Registryideas.asapai.net/meta-registry
Test Scriptsscripts/test-publish-api.js, scripts/test-mcp.py, scripts/test-api.sh
Cleanup Toolscripts/cleanup-test-pages.js
Commitca2d846 — rollback with git revert ca2d846