Changelog
2026-02-25 17:00 UTC [windsurf-chat-capture]
##### Windsurf Chat Capture: Extension, API, and Web UI
- VSCode Extension (
apps/windsurf-chat-capture/): TypeScript extension for Windsurf IDE that captures chat conversations
- Manual capture command using clipboard ( - API Endpoints (
web/public/projects/api/):
- - Database Schema (
database/migrations/2026-02-25-0001-windsurf-chat-schema.sql):
- - Web UI (
web/public/projects/windsurf.php):
- Windsurf Hub page with workspace filtering
- Manual chat capture form (paste chat content, add title)
- Card and list views for chats and plans
- Search and filter functionality - Hook Scripts (
scripts/):
- - Icons: Added PNG icon support for Cursor Hub (
cursor.png) and Windsurf Hub (windsurf.png) inweb/public/projects/icons/ - Documentation:
docs/WINDSURF_CHAT_CAPTURE.md-- complete installation guide for paris.lan - PostgreSQL backup script (
cron/backup-pg.sh): Daily automated backups forzap,energystats,philanthropy_planner,prospecta_ccdatabases with 7 daily + 4 weekly + 3 monthly rotation to/mnt/merlin-backups/databases/postgresql/ - Shared notification library (
cron/notify-lib.sh): Dual-channel failure alerts via Telegram + ntfy.sh. Credentials read from central~/.credentialsfile. - Backup history tracking: New
backup_historytable in zap database records all backup events (success/failure) with timestamps, sizes, and error messages. PHP CLI scriptcron/log-backup.phpfor logging. - Enhanced SQLite backups: Updated
philoenic.com/cron/backup-db.shandzap-mail/cron/backup-db.shto use notification library and log to database. - Database status pages: -
- General planning area: New
zap-projectspages for cross-project roadmap (general.phpdisplayingROADMAP.mdandNOTES.md) - Windows protocol handler: Registry file for paris.lan to enable direct opening of backup folders from browser links
- New shared RAG service (
apps/zap-rag/): standalone retrieval-augmented generation service replacing the embedded RAG in zap-writer. Any Zap app (zap-writer, philoenic, philanthropy-planner) can consume it via REST API. - Design phase complete: MASTER-PLAN.md contains a 10-phase build plan informed by 15+ arxiv papers (Late Chunking, RAPTOR, CRAG, ColPali, HiRAG, BGE-M3, pgvectorscale, CAR, Chain-of-Density, Self-RAG, Skeleton-of-Thought).
- Three frontier model critiques: ChatGPT, Gemini, and Perplexity each reviewed the plan. Key disagreements resolved by paper evidence (proposition indexing made opt-in, PHP/Apache kept for current scale, HyDE+Rocchio validated).
- Research synthesis (RESEARCH-SYNTHESIS.md): paper-by-paper analysis with 11 concrete changes applied to the plan.
- Key architectural decisions: local LLMs only (Ollama), privacy-first LAN-only mode, PostgreSQL + pgvector + pgvectorscale, late chunking as primary embedding strategy, cross-encoder reranking, CRAG with strip refinement, adaptive retrieval cutoff.
- Registered in zap-projects (slug:
zap-rag) with chat and plan links. - Hidden Money project created (
writer_projectsrow with slughidden-money): book on philanthropy and DAFs, co-authored by Julian Darley (writer) and Celine Darley (philanthropy advisor). Config includes Google Doc ID, people, topics, and document tab structure. - Google Docs tab ingestion (
bin/ingest-gdoc-tabs.php): CLI script that fetches a multi-tabbed Google Doc via the Docs API v1 (includeTabsContent=true), extracts text from paragraphs and tables, preserves hierarchical tab paths, and stores each tab as awriter_documentsrow. Reuseszap-mail's Google OAuth tokens. - Document chunking (
bin/ingest-file.php): extended to support re-chunking existing documents with configurable chunk size (1500 chars) and overlap (200 chars). Added sentence-level splitting viasplitOversizedBlock()for paragraphs exceeding target size. Fixed UTF-8 encoding issue (mb_convert_encoding+ control char stripping). - pgvector embeddings (migration
2026-02-22-0003): enabledvectorPostgreSQL extension, createdwriter_chunk_embeddingstable withvector(768)column and HNSW index for cosine similarity search. 424 chunks embedded usingnomic-embed-texton titan (9.5 chunks/sec, 44s total). - Embedding pipeline (
bin/embed-chunks.php): generates vector embeddings via Ollama, auto-selects the best server using the LLM gateway'sGATEWAY_SERVERSconfig (prefers smaller servers to avoid evicting large models from delphi). Pullednomic-embed-textto titan for dedicated embedding. - Multi-source RAG search (
api/rag-answer.php): new endpoint returning 4-part synthesised answers:
* Part A (Documents): pgvector cosine search for top 8 chunks, LLM synthesis with source citations (doc title, path, similarity, excerpt)
* Part B (LLM Knowledge): pure LLM chat with philanthropy-focused system prompt
* Part C (Web Search): SearXNG web search + LLM synthesis with source URLs
* Part D (External Library): placeholder for books/reports not yet ingested
- Search UI overhaul (
project.php): replaced raw chunk display with 4 collapsible answer cards (colour-coded: gold/Documents, indigo/LLM, green/Web, grey/External). Added model selector dropdown (populated from gateway, grouped by server, stored in localStorage). Added collapsible "Raw Matches" section. Fixed CSS padding (search tab was outside.containerdiv). - Models API (
api/models.php): new endpoint proxying LLM gateway models, grouped by server for the dropdown. - Database migrations:
2026-02-22-0001(Hidden Money project insert),2026-02-22-0002(document_chunks table),2026-02-22-0003(pgvector + chunk_embeddings). - Documents tab: tree/list view of ingested Google Doc tabs with document viewer. Refresh button triggers re-ingestion.
- API endpoints:
documents.php(list/fetch documents),refresh-gdoc.php(trigger ingestion),rag-search.php(raw semantic + keyword search). - LLM Server Inventory page (
/projects/llm-servers): three-column view of delphi, phoebe, and titan Ollama servers. Delphi is read-only (90+ models); phoebe and titan are remotely managed with pull/delete actions, streaming progress, VRAM bars, and suggested models for RTX 3060 (12GB). - Shared LLMClient.php updated to route through gateway (
https://llm.orcus.lan): all zap apps now get multi-server routing automatically. Handles gateway response envelope, SSL, server hints. - Updated
test-llm-models.php: fixed constructor call (was passing positional args, now uses config array). - Added
.htaccessroute:^llm-servers$ -> llm-servers.php - Added symlink:
web/public/projects/llm-servers.php - Added
demouser on cursor-demo.lan container (passworddemo, passwordless sudo)
* SSH key auth configured using paris.lan's ed25519 key (same key as orcus)
* Password auth also enabled in sshd as fallback
* Member of www-data group with write access to - paris.lan SSH config updated:
cursor-demo.lanentry added toC:\Users\jd\.ssh\config
with key-based auth (IdentityFile - Credentials updated: Added ADGUARD_USER/ADGUARD_PASS and DU2_SUDO_PASS to
~/.credentials - Updated README with users table and paris.lan access instructions
- New project: cursor-demo -- Ubuntu 22.04 LXC container (CT 301) on phoebe.lan for live Cursor coding demos * 2 cores, 1GB RAM, 8GB disk, static IP 192.168.2.50 * Pre-loaded dev stack: Git, Node 22 LTS, Python 3.10, PHP 8.1, Apache, SQLite * SSH key auth for jd, passwordless sudo, auto-start on boot * LAN access via
- Public access via reverse SSH tunnel: * New systemd service
- Registered as new project in zap-projects with slug
cursor-demo - Added AdGuard credentials placeholder to
~/.credentials(ADGUARD_USER/ADGUARD_PASS) - Added du2 sudo credentials placeholder to
~/.credentials(DU2_SUDO_PASS) - Note: Proxmox 8.2 on phoebe does not support Ubuntu 24.04 LXC templates; used 22.04 instead
- Added
.cursor/mcp.jsonto/var/www/zapworkspace -- was the only workspace of 7 missing the zap-projects MCP server config - All 7 orcus workspaces now have zap-projects MCP tools available
- Lazy-load plans with pagination: * Plans now load 50 at a time (matching chat pagination), with "Load more" button * Added
- Sticky tab selection: * Active tab (Chats/Plans) persisted to
- Plan viewer (NEW page): * Created
- Chat transcript viewer migrated to PostgreSQL: *
- Chat/plan link fixes: * Chat card/list hrefs changed from
- Plan count fix: *
- Docs reorganised: * Moved
- TESTING.md created (NEW): * Comprehensive testing guide covering 10 subsystems * Infrastructure health: systemd services, cron jobs, database connectivity/integrity, Apache, tunnel * Zap-Projects: web UI smoke tests, REST API tests (5 endpoints), MCP server verification, file watcher test, title sync, ingestion test * Zap-Writer: web UI, API tests, CLI engine dry-run * Recording system: tusd, TUS upload, recordings page, NAS storage * Authentication: login flow, API tests, admin panel, references existing auth testing doc * Messaging: page load, API, Centrifugo health * Multi-participant recording: host/guest pages, WebRTC connection * Shared libraries: LLMClient, SearchClient, PgClient * VPN fetch container: connectivity, status, downloaded data * Full-text search verification: chat FTS, plan FTS, cross-system search * Quick checklist for fast post-deployment sanity check
- Plan auto-indexing (FIX): * Plans were not being indexed into the database when created by Cursor -- the file watcher only ran
- Full-text search expansion: * Added
- Plan name extraction fix: *
- Cursor Hub UI improvements: * Plans list view now works (was rendering cards regardless of toggle) * Both chats and plans show "Started" and "Modified" datetimes with time (e.g. "17 Feb 15:40") *
- Zap-Writer app (NEW): * Full writing project management tool for editorial workflows * Database schema: 7 new tables (
- VPN fetch container (NEW): * Alpine Linux 3.23 LXC container on phoebe.lan (Proxmox CT 300, IP 192.168.1.19) * PIA VPN via WireGuard, exits through Miami FL (US IP) for PEMEX data access * Split-tunnel: LAN traffic stays local, only internet traffic goes through VPN *
- LLM model preferences (NEW): * Three-tier cascading system: task-level → project-level → platform-level defaults *
- Shared libraries: *
- Infrastructure: * Apache routing:
- MCP Windows path fix: Corrected global MCP config location from
%APPDATA%\Cursor\mcp.json(wrong) to%USERPROFILE%\.cursor\mcp.json(correct). Config verified working on paris.lan for all workspaces. - MCP architecture clarified: For SSH remote workspaces, project-level
.cursor/mcp.jsonon orcus is the primary mechanism (runs MCP server locally where the agent runs). Global config on Windows client shows as connected in UI but agent on remote side cannot reach it. Each orcus workspace now has its own project-level config. - Zap-Projects README rewritten: Complete overhaul -- now documents PostgreSQL database, web UI, REST API, all 7 MCP tools, full MCP setup process for new projects, troubleshooting guide (agent can't see tools, disabled duplicates, Windows path gotcha), and architecture diagram.
- Cross-chat context blocks updated across all projects: Philoenic, Philanthropy Planner, Prospecta, Prospecta.cc, and Quickstep READMEs now include standardised cross-chat context block pointing to zap-projects MCP tools and web UI.
- Zap README corrections: Database status updated from "Current: SQLite / Forthcoming: PostgreSQL" to "Current: PostgreSQL 17 / Legacy: SQLite". MCP section corrected with proper Windows path. File tree updated with full zap-projects structure.
- Cleaned up redundant project-level MCP configs: Removed all
.cursor/mcp.jsonfrom SSH remote workspaces, then restored them with local python3 command after discovering the global-only approach doesn't work for SSH remotes. - Cursor title sync from paris.lan (NEW): *
- Schema extensions (Postgres): *
- 4-tier title priority system: * display_title (user override) > cursor_title (paris.lan sync) > llm_title (deep analysis) > first_query_short (fallback) * Inline rename via pencil icon on Cursor Hub and project detail pages * LLM title drift detection in deep-analyse-chat.php
- Manual project creation: * POST /api/projects.php -- create projects with slug, aliases, match_patterns * New Project modal on projects index page * Project edit form now includes aliases (comma-separated) and match_patterns (one per line)
- Project-chat discovery: * Each project has configurable aliases and match_patterns * "Scan for material" button on project detail pages rescans all chats/plans against patterns * Ingest pipeline now checks new chats against all projects' match_patterns during ingestion * Seed script populates aliases for all 9 known projects
- UI enhancements: * Projects index: card/list toggle with localStorage persistence, search filter * Project detail: alias badges, rescan button, edit form with aliases/patterns * Cursor Hub: real Cursor titles, lines-changed stats, inline rename pencil icon
- MCP for all workspaces: * Global MCP config on paris.lan (
- ROADMAP.md updated with paris.lan sync as implemented capability
- Chat History System (complete): * Ingest script (
- Web Pages: * Chat history browser (
- Shared Infrastructure: *
- Systemd Unit Tracked: *
- Home Page Links: * Added "Zap-Projects: Chat History" card to Zap home page (
- Docs & Planning: * README updated with Zap-Projects section, current file structure * ROADMAP updated with Project Hub plan (Postgres migration, REST API, MCP server) * Project Hub plan created:
- Platform Vision Document: * Created
- Connect Page Added: * Added Connect page link to home page Main Pages section * Positioned as first entry (primary entry point) * Description explains unified interface that auto-detects role (host or guest) * Hosts can create sessions and manage recordings * Guests can join via invite links
- User Experience: * Connect page now easily discoverable from home page * Clear explanation of unified interface benefits * Primary badge indicates it's the recommended entry point
- Chat Participants List: * Replaced single "guest Live" display with participants list showing all session members * Shows Host (always Live) and Guest (Live/Offline based on connection) * Each participant displays name and status (Live in green, Offline in grey) * Supports truncation: shows "+X more" if more than 10 participants * Scrollable container (max-height: 200px) for many participants
- UI Improvements: * Removed "Full chat →" link from tabs area (not functional in this context) * Participants list styled with clean spacing and borders * Consistent participant item layout with name on left, status on right
- Code Improvements: * Created
- Sessions & Recordings Panel Tabs: * Split "Sessions & Recordings" into two separate tabs: "Sessions" and "Recordings" * Tabs styled similar to sidebar tabs (Contacts, Rooms, Groups) with Title case labels * Tab switching functionality matches sidebar tab behavior * Sessions tab shows list of recent sessions * Recordings tab shows recordings for selected session * Clicking a session automatically switches to Recordings tab and loads recordings
- Chat Tab Added: * Added "Chat" tab as leftmost tab in right panel (order: Chat, Sessions, Recordings) * Chat panel created with blank placeholder content ready for message functionality integration * Tab switching JavaScript handles all three tabs generically
- Sidebar Tab Styling: * Removed
- Code Improvements: * Updated sessions panel HTML structure to use tab-based layout * Added CSS for sessions panel tabs matching sidebar tab styling * Updated tab switching JavaScript to handle multiple tabs generically * Sessions panel list padding updated to match sidebar list padding
- Host Reconnect Button Fix: * Fixed host "Reconnect Remotes" button not properly cleaning up guest video element *
- Connect Page Auto-Detection: * Auto-defaults to host view if user is logged in with host permissions (no
- Navbar Access Control: * Host, Guest, Recordings, and Messages links now only visible to logged-in users with host permissions * Home, Connect, and Login remain visible to everyone * Admin link still only visible to admins * Cleaner navigation for anonymous users and non-host users
- Host Session UI Improvements: * Session UUID (database ID) now displayed separately from human-readable session name * Added "Copy UUID" and "Copy Invite" buttons next to "New Session" button * Copy UUID button copies the database UUID (not the session name) * Copy Invite button copies the full invite URL * Session header matches guest format: "Session: [session-id]" with "Session:" bold
- Recording Status and Button Fixes: * "Start Recording" button now correctly enables when both camera active and guest connected * Dynamic status messages accurately reflect camera and connection state * Status updates: "Your camera active, remote camera connected, ready to record" * Removed hardcoded status messages that overrode dynamic updates *
- TUS Upload Fix: * Fixed
- Code Improvements: * Added
- Header Layout Changes: * Changed "Guest Session" header to "Session: [session-id]" format * "Session:" is bold, session ID is normal weight (not emboldened) * Guest name moved to right side of header with "Your name:" label * Guest name displays inline as "Name (guest)" when prepopulated * Guest name is clickable to edit with tooltip "Click to change your name"
- Guest Name Persistence: * Fixed priority order: user edits (sessionStorage) now take precedence over invite/URL * Added
- Dynamic Status Messages: * Status now accurately reflects actual connection state * Shows "Your camera is off, remote host is not connected." format * Updates automatically when camera state or host connection changes * Replaced hardcoded "Connected. Waiting for host..." with dynamic status
- Recording File Names: * Guest name now included in all recording file names * Format:
- Connect Button: * Renamed "Reconnect" button to "Connect" * Moved to Host Video pane controls (alongside Camera On and Mute Audio buttons) * Styled to match other control buttons
- Code Improvements: * Created
- Guest Camera Controls: * Added "Camera On/Off" button under guest's camera pane (left side) * Guest camera defaults to off on page load, requires manual activation * Button state reflects camera status (Camera On when off, Camera Off when on) * Camera toggle functionality integrated with existing guest.js logic
- Guest Microphone Controls: * Added "Mute Mic" button under guest's camera pane * Button disabled until camera is active * Toggles guest microphone mute/unmute state * Button text and icon update based on mute state (Mute Mic / Unmute Mic)
- Host Audio Controls (Guest Side): * Added "Mute Audio" button under host video pane (right side) * Button disabled until host video stream is available * Allows guest to mute/unmute host's audio feed * Button text and icon update based on mute state (Mute Audio / Unmute Audio)
- UI Consistency: * Guest session controls now match host session layout and styling * All buttons use same CSS classes and structure as host session * Disabled button states properly styled for readability
- Code Improvements: * Added
- Auto-Redirect Guests: * Guests with invite links now skip role selection page and go directly to guest session * Role selection page only shown for logged-in users with host permissions * Invite lookup happens before role check to ensure data is available * Fallback allows guest access even if invite lookup fails (expired/used invites)
- Invite Data Preservation: * Added fallback database lookup to retrieve session_id and guest_name even for expired/used invites * Session ID now displays in header next to "Guest Session" title when available * Guest name pre-populates in input field from invite data * Improved error handling and debug logging for invite lookup issues
- Code Improvements: * Moved invite lookup before role selection logic * Added comprehensive console logging for debugging guest name and session ID issues * Better handling of edge cases (expired invites, used one-off invites)
- Sidebar Width Adjustment: * Increased sidebar width from 520px to 550px to accommodate full tab names * Fixed spacing between GROUPS tab and middle content area * Adjusted tab container padding and gap for better visual balance
- Toggle Button Text: * Updated toggle buttons to show "Open Contacts" / "Close Contacts" and "Open Sessions" / "Close Sessions" * Verb now precedes noun (e.g., "Open Contacts" instead of "Contacts Open") * Buttons correctly display state-based text (Open when collapsed, Close when open) * Added CSS for proper text visibility based on panel state
- Camera Controls: * Camera on/off buttons moved under each video pane (host and guest) * Mute mic button under host camera (disabled until camera is active) * Mute audio button under guest camera (disabled until host video stream available) * Camera button shows "Camera On" when off, "Camera Off" when on * All buttons properly initialized after DOM ready
- Camera Default State: * Camera now defaults to off on page load (no auto-activation) * Removed auto-camera activation code from DOMContentLoaded * Disabled queueAutoCameraActivation function * Users must manually click "Camera On" to activate
- UI Improvements: * Improved disabled button styling (better contrast, readable text) * Camera button text color explicitly set to white for better visibility * Font weight increased for camera buttons * Toggle buttons moved to header row between "Host Session" and "Logged in as" * Simplified "Logged in as" display (name only, or email if no name)
- Code Refactoring: * Refactored camera toggle initialization to use DOMContentLoaded * Created initializeCameraControls() function for proper setup * Removed duplicate/old camera toggle code * Fixed syntax errors in recorder.js
- Invite System: * Secure invite links with 32-character slugs for one-off and persistent sessions * One-off invites: Expire after 1 day (configurable), single-use by default * Persistent invites: No expiration, unlimited uses (configurable) * Guest name pre-filling from invite or URL parameter * Invite creation modal with contact/group linking * Invite lookup, revocation, and usage tracking * Public domain URLs for invites (orcus.getzap.co)
- Sidebar Component: * Left sidebar with Contacts, Rooms, and Groups tabs * Collapsible sidebar with toggle button (always visible) * Contact management (add, view, search) * Room management (view, create, join) * Group management (create, view members) * Integrated with invite creation form
- Sessions Management: * Session records created automatically when invites are created * Sessions displayed in Session Management section on host page * Right-hand panel for sessions & recordings (Option 2) * Recent sessions list with active/completed status * Session switching from both locations * Recordings section (placeholder for API)
- UI Layout Improvements: * Centered main content panel between sidebars * Toggle buttons aligned at same level as "Host Session" heading (80px from top) * Consistent spacing and positioning for left and right toggles * Responsive layout with proper flexbox centering
- Database Schema: * New tables:
- API Endpoints: *
- Repository Classes: *
- Admin Panel (
/admin.php):
* Access restricted to users with - Password Management: * One-time login codes (8 characters, valid for 12 hours) * Password reset via email (logs to
- User Registration (
/register.php):
* Registration form with email, display name, password
* Client-side validation (password match, length)
* Auto-login after successful registration
- Connect Page (
/connect.php):
* Role selection (host/guest) with auto-selection based on login status and permissions
* Host requires login and - Account Page (
/account.php):
* Profile information (email, display name, account created, last login)
* Permissions display (can host, can manage recordings, admin status)
* Password management (change password, reset password)
- Navbar Improvements: * User icon (👤) with dropdown menu * Dropdown shows user name and email * Account link in dropdown * Change Role option (only visible on connect page when role selected) * Logout moved to dropdown menu
- Database Migration: * Added
- API Endpoints: *
- Repository Updates: *
- Email Helper: *
- Files Created: *
- Database Migrations: * Created PostgreSQL
- Authentication System: *
- Dual-Write Migration: * Updated
- Documentation: *
- Next Steps (WIP): * Create
- Fixed messaging API 500 errors: * Installed
- Fixed duplicate messages: added deduplication checks in both
sendMessage()and Centrifugo subscription handler, checking bothserverMessageIdandclientMessageIdto prevent duplicates whether message arrives from API response or Centrifugo - Added auto-selection of most recently active room on page refresh: page now automatically restores the last selected room and loads its message history on load
- Updated README.md to confirm PostgreSQL database
zapexists and schema is applied (5 tables verified) - Provisioned PostgreSQL
zapdatabase (rolezap_user) with initial chat schema (database/migrations/2025-11-12-0001-chat-schema.sql) covering rooms, membership, messages, receipts, attachments - Added
web/bootstrap.phpto centralize Composer autoload + Dotenv load; updated existing Centrifugo APIs to use it - Implemented shared PDO connection (
web/src/Database/Connection.php) and chat repository (web/src/Chat/ChatRepository.php) for room setup, membership, history, read receipts - Created messaging API endpoints: *
- Built standalone
/messagespage with Teams/Skype-style layout, persistent room list, scrollback, send composer, and Centrifugo live updates; exposedZapMessagingAPIhelpers for reuse in host/guest sidebars - Documented new workflow in
README.md+design/zap_messaging_foundation.md, including.envusage and migration instructions - Stored production secrets only in gitignored
env/.env(no duplicate prod directory) - Created comprehensive home page (
index.php) with modern gradient UI, organized link cards for main pages and test pages, and system status section - Added sticky navbar component (
includes/navbar.php) with responsive design:
* Hamburger menu on small devices (≤375px, e.g., iPhone SE)
* Full menu on larger devices (tablets, large phones)
* Active page highlighting
* Gradient styling matching home page theme
- Integrated navbar into all main pages: home, host, guest, recordings
- Fixed mkcert CA warning logic: * Architecture:
- Updated README with detailed proxy/tunnel architecture documentation explaining request flow and certificate handling
- Host/guest field test (Win11 host ↔ MacBook guest) now produces fallback uploads on both sides via Centrifugo signalling
- Host fallback WebM missing audio; master muxes (
*-master.webm) absent for both participants pending investigation - Instrumented host camera toggle in
recorder.js(logs +cleanupHostWebRTC()on hide) to rule out stale WebRTC tracks starving MediaRecorder - Updated
README.mdandCODING_HISTORY.mdwith regression findings and next diagnostic steps - Status:
- Remaining work:
- Centrifugo Installation:
- Apache Proxy Configuration:
- Test Pages:
- Configuration:
- Files Changed:
- Next Steps:
- Signalling Architecture:
- WebSocket/SSE Implementation Attempts:
- Files Changed:
- Documentation:
- Architecture Fix:
- Rewrite Improvements:
- Testing:
- Files Changed:
- Infrastructure Changes:
- Known Issue:
- Camera Diagnostics:
- Documentation:
- Added
🔄 Reconnectbuttons to host and guest pages so either side can tear down and re-establish Centrifugo + WebRTC without refreshing the browser - Both buttons publish a
reconnect:requestevent so the opposite participant retries automatically; logs surfaceRECONNECT_*events for debugging - Centrifugo
signalnamespace now allows history reads for clients, reducing permission errors when recovering late joiners
windsurf-chat-capture.capture)
- Automatic capture via chat monitoring with heuristics
- Sends to Zap-Projects API with workspace detection
- Packaged as .vsix file for installationwindsurf-hook.php -- receives Cascade Hook events from Windsurf (pre_user_prompt, post_cascade_response)
- windsurf-manual-capture.php -- receives manual clipboard captures from extension
- windsurf-chats.php -- list/filter/search windsurf chats
- windsurf-plans.php -- list windsurf planswindsurf_chat_events -- raw hook events with trajectory_id tracking
- windsurf_chats -- aggregated chat records per conversation
- windsurf_chat_projects -- junction table for project associations
- Full-text search (tsvector) on user_prompt, cascade_response, summarywindsurf-capture-hook.py -- Python script receives JSON from Windsurf Cascade Hooks
- windsurf-capture-hook.bat -- Windows batch wrapper for Python script
- windsurf-hook-config.json -- Cascade Hook configuration template2026-02-24 19:00 UTC [database-backup-system]
##### Centralized database backup system with notifications and history tracking
orcus.lan/databases.php — local PostgreSQL + SQLite inventory with backup freshness indicators
- zap.orcus.lan/projects/databases.php — LAN-wide view (orcus + du1 + du2) with backup history and clickable file:// links to NAS folders
2026-02-23 19:57 UTC [video-with-messaging-v1]
##### Add zap-rag shared RAG service: design docs and research
2026-02-22 22:53 UTC [video-with-messaging-v1]
##### Hidden Money project: GDoc ingestion, RAG embeddings, multi-source search
2026-02-22 17:58 UTC [main]
##### LLM gateway integration + server inventory page
2026-02-19 13:30 UTC [video-with-messaging-v1]
##### Cursor Demo: demo user, key auth, paris.lan SSH config
/var/www/html
~/.ssh/id_ed25519, IdentitiesOnly yes)
2026-02-19 13:10 UTC [video-with-messaging-v1]
##### Cursor Demo LXC container and public access
cursor-demo.lan (registered in AdGuard DNS + orcus /etc/hosts)
orcus_cursor_demo_tunnel.service -- autossh tunnel to du2 on port 36004
* Apache vhost on du2 for cursor-demo.merlin-ai.com (CNAME to dev.merlin-ai.com -> 142.93.45.250)
* Let's Encrypt TLS certificate issued and deployed
* HTTP-to-HTTPS redirect configured
2026-02-19 11:39 UTC [video-with-messaging-v1]
##### Add zap-projects MCP config to zap workspace
2026-02-19 11:29 UTC [video-with-messaging-v1]
##### Cursor Hub: lazy-load plans, sticky tabs, fix chat/plan links, plan viewer
planOffset tracking variable, mirroring existing chatOffset for chats
* loadMore() now branches on active tab (chats vs plans)
* Filter changes and search reset planOffset to 0localStorage via existing prefs object
* Tab restored on page load; correct tab button highlighted at startup
* URL query param ?tab=plans overrides localStorage (for deep-linking)plan-viewer.php -- renders plan markdown as styled HTML using Parsedown
* Fetches plan from cursor_plans PostgreSQL table (fallback to disk)
* Displays metadata: name, created, modified, file size
* Back link "All Plans" now correctly returns to Plans tab (/projects/cursor?tab=plans)chat-transcript.php switched from SQLite to PgClient::connect() / PDO
* Table references updated: chats -> cursor_chats, chat_plans -> cursor_chat_plans, chat_deep_analysis -> cursor_chat_deep_analysis
* JSONB column handling added for apps_involved, topics, files_touched
* Back link updated from cursor-chat-history.php to /projects/cursor/projects/cursor-chat-transcript.php to /projects/chat-transcript.php
* Plans are now clickable -- both card and list items wrapped in tags pointing to plan-viewer
* Symlinks created for chat-transcript.php and plan-viewer.php in web public directoryplanTotal now reads from API data.total instead of allPlans.length
* Stats bar displays correct total (e.g. 449) even before all pages are loaded2026-02-19 10:39 UTC [video-with-messaging-v1]
##### Docs reorganisation: move to docs/, create TESTING.md
CHANGELOG.md, CODING_HISTORY.md, ROADMAP.md from repo root into docs/
* README.md stays in root (GitHub requirement)
* All internal references updated to docs/ paths
* Documentation section in README updated to list all docs with new paths2026-02-19 10:27 UTC [video-with-messaging-v1]
##### Fix plan indexing, FTS search expansion, Cursor Hub UI improvements
--single-chat mode which skips plan indexing
* Added --plans-only CLI mode to ingest-chat-transcripts.php (fast, ~3s for 446 plans)
* File watcher (watch-transcripts.sh) now watches /home/jd/.cursor/plans/ in addition to transcript directories
* .plan.md file events trigger --plans-only ingestion with 30-second debounce
* Systemd watcher service restarted to pick up new watch directoryfts_vector (tsvector + GIN index) to cursor_plans table -- plans now searchable via PostgreSQL FTS
* Expanded cursor_chats.fts_vector to include full_transcript (previously only first_query + summary) -- terms buried deep in transcripts (VPN, WireGuard, PIA) now searchable
* MCP server list_plans switched from broken ILIKE substring match to plainto_tsquery FTS
* Plans API (plans.php) updated to use FTS instead of ILIKE
* Searching "vpn pemex" now correctly returns 4 plans (previously 0)discoverPlans() now parses YAML frontmatter name field (falls back to filename-derived name)
* Upsert ON CONFLICT clause now updates name column (previously left stale names)
* Fixed 446 plans that had full content stored in the name column (up to 6KB per name)fmtDateTime() helper: "DD MMM HH:MM" for current year, "DD MMM YYYY HH:MM" for other years
* List view includes column headers (Title/Started/Modified/Msgs/Project for chats; Name/Created/Modified/Size for plans)
* Cards view shows "Started: ..." and "Modified: ..." in a dedicated date row2026-02-18 16:00 UTC [video-with-messaging-v1]
##### Zap-Writer app, VPN fetch container, LLM model preferences, shared libraries
writer_projects, writer_documents, writer_edits, writer_fact_checks, writer_currency_items, writer_bibliography, writer_charts)
* Web UI: project dashboard (/writer/), project workspace with tabbed interface (/writer/project/{slug})
* REST API: 14 endpoints for edits, fact-checks, currency, bibliography, charts, model preferences
* CLI engines: run-all-engines.php, ingest-bib-direct.php, fix-currency-gaps.php, run-currency-scan.php
* Mexico chapter: 78 edits ingested, 8 currency items assessed, 528 bibliography entries parsed, 10 charts inventoriedvpn-connect.sh: handles PIA token auth, WireGuard key registration, tunnel up/down
* fetch-pemex.sh: downloads PEMEX Anuario Estadistico PDFs (1977-2024 available)
* 10 Anuarios (2014-2024, 81MB) already downloaded and pushed to orcus at /APPS/energystats/pemex-downloads/
* Trigger from orcus: /APPS/energystats/bin/fetch-pemex-data.sh
* Registered as vpn-fetch.lan in AdGuard DNS, auto-starts on phoebe bootllm_model_preferences table in PostgreSQL with unique constraint on (scope, project_slug, task_category)
* LLMClient::getPreferredModel() resolves the cascade at runtime
* Admin UI at /admin/models with live Ollama model inventory and dropdown selectors
* Ollama on delphi.lan upgraded with paid plan (~90 models, including cloud-proxied kimi-k2.5, qwen3.5, glm-5)SearchClient.php -- tiered web search (SearXNG → Brave → Google), adapted from philoenic
* PgClient.php -- PostgreSQL connection wrapper
* LLMClient.php -- extended with getPreferredModel() cascade method
* cursor-rules.php -- shared Cursor Rules Viewer, accessible from /projects/rules and orcus.lan/rules.htaccess rules for /writer/, /admin/, /projects/rules
* Symlinks: web/public/writer/ → apps/zap-writer/web/, web/public/admin/models.php → writer models.php
* Web test files for writer API, VPN fetch, LLM models, search client2026-02-17 14:12 UTC [video-with-messaging-v1]
##### MCP setup fix, README overhaul, cross-project documentation
2026-02-17 13:35 UTC [video-with-messaging-v1]
##### Project Hub enhancements: title sync from paris.lan, manual projects, rescan, inline rename, MCP for all workspaces
scripts/sync-cursor-titles.php -- SSHes to paris.lan, reads Cursor's state.vscdb per workspace, syncs sidebar titles and metadata (lines added/removed, files changed, mode, archive status)
* Config at env/cursor-workspaces.json maps workspace hashes to project names
* Cron job every 5 minutes; first run synced 23 titles
* All title changes logged to cursor_chat_title_history tablecursor_chats: added cursor_title, display_title, llm_title, cursor_lines_added/removed, cursor_files_changed, cursor_subtitle, cursor_mode, cursor_archived, cursor_synced_at
* cursor_projects: added aliases (JSONB), match_patterns (JSONB)
* New table: cursor_chat_title_history (append-only log of all title changes from any source)
* Migration script updated for fresh installs%APPDATA%\Cursor\mcp.json) -- SSHes to orcus to run MCP server
* Project-level .cursor/mcp.json added to philoenic, philanthropy-planner, prospecta, prospecta.cc, quickstep
* Cursor rule zap-projects.mdc added to all project workspaces2026-02-17 10:18 UTC [video-with-messaging-v1]
##### Zap-Projects: chat history, deep analysis, file watcher, and project hub groundwork
scripts/ingest-chat-transcripts.php) -- scans Cursor agent-transcripts, extracts metadata, generates LLM summaries via delphi.lan
* Deep analysis script (scripts/deep-analyse-chat.php) -- structured JSON analysis of each chat (artifacts, decisions, unfinished work)
* File watcher (scripts/watch-transcripts.sh) -- inotify-based live monitoring of transcript directories, 120s debounce
* Systemd service (zap-chat-watcher.service) -- enabled, running, auto-restarts
* Cron job -- deep analysis every 30 minutes as safety net
* 23 chats indexed, 348 plan links, all with LLM summaries and deep analysis
apps/zap-projects/web/chat-history.php) -- FTS5 search, app/project filters, stats dashboard
* Chat transcript viewer (apps/zap-projects/web/chat-transcript.php) -- rendered transcripts with summaries, deep analysis, plan links
* Chat Ask AI (apps/zap-projects/web/chat-ask.php) -- LLM-powered Q&A across all chat history
* Energystats assets browser (apps/zap-projects/web/energystats-assets.php) -- asset inventory
* Pages symlinked from web/public/projects/
shared/libs/LLMClient.php -- reusable LLM client for Ollama on delphi.lan
* Energystats asset indexer (scripts/index-energystats-assets.php)
infra/systemd/orcus_zap-chat-watcher.service added to repo (was only in /etc/systemd/)
web/public/index.php)
* Added "Cursor Chats & Plans" card to orcus.lan dashboard
zap_project_hub_a03d3fc4.plan.md2026-02-15 13:33 UTC [video-with-messaging-v1]
##### Zap platform strategy document
design/zap-platform-strategy.md
* Consolidation plan: all Zap tools under getzap.co (/mail, /writer, /events, /projects)
* Three-tier LLM sender classification design for Zap-Mail
* Smart content alerts concept ("you should read this", event detection)
* Zap-Writer, Zap-Events, Zap-Projects component definitions
* Migration path: ProxyPass first, then unified codebase
* Implementation priority ordering2025-11-21 00:05 UTC [video-with-messaging-v1]
##### Home page updates
2025-11-20 18:28 UTC [video-with-messaging-v1]
##### Chat tab participants list and UI improvements
renderParticipants() method in chat-sessions.js to dynamically render participant list
* Updated showChatUI() to call renderParticipants() when chat is active
* Removed redundant connection status display (now shown in participants list)
* Updated CSS for participants list styling2025-11-20 15:27 UTC [video-with-messaging-v1]
##### Sessions & Recordings panel tabs and Chat tab addition
text-transform: uppercase from sidebar tabs CSS
* Sidebar tabs now display in Title case (Contacts, Rooms, Groups) to match Sessions/Recordings tabs
* Consistent styling across all tabs in the application
2025-11-20 14:15 UTC [video-with-messaging-v1]
##### Host reconnect fix, connect page auto-detection, and navbar improvements
cleanupHostWebRTC() now clears guest video srcObject and marks container as empty
* Matches guest "Connect" button behavior for consistent reconnection flow
* Guest video element properly cleared before reinitializing WebRTC connection
?role=host needed)
* Auto-detects guest role when session or invite parameters are present
* Shows helpful message for anonymous users: "Use your Invite URL or log in"
* Message explains two clear options: join with invite link or log in to host
* Simplifies user experience - guests with invites work automatically, hosts can just visit /connect
updateRecordingStatus() called after camera activation, guest stream changes, and WebRTC state changes
tus-hooks.php bootstrap path from ../../bootstrap.php to ../bootstrap.php
* Resolved recording upload failures with 500 errors from hook endpoint
* Uploads now successfully complete and trigger post-finish hooks
$canHost permission check to navbar component
* Created /api/session-uuid.php endpoint to fetch database UUID for session ID
* Updated useSession() function to handle both sessionId and sessionDbId
* Improved guest video cleanup in cleanupHostWebRTC() function
* Added conditional display logic for connect page welcome message2025-11-19 16:14 UTC [2b2d3c2] [video-with-messaging-v1]
##### Guest session UI improvements and name persistence
zap_guest_name_edited flag to track manual edits
* User-edited names persist across page refreshes
* Guest name stored in session metadata via new API endpoint
* URL updates when user edits name, but edited name takes priority on refresh
${sessionId}-${guestName}-master.webm and ${sessionId}-${guestName}-fallback.webm
* Guest name sanitized for filename safety (special chars replaced with _)
* Guest name passed to recorder constructors when starting recording
/api/guest-name-update.php endpoint to store guest name in session metadata
* Updated GuestMasterRecorder and GuestFallbackRecorder to accept guest name parameter
* Added updateConnectionStatus() function for dynamic status updates
* Improved guest name initialization logic with proper priority handling2025-11-19 12:58 UTC [fd9aa84] [video-with-messaging-v1]
##### Guest session camera and audio controls
toggleGuestMicBtn variable and initialization in guest.js
* Added guestMicMuted state tracking
* Implemented updateGuestMicButtonUI() and toggleGuestMic() functions
* Integrated mic button enable/disable logic with camera toggle2025-11-18 00:25 UTC [1f70a1e] [video-with-messaging-v1]
##### Guest invite flow improvements and UI enhancements
2025-11-16 20:06 UTC [719659c] [video-with-messaging-v1]
##### Sidebar spacing and toggle button improvements
2025-11-16 09:09 UTC [video-with-messaging-v1]
##### Camera controls and UI improvements
2025-11-15 23:11 UTC [video-with-messaging-v1]
##### Invite system, sidebar, sessions panel, and UI layout improvements
invites, contacts, groups, group_members, sessions
* Foreign key relationships and indexes
* Support for contact/group linking in invites
/api/invites-create.php - Create invite with session/room linking
* /api/invites-list.php - List invites for current user
* /api/invites-lookup.php - Lookup invite by slug
* /api/invites-revoke.php - Revoke unused invites
* /api/contacts-list.php - List contacts
* /api/groups-list.php - List groups
* /api/sessions-list.php - List sessions for current user
InvitesRepository - Invite CRUD operations
* ContactsRepository - Contact management
* GroupsRepository - Group management
* SessionsRepository - Session management2025-11-15 18:48 UTC [video-with-messaging-v1]
##### Admin panel, password management, and user experience improvements
is_admin = TRUE in database
* Create new users with temporary passwords (8-character alphanumeric)
* View all users with permissions and status
* Edit user permissions (can_host, can_manage_recordings)
* Temporary password display with show/hide eye icon and copy button
* User list shows email, display name, permissions, password change status, and last login
/var/www/zap/logs/emails.log for now)
* Random password generation on reset
* Password change required on first login with temp password
* Password change modal on login if required
* Login page supports both password and one-time code authentication
can_host permission
* Guest access without login (optional name input)
* Guest name support via URL parameter (?guest=John)
* Guest name stored in sessionStorage
* Replaced "Change Role" button with logged-in user display text
password_change_required, temporary_password_hash, one_time_code, one_time_code_expires_at, is_admin columns to users table
* Migration script: database/migrations/2025-01-20-0001-password-management.sql
/api/admin-users.php - List, create, update user permissions (admin only)
* /api/auth-register.php - User registration
* /api/auth-reset-password.php - Generate reset code and random password
* /api/auth-set-password.php - Change password
* Updated /api/auth-login.php - Handles one-time codes and password changes
UsersRepository - Added methods for password management, one-time codes, admin checks, user creation
* Session - Added admin and password change tracking
EmailHelper class logs emails to /var/www/zap/logs/emails.log
* Ready for SMTP integration later
web/public/admin.php - Admin panel
* web/public/account.php - Account settings page
* web/public/register.php - Registration page
* web/public/logout.php - Logout page
* web/public/api/admin-users.php - Admin user management API
* web/public/api/auth-register.php - Registration API
* web/public/api/auth-reset-password.php - Password reset API
* web/public/api/auth-set-password.php - Password change API
* web/src/Utils/EmailHelper.php - Email helper class
* database/migrations/2025-01-20-0001-password-management.sql - Password management schema---
2025-11-15 14:20 UTC [video-with-messaging-v1] (WIP)
##### Authentication foundation and dual-write migration
recordings table migration (2025-11-15-0001-recordings-schema.sql) - migrated from SQLite schema with UUID primary keys, timestamps, indexes
* Created PostgreSQL users and user_permissions tables migration (2025-11-15-0002-users-auth-schema.sql) - user accounts with role-based permissions (can_host, can_manage_recordings)
* Both migrations applied to zap database
web/src/Auth/Session.php - PHP session management helper (login, logout, permission checks, requireLogin/requireHost middleware)
* web/src/Auth/UsersRepository.php - User lookup by email/ID, permission checks, last login tracking
* web/public/api/auth-login.php - Login endpoint (POST, validates credentials, returns user + permissions)
* web/public/api/auth-logout.php - Logout endpoint (POST, destroys session)
* web/public/api/auth-check.php - Auth status check (GET, returns authenticated user or 401)
* Test user created: test@example.com / test123 (can_host: true, can_manage_recordings: true)
* Test page: /test-auth.html for browser-based authentication testing
tus-hooks.php to write recording metadata to both SQLite (legacy) and PostgreSQL (new)
* Idempotent writes prevent duplicates if hook called twice
* Graceful degradation: PostgreSQL errors don't break SQLite writes
* web/src/Recordings/RecordingsRepository.php - PostgreSQL recordings operations
docs/testing-auth-and-migration.md - Comprehensive testing guide for authentication and dual-write
* scripts/create-test-user.php - Script to create test users with permissions
/login.php page for user login
* Create /connect page with role selection (host/guest) and authorization checks
* Migrate existing SQLite data to PostgreSQL
* Switch reads from SQLite to PostgreSQL---
2025-11-15 11:25 UTC [messaging]
##### Messaging fixes: API errors, duplicate messages, state persistence
php8.3-intl extension (required for Composer)
* Installed Composer dependencies (vlucas/phpdotenv, etc.)
* Fixed .env file permissions (changed from 600 to 640, group www-data) so PHP-FPM can read database credentials
* Regenerated Composer autoloader
* Removed unnecessary use Throwable; statements from API files (Throwable is a built-in interface)
---
2025-11-14 12:55 UTC [signalling]
##### Messaging foundation: PostgreSQL schema + API endpoints + UI
POST /api/chat-send.php – validates input, persists message with idempotent clientMessageId, publishes to chat:room:{room_uuid} via Centrifugo
* GET /api/chat-history.php – paginated history with optional cursor
* POST /api/chat-read.php – upserts read receipts
* GET /api/chat-rooms.php – ensures session rooms + membership for host/guest
---
2025-11-12 13:40 UTC [signalling]
##### Home page and common navbar
orcus.getzap.co is proxied through du2 (Let's Encrypt) → SSH tunnel → orcus.lan → zap.orcus.lan vhost (mkcert)
* Warning only shows for direct access to zap.orcus.lan (local domain, mkcert)
* Hidden for orcus.getzap.co (public domain, Let's Encrypt) - detected via X-Forwarded-Host header
* mkcert CA certificate is installed on orcus.lan server; client machines need to install it to trust local certificates
---
2025-11-11 19:05 UTC [signalling]
##### Centrifugo regression: fallback-only recordings (WIP)
---
2025-11-10 15:21 UTC [signalling]
##### Centrifugo recorder integration (Phase 2 continuing)
* Apache proxy now forwards WebSocket Upgrade headers correctly; browsers connect via https://orcus.getzap.co/centrifugo/connection/websocket
* Host (recorder.js) and guest (guest.js) fetch JWTs, subscribe to signal:zap:session:{id}, and exchange record:start / record:stop / guest:status events
* WebRTC offer/answer/ICE signalling now published via Centrifugo with short-lived history replay (20 messages / 2 minutes) so late subscribers can retrieve the latest SDP
* PHP publish endpoint upgraded to accept generic {channel,data} payloads; CentrifugoClient allows extra metadata on start/stop/chat publishes
* Legacy /api/session-signal.php still retained as a fallback pending regression tests
* Exercise end-to-end recording sessions (host ↔ guest) over Centrifugo to confirm simultaneous start/stop and upload behaviour * Move Centrifugo secrets completely into environment/systemd so no placeholders leak into production configs
---
2025-11-10 14:05 UTC [signalling]
##### Centrifugo installation and configuration
* Installed Centrifugo v6.5.0 (Go-based real-time messaging server)
* Created config file at /etc/centrifugo/config.json (port 25001, localhost only)
* Fixed config format for v6.5.0 (nested objects: http_server.port, token_auth.hmac_secret_key, admin.enabled)
* Created systemd service: infra/systemd/orcus_centrifugo.service
* Deployed and started Centrifugo service (running on port 25001)
* Added Centrifugo proxy to Apache vhost (zap-subdomain-ssl.conf)
* Proxy path: /centrifugo/ → http://127.0.0.1:25001/
* WebSocket upgrade rules for Centrifugo connections
* Tested and verified: Centrifugo responding via Apache proxy
* Created test-centrifugo-host.html - Centrifugo connection test for host
* Created test-centrifugo-guest.html - Centrifugo connection test for guest
* Uses Centrifugo JS client library (CDN) for WebSocket connections
* TODO: Add JWT token generation for secure authentication
* Two namespaces configured: signal (no history) and chat (1-day history)
* API key and JWT secret configured (to be moved to environment variables)
* Admin interface enabled (insecure mode for testing)
* infra/centrifugo/config.json: Centrifugo configuration file * infra/systemd/orcus_centrifugo.service: Systemd service file * infra/apache/zap-subdomain-ssl.conf: Apache proxy configuration * web/public/test-centrifugo-host.html: Host test page * web/public/test-centrifugo-guest.html: Guest test page * design/zap_signalling_and_centrifugo.md: Centrifugo implementation details * design/zap_signalling_and_scaling.md: Scaling architecture discussion
* Create PHP CentrifugoClient class for publishing messages * Create JWT generator class for browser client authentication * Integrate Centrifugo into host/guest recording signalling * Move API key and JWT secret to environment variables
2025-11-10 00:32 UTC [main]
##### Signalling architecture discussion and WebSocket/SSE investigation
* Created design document: design/zap_signalling_architecture.md
* Documented investigation of real-time signalling solutions for simultaneous recording
* Evaluated options: SSE, PHP WebSocket, Centrifugo, EMQX/MQTT, Node.js
* Recommended solution: Centrifugo (Go-based WebSocket appliance)
* Centrifugo advantages: PHP-friendly, no Apache proxy issues, built-in presence/history
* Attempted SSE (Server-Sent Events) for real-time signalling
* SSE failed due to one-way nature and connection instability
* Switched to PHP WebSocket server (scripts/websocket-server.php)
* WebSocket handshake succeeds but Apache rejects Upgrade response
* Apache error: "AH00898: Unexpected Upgrade: websocket (expecting n/a)"
* Created test pages: test-ws-host.html, test-ws-guest.html for debugging
* Created session-signal API: web/public/api/session-signal.php for signalling
* design/zap_signalling_architecture.md: New architecture document * scripts/websocket-server.php: PHP WebSocket server implementation * web/public/api/session-signal.php: Signalling API endpoint * web/public/test-ws-host.html: WebSocket test page for host * web/public/test-ws-guest.html: WebSocket test page for guest * infra/apache/zap-subdomain-ssl.conf: WebSocket proxy configuration (attempted) * web/public/guest.js: Updated to use WebSocket for signalling * web/public/recorder.js: Updated to send recording commands via signalling * web/public/host-webrtc.js: Updated to use signalling API
* Updated README.md with signalling architecture section * Documented Centrifugo as recommended solution * Added known issue: Apache WebSocket proxy not working
2025-11-07 16:02 UTC [a6b7d3d] [main]
##### Fix clean URL rewrites via reverse SSH tunnel
* Created dedicated Apache vhost on port 36002 (zap-tunnel-proxy.conf) on orcus * This vhost proxies to internal https://zap.orcus.lan where rewrites work * Tunnel forwards du2:36002 → orcus:36002 (not port 443) * du2 proxy connects to http://localhost:36002 (HTTP, not HTTPS) * Avoids SNI conflicts - no ServerAlias localhost needed
* Universal rewrite rule: ^([a-zA-Z0-9_-]+)/?$ → $1.php
* No need to add separate rule for each URL
* Works for /host, /guest, and any future pages
* ✅ https://orcus.getzap.co/host?session=123 (200 OK) * ✅ https://orcus.getzap.co/guest?session=test (200 OK) * ✅ https://orcus.getzap.co/host.php (200 OK) * ✅ https://zap.orcus.lan/host (200 OK)
* infra/apache/zap-tunnel-proxy.conf: New proxy vhost on port 36002 * infra/systemd/orcus-tunnel.service: Forward 36002:36002 not 36002:443 * infra/apache/orcus-getzap-proxy-le-ssl.conf: Connect to http://localhost:36002 * infra/apache/zap-subdomain-ssl.conf: Universal rewrite rule
2025-11-07 11:01 UTC [e4a5c2c] [main]
##### Fix public URL access and add camera diagnostics
* Switch reverse SSH tunnel from HTTPS (port 443) to HTTP (port 80) to avoid SNI conflicts with multiple sites on du2 * Update orcus-tunnel.service: tunnel now forwards port 80 instead of 443 * Update orcus-getzap-proxy-le-ssl.conf on du2: proxy to http://localhost:36002 instead of https * Update zap-subdomain-ssl.conf on orcus: remove ServerAlias localhost (caused conflicts with concerts vhost) * Public URLs now work: https://orcus.getzap.co/host.php and https://orcus.getzap.co/guest.php
* Clean URL rewrites NOT working on public URL (/host, /guest return 404) * Rewrites work locally (https://zap.orcus.lan/host) but fail via tunnel * Workaround: use .php extension in URLs (/host.php?session=123) * Root cause: Apache rewrites on HTTP vhost (port 80) not being applied correctly
* Add scripts/check-camera-windows.ps1: PowerShell script to identify processes using camera on Windows 11 * Add scripts/check-camera-linux.sh: Bash script to identify processes using camera on Linux * Enhanced error messages in guest.js and recorder.js with better troubleshooting steps * Error messages now show available cameras/mics and platform-specific solutions
* Update README with correct tunnel architecture (HTTP not HTTPS) * Document du2 connection: ssh jd@orcus.getzap.co * Add Current Status section noting rewrite issues on public URL * Update troubleshooting commands for both orcus and du2 * Add file structure tree showing new scripts directory
2025-11-11 21:45 UTC [signalling]
##### Manual reconnect controls for host & guest