joaoluisbrazao.com Audit
AUDIT & IMPLEMENTATION REPORT
Implementation of the new landing for joaoluisbrazao.com\ and the Irrelevant Machines subdomain (tcn.joaoluisbrazao.com)
--- Down a Rabbit Hole ---
Prepared by: Claude Code (Opus 4.7) for João Luís Brazão
Date: 2026-05-16
Source artefact: joaoluisbrazao-landing.zip (42.7 KB, 18 files)
Status: Audit complete --- pending implementation approval
1. Executive Summary
The supplied ZIP is not a standalone subpage for \'Irrelevant Machines\' as the prompt phrasing initially suggested. It is the full new landing page for joaoluisbrazao.com --- a four-card \'Down a Rabbit Hole\' hub (Geopolitics, Tuga Car Nuts, Broken Finance, AI & Society) plus a 2nd Brain strip. The \'Irrelevant Machines\' element is one of the four cards and acts as the entry point into a dedicated subdomain that surfaces the TCN slice of the existing Second Brain (jb_brain Postgres).
Bottom-line recommendation
Implement in five small sprints over \~7-8 working days. ZERO new software is required --- the existing stack (Postgres jb_brain with HNSW cosine, LiteLLM proxy, Rabbithall Flask, jb-skills-gateway, Chatwoot, nginx) covers every functional need. The only build work is application code: a corrected static landing, a new Rabbithall blueprint for tcn.joaoluisbrazao.com, a custom 300-LOC chat widget (\'Brain Pilot\'), a 3-table Postgres schema, and a weekly mining skill that feeds the existing quarantine UI.
Key findings at a glance
-
Architecturally sound. No-build, no-CDN, light background. Bates with TCN constraints in CLAUDE.md §6.1.
-
20 gaps identified (1 CRITICAL, 3 HIGH, 4 MEDIUM, 12 LOW). All addressable inside the planned sprints. See §3.
-
The current physical TCN site (/opt/downrabbithole/html/v7_final.html, 76 KB) is dismantled --- TCN content lives in Postgres jb_brain only.
-
Chat surface must NOT be Chatwoot (support-ticket platform). A custom Brain Pilot widget speaks to the brain via LiteLLM + RAG.
-
RGPD-compliant by design: persistent recording banner, hashed IPs, user actions exit/delete/email always available.
ASSUMPTION Voice-to-text drift: the original prompt referenced \'2G cardnets\' and \'joanwich-brazilian.com\'. Interpreted as \'TCN cards on joaoluisbrazao.com\'. If this interpretation is wrong, all of §4-§6 must be revisited.
2. What the ZIP Contains
Inventory of the artefact at /Users/joaoluisbrazao/Desktop/joaoluisbrazao-landing.zip:
Path Size Role
public/index.html 54 KB The new landing --- HTML + CSS + JS inline, no build
public/assets/typewriter.mp3 17 KB Ambient typing sound on first user interaction
public/assets/favicon.svg 0.3 KB Favicon
public/robots.txt \<1 KB Allow all, disallow /admin/
public/sitemap.xml \<1 KB Single URL (root) --- needs expansion when subpages are wired
public/.htaccess 1.5 KB Apache config (irrelevant on this VPS --- runs nginx)
nginx.conf.example 2.6 KB Sample nginx config --- needs HSTS, CSP, OCSP additions
nginx-docker.conf 0.5 KB Minimal nginx for the optional Docker mode
Dockerfile + 1 KB Not needed --- TCN is docker-compose.yml served directly from filesystem
README.md, 8 KB Deployment DEPLOY_QUICKSTART.md instructions, generic
CLAUDE.md 7 KB AI assistant context --- design intent, voice, anti-patterns
Feature catalogue (from the JS in index.html)
-
Visual: Wave generator --- 8 SVG paths animated at 60fps via requestAnimationFrame
-
Status: Live UTC clock + scrolling status banner (140s loop)
-
Hero: Word rotator on \'Welcome. You [word] shouldn\'t be here.\' + dual-glitch effect
-
Cards: 4 cards (Geopolitics / TCN / Broken Finance / AI), each with hover tilt, hover-line reveal, gradient accent bar
-
Brain: 2nd Brain strip with pulsing node + \'Open Graph\' CTA
-
Footer: \'Talk to us\' mailto + Subscribe stub with hover label mischief
-
Easter eggs: Konami code → 360° rotation; type \'truth\' → 5-rule terminal manifesto; triple-click logo → randomised CLASSIFIED stamp
-
i18n: Per-language dropdown stub (7 locales) --- fires console.log only
-
Audio: Typewriter ambience MP3, off by default, user toggle, browser autoplay-safe
3. Audit Findings --- Gaps & Required Corrections
Twenty issues identified across functional, security, accessibility, and operational dimensions. Severity scale: CRITICAL (blocks deployment), HIGH (must fix before GA), MEDIUM (important but non-blocking), LOW (polish or future).
# Gap Severity Correction
G1 openProject(\'machines\') is a CRITICAL Wire to console.log stub https://tcn.joaoluisbrazao.com. Rename slug \'machines\' → \'tcn\'.
G2 Admin gear → HIGH Point to https://joaoluisbrazao.cloud https://admin.joaoluisbrazao.cloud (root) (post DNS+SSL #714/#715).
G3 Language dropdown is HIGH Reduce to 2 options (PT, EN). Wire console.log stub to existing /js/i18n.js + locales/{pt,en}.json (TCN pattern, commit af227a6).
G4 Newsletter Subscribe is a stub MEDIUM POST /api/landing/subscribe → brain.newsletter_subscribers + double opt-in via SMTP (deferred).
G5 Hardcoded node count 14,978 LOW Pull live from /api/brain/stats (new endpoint). jb_brain currently at 14,979+ nodes.
G6 Email mailto: LOW Verify alias forwarding active; jbrazao@eureekka.com otherwise switch to jbrazao@me.com.
G7 Easter egg \'truth\' captures LOW Add guard: ignore when keystrokes globally e.target.tagName ∈ {INPUT, TEXTAREA}.
G8 Konami code: same global LOW Same guard as G7. keystroke issue
G9 8 animated SVG waves + card LOW Add \@media (prefers-reduced-motion: tilt + word rotator at 60fps reduce) --- pause all animations.
G10 Status banner uses dark ink LOW Acceptable --- thin decorative bar, #1A1F2E (30px height) not a reading block. Documented exception to \'no dark backgrounds\'.
G11 No \@media queries --- HIGH Add breakpoints at 768px (tablet, desktop-only layout cards 2→1 col) and 480px (mobile, dropdown repositioned).
G12 No prefers-color-scheme LOW OK --- design enforces single handling palette by accessibility constraint. Document.
G13 No Chatwoot widget on the MEDIUM Inject Chatwoot snippet (account 3, landing websiteToken JHW1yu1p3ickdixj418uK3bx) per pattern of TCN\'s existing 4 pages.
G14 No analytics LOW Optional Plausible/Umami (privacy-friendly) self-hosted. Non-blocking.
G15 Subscribe button LOW Documented as intentional voice. label-mischief (5 hover Keep. strings)
G16 Dockerfile + LOW Discard. nginx serves static docker-compose.yml provided directly from /opt/downrabbithole/html/ (existing pattern).
G17 nginx.conf.example lacks HSTS, MEDIUM Add Strict-Transport-Security CSP, OCSP stapling max-age=31536000 includeSubDomains preload; CSP self + \'unsafe-inline\'; OCSP stapling on.
G18 CSP not declared --- easter MEDIUM Initial CSP allows \'unsafe-inline\' eggs use inline JS for script/style; revisit when JS is externalised.
G19 No version badge LOW Per CLAUDE.md §14 --- add hidden-until-hover badge bottom-left showing v{VERSION} . {ENV} . {GIT_SHA}.
G20 No VERSION file in the ZIP LOW Create VERSION=0.1.0 at repo root. Use prefix \'tcn-v\' per CLAUDE.md §4.2 versioning convention.
3.1 Conflicts with current production state
Conflict Resolution
TCN at /opt/downrabbithole/html/ Backup current index.html to currently occupies _backup/v7_final.html.2026-05-16.bak; joaoluisbrazao.com root deploy new landing to same path. (v7_final.html, 76598 bytes).
nginx config currently serves Rewrite to keep static-only. Add new /opt/downrabbithole/html/ as server block for tcn.joaoluisbrazao.com joaoluisbrazao.com. with proxy_pass → infra-rabbithall.
Permission 403 issue (umask 077 → Preserve ACL on new deploy. Verify with 640) already fixed via setfacl + umask 077 test post-swap. git hooks (2026-05-16).
6 existing TCN pages (index, cars, Decide individually: 301 redirect to ai, geopolitics, etc) with Chatwoot tcn.joaoluisbrazao.com (recommended), or installed. keep as standalone subpages. Tracking task to be created.
3.2 Aspects validated as correct (keep as is)
-
Plain HTML/CSS/JS, no build step, no CDN imports --- matches TCN convention.
-
Light cream background (#f4f0e8) --- respects João\'s documented colour-blind + low-vision accessibility constraint.
-
Editorial / Financial-Times aesthetic --- appropriate voice register for the project.
-
Security headers in nginx.conf.example (X-Content-Type-Options, X-Frame-Options, Referrer-Policy) correctly configured.
-
TLS 1.2/1.3, gzip, immutable caching for static assets, hidden-file deny --- all correct.
-
Audio is opt-in (default off, click-to-start) --- respects browser autoplay policy and user preference.
4. Proposed Architecture
4.1 Domain map
joaoluisbrazao.com/ ← landing static (this ZIP, corrected)\ Source: /opt/downrabbithole/html/\ nginx: static, no proxy\ \ tcn.joaoluisbrazao.com/ ← Irrelevant Machines page\ Source: Rabbithall blueprint /tcn/*\ nginx: proxy_pass → infra-rabbithall:5000\ Reads: jb_brain (TCN slice, 112 entities)\ \ apocalypse.joaoluisbrazao.com/ ← future (Geopolitics --- out of this sprint)\ banks.joaoluisbrazao.com/ ← future (Broken Finance --- out of this sprint)\ ghost.joaoluisbrazao.com/ ← future (AI & Society --- out of this sprint)\ brain.joaoluisbrazao.com/ ← already LIVE (Brain OS Graph Explorer)
4.2 tcn.joaoluisbrazao.com --- page layout
Three-zone layout served by a new Rabbithall Flask blueprint:
-
Graph pane: Left 60% --- 3D/2D force-graph (3d-force-graph.js vendored locally) showing the TCN slice of jb_brain (112 nodes, 51 links). Reuses the component already running at brain.joaoluisbrazao.com/graph.
-
Chat pane: Right 40% --- Brain Pilot custom chat widget. Conversational interface over the brain. Each reply may carry a focus_node_id which re-centres the graph dynamically.
-
Nav: Top --- language toggle (PT/EN), admin gear, back-to-joaoluisbrazao.com link.
-
Support: Bottom-right --- Chatwoot widget for \'Talk to a human\'. Separate channel from Brain Pilot.
4.3 Brain Pilot --- chat widget design
Custom-built (\~300 LOC vanilla JS) --- no external chat library required. The rationale and the four open-source alternatives evaluated are in §5.
Frontend
-
Persistent RGPD banner: \"ⓘ Esta conversa está a ser gravada para enriquecer a base de conhecimento. Os teus dados não são partilhados. Podes apagar ou pedir email ao terminar.\"
-
Message stream with simple markdown rendering (bold, italic, links)
-
Input field + send button + typing/saved status indicator
-
Three terminal actions in the widget header:
-
Sair --- close widget, keep log
-
Apagar conversa --- confirm modal → DELETE in Postgres + clear UI
-
Email-me --- input prompt → POST → SMTP sends HTML transcript (SMTP currently deferred)
Backend --- Rabbithall blueprint endpoints
POST /api/tcn/chat # user msg → AI reply + focus_node_id\ POST /api/tcn/chat/clear # purge messages for session_id\ POST /api/tcn/chat/email # send transcript via SMTP (queued if disabled)\ GET /api/tcn/entities # list 112 TCN entities (partial: already exists)\ GET /api/tcn/graph/full # full TCN slice for initial render\ GET /api/tcn/graph/ego/\<id> # ego-graph 1--2 hops around node_id\ GET /api/tcn/stats # node count, edge count for UI
Chat flow (POST /api/tcn/chat)
-
1. Receive {session_id, message, history[]}
-
2. Embed user message via LiteLLM (gemini-embedding-001, dimensions=768)
-
3. HNSW cosine search on jb_brain.nodes WHERE metadata->>\'topic\' = \'tuga-car-nuts\' LIMIT 8
-
4. Regex + fuzzy match against 112 TCN entities to detect explicit mentions (\'Niki Lauda\' → pilot UUID)
-
5. Build prompt: system + RAG context + history last 6 turns + user message
-
6. LLM call via LiteLLM (Mistral-first chain, \~\$0.001/msg)
-
7. INSERT brain.conversation_messages × 2 (user + assistant with retrieved nodes JSONB)
-
8. Return {reply, focus_node_id, related_node_ids[], retrieved_evidence[]}
On receiving the response the frontend calls graph.centerOnNode(focus_node_id) if present and renders retrieved_evidence as clickable chips that highlight nodes in the graph.
4.4 New Postgres schema
Lives inside the existing jb_brain DB, under a new schema \'brain\'.
CREATE SCHEMA IF NOT EXISTS brain;\ \ CREATE TABLE brain.conversations (\ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\ session_id TEXT NOT NULL,\ surface TEXT NOT NULL, -- \'tcn\', \'apocalypse\', ...\ user_agent TEXT,\ ip_hash TEXT, -- SHA-256(ip) for RGPD safety\ locale TEXT, -- \'pt\' or \'en\'\ started_at TIMESTAMPTZ DEFAULT now(),\ ended_at TIMESTAMPTZ,\ action_taken TEXT, -- exit / clear / email / abandoned\ email_sent_to TEXT,\ created_at TIMESTAMPTZ DEFAULT now(),\ updated_at TIMESTAMPTZ DEFAULT now(),\ deleted_at TIMESTAMPTZ\ );\ CREATE INDEX idx_conv_session ON brain.conversations(session_id);\ CREATE INDEX idx_conv_surface_started\ ON brain.conversations(surface, started_at DESC);\ \ CREATE TABLE brain.conversation_messages (\ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\ conversation_id UUID NOT NULL\ REFERENCES brain.conversations(id) ON DELETE CASCADE,\ role TEXT NOT NULL\ CHECK (role IN (\'user\', \'assistant\', \'system\')),\ content TEXT NOT NULL,\ retrieved_node_ids JSONB,\ detected_entities JSONB,\ focus_node_id UUID,\ tokens_in INT, tokens_out INT,\ model_used TEXT, latency_ms INT,\ created_at TIMESTAMPTZ DEFAULT now()\ );\ CREATE INDEX idx_msg_conv\ ON brain.conversation_messages(conversation_id, created_at);\ \ CREATE TABLE brain.conversation_quarantine (\ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\ source_conversation_id UUID\ REFERENCES brain.conversations(id),\ candidate_type TEXT NOT NULL, -- question / entity / gap / novel_topic\ payload JSONB NOT NULL,\ score NUMERIC(3,2),\ status TEXT DEFAULT \'pending\', -- pending / accepted / rejected / archived\ reviewed_by TEXT, reviewed_at TIMESTAMPTZ,\ created_at TIMESTAMPTZ DEFAULT now()\ );\ CREATE INDEX idx_quar_status\ ON brain.conversation_quarantine(status, created_at DESC);
4.5 Quarantine & knowledge enrichment loop
A new skill \'discover.conversation-mining\' is added to jb-skills-gateway (52 skills currently). It follows the proven \'discover.content-nuggets\' pattern that is already LIVE and runs every Monday 07:00 UTC.
-
Schedule: Monday 05:30 UTC (cron entry inside jb-skills-gateway)
-
Input: last 7 days of brain.conversation_messages, grouped by surface
-
Algorithm 1 --- Frequent questions: cluster user messages by embedding cosine ≥ 0.85 → recurring themes
-
Algorithm 2 --- Unknown entities: surface mentioned names without a match in jb_brain (≥ 2 occurrences)
-
Algorithm 3 --- Content gaps: questions where RAG returned weak or empty evidence
-
Output: INSERT into brain.conversation_quarantine
-
UI: existing /admin/quarantine page receives a new filter ?source=conversation-mining; Accept/Reject buttons create new jb_brain nodes or content tasks
5. Tools & Components Inventory
5.1 Zero new software to install
Every functional requirement is covered by infrastructure that is already LIVE:
Component State Location / role
Postgres jb_brain DB LIVE infra-postgres --- 14,979+ nodes, HNSW cosine 768-dim
TCN slice in jb_brain LIVE 112 entities (61 cars + 15 pilots + 20 events + 8 brands + 8 eras), 51 node_links
LiteLLM Smart Router v2 LIVE 25 models, gemini-embedding-001 768-dim free, Mistral-first chain
Rabbithall (Flask + LIVE /opt/rabbithall/, container blueprints) infra-rabbithall, pattern already used for /admin/*, /brain/*
jb-skills-gateway LIVE 52 skills, discover.* pattern established (content-nuggets, etc.)
3d-force-graph (JS lib) In use Already powering brain.joaoluisbrazao.com/graph --- vendoring locally for tcn
Chatwoot LIVE Account 3, used on landing only (NOT inside Brain Pilot)
nginx LIVE infra-nginx, TLS 1.3, certbot --- add new server block for tcn subdomain
Forgejo (sovereign git) LIVE New repo joaobrazao/jlb-landing to be created
Vaultwarden LIVE Will hold SMTP credentials when mail server is provisioned
Telegram LIVE SSL expiry monitor will pick up \@DownRabbitbot the new tcn cert automatically
Uptime Kuma LIVE Add monitor for tcn.joaoluisbrazao.com (HTTPS, response \< 2s)
5.2 Locally-vendored static files (not \'tools\', just .js)
File Size Reason
3d-force-graph.min.js \~250 KB Force-graph component (already in use at brain.joaoluisbrazao.com)
three.min.js \~600 KB WebGL 3D dependency of 3d-force-graph
d3.min.js \~80 KB Force-simulation engine used by 3d-force-graph
i18n.js (existing TCN) \~5 KB Locale switcher --- already in use on current TCN, port to landing
Total additional payload: \~1 MB. Served with Cache-Control: public, immutable, max-age=30d.
5.3 SMTP --- deferred plug-and-play hook
João indicated a VPS-hosted mailbox will be set up later. The \'email me\' endpoint is fully implemented but gated by a feature flag. When credentials arrive:
-
Store SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_FROM in Vaultwarden
-
Wire env vars into rabbithall docker-compose.yml
-
Set SMTP_ENABLED=true
-
Restart container --- no code change required
STATE Until SMTP is configured, the \'Email-me\' button returns {status: \'queued\', message: \'Email pendente --- SMTP em configuração\'}. The user sees a friendly notice. No transcripts are lost.
5.4 Alternatives evaluated and rejected
Why a custom 300-LOC widget instead of an off-the-shelf open-source chat library:
Candidate Fit Reason
AnythingLLM, Librechat, BAD Full standalone RAG platforms Open WebUI with their own DB, auth, UI. Duplicate jb_brain. Operational overhead. Lock-in.
deep-chat OK Drop-in JS web component, BYO (deepchat-dev/deep-chat, backend. \~80 KB to vendor. MIT) Custom actions (exit/clear/email) still require \~150 LOC. Net win vs custom is marginal.
Chatwoot bot integration BAD Possible but overcomplicated --- Chatwoot is a support-ticket platform, the bot API is geared to human handoff, not in-page RAG agent.
Custom widget (\~300 LOC RECOMMENDED Direct fit to requirements. vanilla JS) Zero new deps. Direct INSERT to brain.conversation_messages. No library version churn. Reuses existing rabbithall/LiteLLM/jb_brain stack.
6. Implementation --- Step by Step
Five sprints. Each sprint is independently shippable; later sprints depend on earlier ones. Total \~7-8 working days with Claude Code assistance.
Sprint 0 --- Preparation (1 day)
-
0.1 Create VERSION file (0.1.0) at repo root
-
0.2 Create Forgejo repo joaobrazao/jlb-landing with ZIP content + corrections G1--G20
-
0.3 Backup current /opt/downrabbithole/html/index.html → _backup/v7_final.html.2026-05-16.bak
-
0.4 Snapshot jb_brain DB: pg_dump → /opt/backups/jb_brain_pre_tcn_chat_2026-05-16.sql
Sprint 1 --- New landing live at joaoluisbrazao.com/ (1 day)
- 1.1 Apply all G1--G20 corrections to index.html
-
Wire openProject(\'tcn\') → https://tcn.joaoluisbrazao.com (other three cards link to placeholder)
-
Admin gear → https://admin.joaoluisbrazao.cloud
-
i18n dropdown reduced to PT/EN, wired to /js/i18n.js + locales/{pt,en}.json
-
Easter-egg keystroke guards (ignore when focus on INPUT / TEXTAREA)
-
prefers-reduced-motion media query
-
Responsive breakpoints \@768px and \@480px
-
Version badge bottom-left (hover to reveal)
-
Chatwoot widget snippet (token JHW1yu1p3ickdixj418uK3bx)
-
1.2 Mark \~80 strings with data-i18n; create pt.json + en.json
-
1.3 Add hreflang + canonical tags in \<head>
-
1.4 Vendor /assets/js/i18n.js locally
-
1.5 Deploy: scp → /opt/downrabbithole/html/, setfacl, chmod normalisation, reload nginx
-
1.6 Revise /opt/infrastructure/nginx/conf.d/joaoluisbrazao.com.conf --- pure static, no proxy, add HSTS / CSP / OCSP stapling
-
1.7 Manual test: load, swap language, easter eggs, Chatwoot widget, card links (placeholders for 3 cards, 502 for tcn until Sprint 2)
Sprint 2 --- tcn.joaoluisbrazao.com page + graph (2 days)
-
2.1 DNS: create A record \'tcn\' → VPS IP at Hostinger panel
-
2.2 Certbot: certbot --nginx -d tcn.joaoluisbrazao.com (added to renewal crontab)
-
2.3 Create /opt/infrastructure/nginx/conf.d/tcn.joaoluisbrazao.com.conf --- proxy_pass → infra-rabbithall:5000, X-App-Version header, HSTS
-
2.4 Add new blueprint /opt/rabbithall/app/blueprints/tcn.py; register in app/__init__.py
-
2.5 Vendor 3d-force-graph.min.js, three.min.js, d3.min.js into app/static/assets/js/vendor/
-
2.6 Template app/templates/tcn/index.html --- 3-zone layout, data-i18n marks, Chatwoot in footer
-
2.7 Endpoint GET /api/tcn/graph/full --- returns 112 nodes + 51 links JSON
-
2.8 Endpoint GET /api/tcn/graph/ego/\<node_id>?hops=2
-
2.9 Verify existing GET /api/tcn/entities (session 2026-05-16 #718)
-
2.10 Tests: page loads, graph renders 112 nodes, node click expands ego
Sprint 3 --- Brain Pilot chat widget (2 days)
-
3.1 Alembic migration 001_brain_chat.py --- create schema \'brain\' + 3 tables
-
3.2 Frontend app/static/js/tcn/brain-pilot.js (\~300 LOC) --- persistent RGPD banner, message stream, send box, 3 action buttons, confirm modals
-
3.3 CSS app/static/css/tcn/brain-pilot.css
-
3.4 Endpoint POST /api/tcn/chat --- embed → HNSW search → entity match → LiteLLM call → INSERT × 2
-
3.5 Endpoint POST /api/tcn/chat/clear --- UPDATE conversation, DELETE messages
-
3.6 Endpoint POST /api/tcn/chat/email --- SMTP-disabled fallback (returns queued state)
-
3.7 Frontend hook: on response, call graph.centerOnNode(focus_node_id) if present; render retrieved_evidence chips
-
3.8 Manual tests:
-
\'Niki Lauda\' → graph re-centres on the pilot, reply contains biographical context from brain
-
\'Que carros tinham V12?\' → RAG returns cars with V12 metadata, graph highlights them
-
\'Apagar\' button → DELETE confirmed in Postgres, UI clears
-
\'Email-me\' → returns queued state, UI shows \'pendente\' notice
-
RGPD banner visible across all renderings
Sprint 4 --- Quarantine & enrichment (1 day)
-
4.1 Create skill /opt/jb-skills-gateway/skills/discover/conversation_mining.py --- implements 3 algorithms (frequent_questions, unknown_entities, content_gaps)
-
4.2 Add cron: 30 5 * * 1 curl -X POST http://localhost:8095/skills/discover.conversation-mining/run
-
4.3 Extend /admin/quarantine UI: filter ?source=conversation-mining, Accept/Reject buttons per candidate
-
4.4 Accept candidate → create node in jb_brain (entity) or content task in Vikunja (gap)
Sprint 5 --- Verification & docs (1 day)
-
5.1 Run audit pipeline (audit.security-scan, audit.code-quality, audit.container-health) --- expect zero new CRITICAL
-
5.2 Lighthouse Core Web Vitals on the new landing --- target LCP \< 2.5s
-
5.3 Update CLAUDE.md §12 --- new state lines for tcn.joaoluisbrazao.com LIVE, Brain Pilot LIVE, quarantine extension LIVE
-
5.4 infrastructure-docs portal --- new doc apps/tcn.md, ADR-0005 \'Brain Pilot architecture decision\'
-
5.5 Vikunja close-out tasks + follow-ups for the eight open decisions in §10
7. End-to-End Verification Checklist
GA (Sprint 5 closed) requires all items below to pass.
-
☐ https://joaoluisbrazao.com/ loads the new landing --- verified via curl + browser DevTools (no console errors, LCP \< 2.5s)
-
☐ Clicking \'Irrelevant Machines\' opens tcn.joaoluisbrazao.com
-
☐ PT/EN switch translates all strings dynamically on both landing and tcn
-
☐ tcn.joaoluisbrazao.com loads the 3D graph with 112 nodes and 51 links
-
☐ Clicking a graph node expands its 1-2 hop ego-graph
-
☐ Brain Pilot: typing \'Niki Lauda\' re-centres the graph on that pilot node and replies with biographical context
-
☐ RGPD banner is visible at the top of the chat in every session
-
☐ \'Apagar\' action: messages disappear in the UI and DELETE is confirmed in Postgres
-
☐ \'Email-me\' action: email input is accepted, response shows pending state (SMTP disabled phase)
-
☐ Conversation is logged to brain.conversation_messages with retrieved_node_ids and detected_entities populated
-
☐ Monday 05:30 UTC cron runs discover.conversation-mining (visible in /admin/runs)
-
☐ Candidates appear in /admin/quarantine?source=conversation-mining
-
☐ Chatwoot widget opens on the landing as \'Talk to us\' (separate from Brain Pilot)
-
☐ Easter eggs (konami, \'truth\', triple-click) work but do not fire when focus is on an input field
-
☐ Audit pipeline (LIVE) runs the following Sun 23:00 with zero new CRITICAL findings
-
☐ Telegram bot picks up the new SSL cert expiry for tcn.joaoluisbrazao.com
-
☐ Uptime Kuma monitor for tcn.joaoluisbrazao.com is green
8. Suggestions & Improvements Beyond the ZIP Spec
These items are not strictly required by the ZIP but materially improve the result. None block delivery; all are inside the Sprint 1-5 timeline.
Improvement Value Effort
HSTS + CSP + OCSP stapling in nginx Security baseline --- 30 min
flagged by audit
pipeline if absent
Responsive \@media for tablet + mobile \~30% of João\'s 2 h
audience uses mobile
--- current ZIP is
desktop-only
prefers-reduced-motion gate on waves + Accessibility (WCAG 2.1 30 min
tilt + glitch SC 2.3.3) + battery
savings on mobile
Version badge per CLAUDE.md §14 Debug aid + provenance 20 min
for visiting
collaborators
IP hash instead of raw IP storage RGPD-safe 10 min
identification ---
defensible audit trail
Rate-limit Brain Pilot at 30 msg / Prevents LiteLLM 1 h session / hour monthly cap blow-up
Hashed-IP rate-limit on Prevents subscribe-form 30 min /api/landing/subscribe abuse
Lighthouse + Web Vitals automated check Catches regressions in 1 h (add to deploy post-deploy landing weight / paint hook) timing
Brain Pilot \'show evidence\' toggle Lets users see which 1 h
jb_brain nodes informed
the reply ---
transparency
JSONB GIN index on Faster TCN slice filter 5 min jb_brain.nodes.metadata->>\'topic\' on every chat query
Word rotator + manifesto easter egg Voice integrity in 30 min
translated to PT Portuguese ---
currently English-only
Add new tcn subdomain to UptimeKuma + Operational 20 min Telegram alerts observability
301 redirects from 6 old TCN pages → Preserves SEO and 30 min tcn.joaoluisbrazao.com external links
Conversation \'show evidence\' chips Tightens the chat-graph 1 h
clickable → graph highlight loop, makes the
dynamic-centring useful
in practice
Sitemap.xml expanded with PT + EN URLs SEO for both locales 15 min and hreflang
9. Risks & Mitigations
Risk Impact Mitigation
Easter eggs (konami, UX confusion Guard against \'truth\', e.target.tagName ∈ {INPUT, triple-click) fire TEXTAREA} --- G7/G8 accidentally during corrections chat input
RGPD: storing Legal exposure Persistent recording banner + conversations + IP SHA-256-hashed IP + requires lawful basis always-available \'Apagar\' action satisfies Art. 13 (information at collection) and Art. 17 (right to erasure)
LiteLLM hits monthly Cost / failure Mistral-first routing (per cap (\$25/mo global) CLAUDE.md §5). Rate-limit per under chat load session_id (30 msg/h). Monitor in /admin/runs
3d-force-graph UX TCN slice is only 112 nodes performance on mobile --- well under any devices performance threshold. Mobile falls back to 2D view via UI toggle
Cold-start latency on Perceived slowness HNSW index already present. jb_brain queries with Add JSONB GIN index on JSONB filters metadata->>\'topic\' (see §8)
SMTP deferred = Feature gap Button present but returns \'Email-me\' unusable queued state with friendly until set up notice. Decoupled --- switching on later requires no code change
New subdomain = Operational Certbot already managing .com separate SSL cert and .cloud. Add \'tcn.\' lifecycle alias to existing renewal cron. Telegram alert on expiry inherits from current setup
Chatwoot widget + Brain UX Clear visual separation: Pilot on same page Chatwoot bottom-right (small could confuse users floating button), Brain Pilot fixed right panel (always open). Label both explicitly
Brain Pilot LLM may Quality System prompt forces hallucinate about TCN \'Respond only using the entities provided context. If unsure, say so.\' Every reply logs retrieved_evidence for audit
Conversation logs grow Storage Partition over time brain.conversation_messages by month after 6 months. Expected volume \< 1 MB/month at initial traffic
Slug change Coordination Single point of change in \'machines\' → \'tcn\' index.html JS (openProject must be made everywhere mapping). Documented in §10 as open decision
6 existing TCN pages SEO + bookmarks Map each old URL to its may break if redirected closest new view on without care tcn.joaoluisbrazao.com via nginx 301. Test with Google Search Console post-deploy
10. Open Decisions (need João\'s input before deploy)
-
D1 Confirm slug change in card 2 from \'machines\' to \'tcn\' so it matches tcn.joaoluisbrazao.com
-
D2 What to do with the other 3 cards (apocalypse / banks / ghost) before their subdomains exist --- placeholder page, \'coming soon\' modal, or hide?
-
D3 Retire or redirect the 6 existing TCN pages (cars / ai / geopolitics / etc.) --- recommendation: 301 each to the appropriate tcn.* view
-
D4 Keep Chatwoot widget on tcn.joaoluisbrazao.com alongside Brain Pilot, or Brain Pilot only?
-
D5 ETA on VPS-hosted SMTP --- affects when \'Email-me\' becomes usable (no code change required, just config)
-
D6 Version-tracking convention: use tcn-v0.1.0 (per CLAUDE.md §4.2 prefix) or generic 0.1.0?
-
D7 Where does the git SHA come from for the version badge (no CI/CD on static landing)? --- recommended: post-commit hook writes /version.json
-
D8 Translate easter-egg manifesto + word rotator (probably / definitely / inevitably...) into PT?
Appendix A --- Example RAG prompt for Brain Pilot
SYSTEM:\ You are Brain Pilot for joaoluisbrazao.com --- the Tuga Car Nuts (TCN) section.\ Answer in the user\'s language (PT or EN, detected from the locale field).\ Voice: dry, sharp, witty, sophisticated --- never clownish or \'startup\'.\ \ RULES:\ 1. Answer only from the provided RETRIEVED_CONTEXT below.\ 2. If the answer is not in the context, say so plainly. Do not invent facts.\ 3. When you mention a named entity that exists in DETECTED_ENTITIES,\ set focus_node_id in your JSON response so the UI can re-centre the graph.\ 4. Keep replies under 6 sentences unless asked to elaborate.\ \ RETRIEVED_CONTEXT:\ {top_8_jb_brain_chunks_with_metadata}\ \ DETECTED_ENTITIES:\ {entities_matched_in_user_message_with_node_ids}\ \ HISTORY (last 6 turns):\ {compact_user_assistant_pairs}\ \ USER:\ {user_message}\ \ OUTPUT JSON:\ {\ \"reply\": \"\<your reply, plain text + simple markdown>\",\ \"focus_node_id\": \"\<uuid|null>\",\ \"related_node_ids\": [\"\<uuid>\", ...],\ \"retrieved_evidence\": [\ {\"node_id\": \"\<uuid>\", \"snippet\": \"\<text>\", \"score\": 0.86}\ ]\ }
Appendix B --- Example chat flow
Illustrative end-to-end of the \'Niki Lauda\' scenario described in the brief.
[user types] > Niki Lauda\ \ [backend]\ 1. session=abc123, locale=pt detected\ 2. embed(\'Niki Lauda\') → [768 floats]\ 3. HNSW search:\ SELECT id, content, metadata\ FROM jb_brain.nodes\ WHERE metadata->>\'topic\'=\'tuga-car-nuts\'\ ORDER BY embedding_768 \<=> \$1\ LIMIT 8;\ → top hit: id=4f3a..., type=pilot, name=\'Niki Lauda\', metadata={...biography}\ 4. entity match: \'Niki Lauda\' → confirmed node_id=4f3a...\ 5. LiteLLM call (Mistral) with system + RAG context + this query\ 6. INSERT user message + assistant reply into brain.conversation_messages\ 7. Response:\ {\ \"reply\": \"Andreas Nikolaus Lauda, três vezes campeão de F1 (1975, 1977, 1984). ...\",\ \"focus_node_id\": \"4f3a-...-...\",\ \"related_node_ids\": [\"\<Ferrari 312T uuid>\", \"\<Brabham BT46 uuid>\", \"\<1976 GP Alemanha uuid>\"],\ \"retrieved_evidence\": [\ {\"node_id\":\"4f3a-...\",\"snippet\":\"Vencedor 1975, 1977, 1984...\",\"score\":0.91},\ {\"node_id\":\"\<Ferrari uuid>\",\"snippet\":\"Conduziu o 312T...\",\"score\":0.82}\ ]\ }\ \ [frontend]\ 8. graph.centerOnNode(\'4f3a-...\') → camera moves\ 9. graph.highlightNodes([related ids]) → glow ring on connected nodes\ 10. render reply in chat with evidence chips\ 11. chips clickable → highlight node on graph + open node detail panel
Appendix C --- Key file paths to create or modify
Files to create
Local (dev):\ \~/Documents/JB_Hostinger/jlb-landing/ (cloned ZIP + corrections)\ → Forgejo joaobrazao/jlb-landing\ \ VPS:\ /opt/downrabbithole/html/index.html (replaces v7_final.html)\ /opt/downrabbithole/html/locales/pt.json\ /opt/downrabbithole/html/locales/en.json\ /opt/downrabbithole/html/js/i18n.js\ /opt/infrastructure/nginx/conf.d/tcn.joaoluisbrazao.com.conf\ /opt/rabbithall/app/blueprints/tcn.py\ /opt/rabbithall/app/templates/tcn/index.html\ /opt/rabbithall/app/static/js/tcn/brain-pilot.js\ /opt/rabbithall/app/static/css/tcn/brain-pilot.css\ /opt/rabbithall/app/static/assets/js/vendor/3d-force-graph.min.js\ /opt/rabbithall/app/static/assets/js/vendor/three.min.js\ /opt/rabbithall/app/static/assets/js/vendor/d3.min.js\ /opt/rabbithall/migrations/001_brain_chat.py\ /opt/jb-skills-gateway/skills/discover/conversation_mining.py\ /opt/backups/jb_brain_pre_tcn_chat_2026-05-16.sql\ /opt/downrabbithole/_backup/v7_final.html.2026-05-16.bak
Files to modify
/opt/infrastructure/nginx/conf.d/joaoluisbrazao.com.conf\ (static-only, HSTS+CSP+OCSP added)\ /opt/rabbithall/app/__init__.py\ (register tcn_bp blueprint)\ /opt/rabbithall/docker-compose.yml\ (SMTP_* env vars, gated by SMTP_ENABLED flag)\ \~/.claude/CLAUDE.md §12\ (new state: tcn.joaoluisbrazao.com LIVE, Brain Pilot LIVE, quarantine extension LIVE)\ /opt/infrastructure-docs/apps/tcn.md (new)\ /opt/infrastructure-docs/decisions/ADR-0005-brain-pilot.md (new)\ /var/spool/cron/crontabs/root\ (entry: 30 5 * * 1 curl -X POST http://localhost:8095/skills/discover.conversation-mining/run)
--- Bricks over bricks. ---