NowPage Issue Tracker
Deep Infrastructure Review — Feb 20, 2026 — 17 files reviewed, 57 tests run
Critical Issues — Fix Before Next Deploy
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.
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.
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.
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
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.
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.
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.
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).
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.
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
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.
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.
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.
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 =.
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.
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).
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:
| File | What it does | Status |
lib/publish/core.ts | Saves registry HTML before publish injection | CORRECT |
update-registry/route.ts | Saves registry + meta-registry HTML before API update | CORRECT |
scripts/hc-publish.js | Saves registry HTML before CLI injection | CORRECT |
Verified Working (57 automated tests)
API Tests (31/31 pass)
- ✓ List domains via API key
- ✓ List templates (public, no auth)
- ✓ Publish new page
- ✓ Page live immediately (200)
- ✓ ?format=raw returns source
- ✓ ?format=hc returns HC text
- ✓ Update page (version mode)
- ✓ Updated content goes live
- ✓ update_mode=fail rejects dupes
- ✓ No auth → 401
- ✓ Bad key → 401
- ✓ Missing fields → 400
- ✓ Short HTML → 400
- ✓ String tags accepted
- ✓ Array tags accepted
- ✓ Folder auto-creation
- ✓ Session-only endpoints reject API keys
MCP Tests (26/26 pass)
- ✓ list_domains returns domains
- ✓ list_templates returns 8 templates
- ✓ publish_page creates new page
- ✓ publish_page updates existing
- ✓ get_page_html fetches source
- ✓ Folder publish works
- ✓ Auto-slug from title
- ✓ Bad domain returns error
- ✓ Empty HTML returns error
- ✓ 404 page returns error
- ✓ Meeting tag auto-registry
Not Yet Tested (Needs Session Auth / Manual)
- ☐ Webhook create/update/delete (session auth only)
- ☐ Webhook HMAC signature verification
- ☐ Page CRUD via dashboard API
- ☐ Registry update/remove via API
- ☐ HC analyze endpoint (Claude-powered)
- ☐ DNS verification flow
- ☐ FTP publishing (Hostinger/AWS)
- ☐ Asset upload/management
- ☐ Page version restore
- ☐ Admin endpoints
Feature Requests (New)
Impact: One-click page creation flow replacing CLI workflow. Select domain → pick template → drag content → select registry → publish → opens live page.
-
✓
Template Selector — Dropdown of saved templates from
templates/ folder, or upload custom HTML, or point to local folder path
-
✓
Design Standards Library — Saved CSS/design-standard files (fonts, colors, spacing) that can be applied to any template
-
✓
Content Input — Drag-and-drop zone accepting: transcript text files, YouTube URLs (auto-extract), direct links, or paste raw content
-
✓
Registry Selector — Dropdown of available neural registries to auto-register the new page into during build
-
✓
Post-Publish Actions — Auto-opens the new page in browser after creation
-
✓
Build Preview — Preview generated HTML before publishing
Impact: Get notified when pages are published. Configurable per-build or saved as defaults.
-
✓
Slack Integration — Select Slack channels/users to notify on publish (webhook-based)
-
✓
Email Notifications — Select email addresses to notify on publish
-
✓
Saved Recipients — Save notification groups that persist across builds (e.g., "Athio Team" = Derek + Will + Jason Slack + emails)
-
✓
Per-Build Selection — Choose which saved groups to notify during the page build process
-
✓
Add More Anytime — Add new recipients without losing existing saved groups
Impact: Templates currently flat in templates/ folder. Need structured organization.
-
✓
Category Taxonomy — Templates organized by type: Meeting Notes, Sprint Pages, Registry, Skill, Blog, EOD, Custom
-
✓
Template Metadata — Each template has: name, description, preview thumbnail, design-standard file, supported content types
-
✓
Template Versioning — Track template versions (v1, v2) with ability to revert
-
✓
Template Search/Filter — Search by name, type, or tags in the GUI builder dropdown
Impact: Published pages stored in flat structure. Need organized folders sorted by neural registry.
-
✓
Auto-Folder by Registry — When publishing, auto-create/assign folder matching the target neural registry name
-
✓
Registry-Based Views — Dashboard shows pages grouped by which registry they belong to
-
✓
Orphan Detection — Find pages not registered in any neural registry
-
✓
Bulk Re-Organize — Tool to move existing pages into proper registry-based folders
Future Roadmap (API/Architecture Required)
High-level items requiring design and API work. Details TBD.
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.
- ✓OAuth Provider Integration — Connect auth (Google, GitHub, or custom) to gate bot access
- ✓Session Tokens for Bots — Replace name-based password with short-lived tokens tied to OAuth identity
- ✓Per-Registry Access Control — Configure which users/groups can chat with which registry agent
- ✓Audit Log — Track who queried what, which model, how many tokens consumed
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.
- ✓Key Input UI — Secure field in chat settings to paste API key (stored client-side only, never sent to our DB)
- ✓Server-Side Proxy — Route passes user key to LLM provider, falls back to our key if none provided
- ✓Usage Transparency — Show token counts and estimated cost per query in chat footer
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.
- ✓Public Landing — Unauthenticated visitors see registry title, description, and entry count only
- ✓Authenticated View — Full entry list, download links, embedded chat agent gated behind login
- ✓Per-Page Visibility — Mark individual pages as public, team-only, or private in page metadata
- ✓Share Links — Time-limited or password-gated share URLs for specific pages
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.
- ✓Bot Allowlist — Approved bot identifiers (API keys, IPs, user-agents) that bypass robot restrictions
- ✓robots.txt + API Enforcement — Block unapproved crawlers at both HTTP and API levels
- ✓Forge VPS Whitelisting — Auto-approve Forge API key for all read/write operations
- ✓Monitoring — Log and alert on unexpected bot traffic patterns
Impact: Extends F2 (Notification System). Define who gets notified for which registries, templates, and events. Connects to file organization (F4) and template schema (F3).
- ✓Recipient Groups — Named groups (e.g. "Sprint Team", "Cohort Leads") with Slack/email addresses
- ✓Registry-to-Recipient Mapping — Auto-notify specific groups when a registry is updated
- ✓Template-Based Routing — Different templates trigger different notification channels
- ✓Per-Build Selection — Override default recipients at publish time
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).
- ✓Install Ollama on Forge VPS — systemd service, pull llama3/mistral models
- ✓Reverse proxy via Cloudflare Tunnel or nginx — Auth header required, HTTPS endpoint
- ✓Set LOCAL_LLM_URL env var on Vercel — Registry agent reads from env instead of localhost
- ✓End-to-end test — registry-agent with model=local, verify response quality
- ✓Auto-fallback — If local endpoint unreachable, switch to Haiku automatically
Effort: ~2 hours infra + 1 hour testing | Depends on: VPS access, Ollama install
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.
- 1New agent tool:
create_page — Agent generates HC-compliant HTML (using hc-metadata, hc-instructions, hc-context-public blocks) from natural language instructions. Calls /api/publish internally with the authenticated user's API key or session. Returns preview URL.
- 2Preview-then-confirm gate — Agent returns a preview card in chat (title, slug, tags, first 200 chars). User clicks "Publish" or "Edit" before it goes live. No auto-publish without confirmation.
- 3
created_by field in hc-metadata — Add per-entry attribution: { created_by: "jason", created_via: "chat-agent", created_at: "..." }. Enables filtering by creator across all registries.
- 4"My Pages" tab in Athio registry — New tab (after existing category tabs) showing only pages created by the authenticated user. Filter on
created_by field. Falls back to showing all if field missing (backward compat).
- 5Template selection via chat — Agent picks from available HC templates (meeting-page, eod-review, hc-skill, etc.) based on user intent. "Write up today's standup" → meeting-page template. "Create a spec for X" → artifact template.
- 6Registry routing — Agent-created pages follow existing
--registry auto logic: meeting tags → meeting registry, eod tags → EOD registry, else → homepage. User can override: "put it in the sprint registry."
- 7Edit existing pages — Agent can fetch a page via
read_page tool, modify it, and re-publish with update_mode: "version". "Update the Phase 2 page to add Day 8 tasks" → fetches, edits, republishes.
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