diff --git a/AGENTS.md b/AGENTS.md index 342f34f1..d289c0ce 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,6 +27,4 @@ and no restart. - `CONVENTIONS.md` — component organisation and React patterns, with rationale - `TODO.md` — current direction; takes precedence where it disagrees with anything else -The other Markdown files in this repo root (`OFFICERDEV_*.md`, `MARKETING_WEBSITE.md`, -`PHONE_APP.md`, `SECURITY_AUDIT.md`, `SETUP_*.md`, …) are older design notes and have not been kept -current. Treat the code as the source of truth. +Treat the code as the source of truth where anything disagrees with it. diff --git a/CLAUDE.md b/CLAUDE.md index 6e5f5315..c68c8b9b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,7 +3,7 @@ ## Project Overview Officer is a self-hosted personal platform for one person: the server owner. It bundles an AI agent, -a terminal, a file browser, a code editor, email, chat channels, a remote desktop and customisable +a terminal, a file browser, a code editor, email, a bitcoin wallet, a remote desktop and customisable dashboards behind a single web app. **Single-user is a hard invariant, not a stage.** There is exactly one account, created once by @@ -17,15 +17,16 @@ One Bun process (`src/server.tsx`) serves everything: - the React SPA, via Bun's HTML import of `src/apps/officer-web/index.html` (HMR in dev) - the REST API, a Hono app mounted at `/api` (`src/servers/hono.ts`) -- seven WebSocket providers — terminal, chat, task-runner, pipeline, cliamp, cliamp-audio, - desktop — plus the vault notifications hub and a sidecar registration socket +- eight WebSocket providers — terminal, chat, task-runner, pipeline, cliamp, cliamp-audio, desktop, + vault — plus a sidecar registration socket. `terminal` is a byte relay onto the pty sidecar's own + listener, not a translating bridge; `vault` is the same shape onto Vaultwarden's notifications hub. - a browser relay on its own port (`BROWSER_RELAY_PORT`, default 18792) Long-running and privileged work lives in **sidecars**: separate processes that dial back in over `/api/sidecar/register` and are tracked in `src/servers/sidecar-registry.ts`. PM2 runs them (`ecosystem.config.cjs`): `officer` (the server), `officer-anthropic-proxy`, `officer-agent`, `officer-opencode`, `officer-email`, `officer-pty`, `officer-vnc`, `officer-music`, `officer-vault`, -`officer-slskd`, `officer-headscale`, `officer-transmission`, `officer-invoiceshelf`. +`officer-slskd`, `officer-headscale`, `officer-transmission`, `officer-invoiceshelf`, `officer-wallet`. **`officer-anthropic-proxy` and `officer-agent` are not the same thing.** The proxy holds the Anthropic credential and forwards API traffic; the agent is the process that spawns `claude`. They were one entry @@ -48,7 +49,8 @@ src/ │ ├── hono.ts # router composition; everything under /api │ ├── _middlewares/ # auth, body parsing, origin validation, rate limiting │ ├── api// # one folder per feature, each exporting a router -│ ├── channels/ # Telegram / WhatsApp / Discord bridges +│ ├── channels/ # send-claude-code / send-opencode — how /chat drives an agent turn +│ ├── notify/ # outbound notifications (Discord webhook, env-configured) │ ├── queue/ # background job engine │ └── sidecar/ # sidecar implementations + the wire protocol ├── databases/officer_db/ # the only database (Postgres + Drizzle) @@ -83,8 +85,9 @@ email accounts, queue and pipeline jobs. Schema in `src/schema/`, hand-written q **The filesystem** holds everything the agent authors. `OFFICER_ITEMS_DIR` contains one directory per item under `skills/`, `tools/`, `tasks/`, `processes/`, `extensions/` — no database rows, no -scope tiers. `DATA_PATH//` holds the managed home, attachments and per-account email SQLite -stores. Path helpers live in `src/servers/data-path.ts`; note `getHomeDir` (the managed home under +scope tiers. `DATA_PATH//` holds the managed home, attachments and the per-account email SQLite +stores — those are the **email sidecar's**, and nothing in the platform opens them. Path helpers live in +`src/servers/data-path.ts`; note `getHomeDir` (the managed home under `DATA_PATH`) versus `getOwnerHomeDir` (the owner's real login home when `HOME_DIR` is set, which is where terminals, chats and task runs actually execute). @@ -245,12 +248,15 @@ link-focusable). Half the app still does this; none of the new code should. ## Further Reading -- `CONVENTIONS.md` — component organisation, state management, React patterns, with rationale - `docs/navigation-audit.md` — **authoritative** on routing/navigation: the opaque-click anti-pattern, a severity-ranked findings table, the channel-selection map and the four-phase plan +- `docs/sidecar-topology.md` — where the sidecar architecture is going, and what was considered and dropped +- `docs/working-on-officer.md` — how to run, restart and check your work on this machine +- `docs/wallet-key-custody.md` — what the platform can and cannot see of the wallet - `TODO.md` — current direction and deferred work; **takes precedence over this file where they disagree** - `src/apps/CLAUDE.md` — shared frontend patterns - `src/databases/CLAUDE.md` — database patterns +- `CONVENTIONS.md` — component organisation, state management and React patterns, with rationale; + `src/workspaces/officerdev/APP_CONVENTIONS.md` and `HOOK_CONVENTIONS.md` for panel apps and hooks -The other markdown files in the repo root (`OFFICERDEV_*.md`, `MARKETING_WEBSITE.md`, `PHONE_APP.md`, -`SECURITY_AUDIT.md`, `SETUP_*.md`, …) are older design notes. Treat the code as the source of truth. +Treat the code as the source of truth where anything here disagrees with it. diff --git a/MARKETING_WEBSITE.md b/MARKETING_WEBSITE.md deleted file mode 100644 index 2b4cb12a..00000000 --- a/MARKETING_WEBSITE.md +++ /dev/null @@ -1,716 +0,0 @@ -# Officer.dev Marketing Website Plan - -> Written by Claude for Claude. This document covers the full marketing website — structure, copy, visuals, and demo video plans. When resuming, read this first and walk the user through the strategy before building. - ---- - -## Table of Contents - -1. [Positioning & Messaging Strategy](#1-positioning--messaging-strategy) -2. [Site Map](#2-site-map) -3. [Page-by-Page Breakdown](#3-page-by-page-breakdown) -4. [Copy Bank](#4-copy-bank) -5. [Visual Identity for Marketing](#5-visual-identity-for-marketing) -6. [Demo Videos Plan](#6-demo-videos-plan) -7. [Technical Implementation](#7-technical-implementation) -8. [Launch Considerations](#8-launch-considerations) - ---- - -## 1. Positioning & Messaging Strategy - -### The Core Idea - -Officer is not a developer tool. It's not an AI chatbot wrapper. It's an **operating system** — a central place where AI does your repetitive work so you can do what matters. - -### Positioning Triangle - -``` - OFFICER - / \ - Easier More Powerful - than than - | | - OpenClaw Claude Work - (open source (polished but - but complex) locked down) -``` - -**vs. OpenClaw/Open Source AI tools**: "You shouldn't need a CS degree to use AI. Officer gives you the same power — with a UI your team actually wants to use." - -**vs. Claude Work/Enterprise AI**: "Enterprise AI is a walled garden. Officer is open source, self-hosted, and yours. No data leaves your servers unless you say so." - -**vs. Building it yourself**: "You could stitch together 15 tools and spend months on glue code. Or you could install Officer in five minutes." - -### Messaging Pillars - -| Pillar | For Individuals | For Companies | -|--------|----------------|---------------| -| **Automation** | "Automate your life. Have more time to live it." | "Every minute your team spends on repetitive work is a minute wasted." | -| **AI-Native** | "An AI that doesn't just chat — it acts." | "Give every employee an AI-powered workspace." | -| **Self-Hosted** | "Your data, your server, your rules." | "Enterprise-grade AI without enterprise-grade surveillance." | -| **Open Source** | "Built in the open. Extend it however you want." | "No vendor lock-in. No surprise pricing changes." | - -### Tagline Options - -**Primary (hero):** -> **Your AI-powered operating system — everywhere.** - -**Alternatives to test:** -> **Stop managing. Start living.** -> -> **The last tool you'll need.** -> -> **One platform. Everything automated.** - -**For the business/enterprise angle:** -> **What if your entire company ran itself?** -> -> **The company intranet that actually works.** -> -> **Fortunes are lost to repetitive work every day. Not anymore.** - -### Tone of Voice - -- **Confident but not arrogant** — we know what we are, we don't trash competitors -- **Clear and direct** — no jargon, no buzzword soup -- **Warm** — the duck mascot sets the tone. Serious product, friendly personality -- **Action-oriented** — every section should make you want to try it - ---- - -## 2. Site Map - -``` -officer.dev/ -├── / (Landing / Home) -├── /features -│ ├── /features/ai-assistant -│ ├── /features/file-management -│ ├── /features/automation -│ └── /features/workspaces -├── /pricing -├── /docs (external link to docs site) -├── /marketplace (coming soon / waitlist) -├── /enterprise -├── /open-source -├── /blog (future) -└── /about -``` - ---- - -## 3. Page-by-Page Breakdown - -### 3.1 Landing Page (Home) - -The landing page is the entire pitch in one scroll. It must convert three different audiences: individual users, small teams, and enterprises. - -#### Section 1: Hero - -``` -┌──────────────────────────────────────────────────┐ -│ │ -│ [Nav: Logo | Features | Pricing | Docs | GitHub]│ -│ [ Star on GitHub | Login]│ -│ │ -│ Your AI-powered operating │ -│ system — everywhere. │ -│ │ -│ Open source. Self-hosted. Free forever. │ -│ │ -│ [ Get Started — Free ] [ Watch Demo ▶ ] │ -│ │ -│ 🦆 (animated duck walks across) │ -│ │ -│ ┌──────────────────────────────────────────┐ │ -│ │ │ │ -│ │ (Hero product screenshot/video) │ │ -│ │ Dashboard with widgets + chat open │ │ -│ │ │ │ -│ └──────────────────────────────────────────┘ │ -│ │ -│ Trusted by developers at [logos if available] │ -│ │ -└──────────────────────────────────────────────────┘ -``` - -**Copy:** -- Headline: "Your AI-powered operating system — everywhere." -- Subheadline: "Open source. Self-hosted. Free forever." -- CTA Primary: "Get Started — Free" -- CTA Secondary: "Watch Demo" -- Background: landscape1.png with gradient overlay - -**Behavior:** -- Duck walks across the hero from right to left (CSS/JS animation, lightweight — not the 3D model) -- Product screenshot below the fold, slightly overlapping -- Subtle parallax on scroll -- GitHub stars badge updates live - -#### Section 2: The Problem - -``` -┌──────────────────────────────────────────────────┐ -│ │ -│ Every day, you... │ -│ │ -│ ┌────────┐ ┌────────┐ ┌────────┐ │ -│ │ Rename │ │ Organize│ │ Copy │ │ -│ │ 47 │ │ files │ │ data │ │ -│ │ files │ │ into │ │ between│ │ -│ │ │ │ folders │ │ apps │ │ -│ └────────┘ └────────┘ └────────┘ │ -│ │ -│ ┌────────┐ ┌────────┐ ┌────────┐ │ -│ │ Format │ │ Convert │ │ Search │ │ -│ │ reports│ │ formats │ │ through│ │ -│ │ │ │ │ │ docs │ │ -│ └────────┘ └────────┘ └────────┘ │ -│ │ -│ This isn't work. It's busywork. │ -│ And it costs more than you think. │ -│ │ -│ [$X,XXX per employee per year wasted] │ -│ │ -└──────────────────────────────────────────────────┘ -``` - -**Copy:** -- "Every day, you rename files. Organize folders. Copy data between apps. Format reports. Convert formats. Search through documents." -- "This isn't work. It's busywork." -- "And it's costing you more than you think." -- Animated counter or stat: estimated cost of repetitive work per employee/year - -#### Section 3: The Solution (Feature Overview) - -``` -┌──────────────────────────────────────────────────┐ -│ │ -│ Meet Officer. │ -│ │ -│ The platform that combines AI, file management, │ -│ automation, and workspaces into one self-hosted │ -│ operating system. │ -│ │ -│ ┌─────────────────────────────────────────┐ │ -│ │ │ │ -│ │ (Animated product showcase) │ │ -│ │ Cycling through: Chat → Files → │ │ -│ │ Automation → Dashboard │ │ -│ │ │ │ -│ └─────────────────────────────────────────┘ │ -│ │ -│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ -│ │ 🤖 │ │ 📁 │ │ ⚡ │ │ 🏠 │ │ -│ │ AI │ │Files │ │Auto- │ │Work- │ │ -│ │Assist│ │ │ │mate │ │space │ │ -│ └──────┘ └──────┘ └──────┘ └──────┘ │ -│ │ -└──────────────────────────────────────────────────┘ -``` - -**Four feature cards:** - -1. **AI Assistant** — "Not just chat. An AI that reads your files, runs your tasks, and gets things done." -2. **File Management** — "Your entire digital life in one place. Browse, preview, edit, convert, transcribe." -3. **Automation** — "Build workflows that run themselves. Tasks, cron jobs, pipelines — without writing code." -4. **Workspaces** — "Your desk, digitized. Combine any tool into a custom layout that fits how you work." - -Each card links to its feature detail page. - -#### Section 4: For You / For Your Team (Split Section) - -``` -┌──────────────────────────────────────────────────┐ -│ │ -│ ┌─────────────────┐ ┌─────────────────────┐ │ -│ │ │ │ │ │ -│ │ FOR YOU │ │ FOR YOUR COMPANY │ │ -│ │ │ │ │ │ -│ │ "Automate your │ │ "What if your │ │ -│ │ life. Have more │ │ entire team had an │ │ -│ │ time to live │ │ AI-powered intranet │ │ -│ │ it." │ │ that actually │ │ -│ │ │ │ worked?" │ │ -│ │ • Personal AI │ │ │ │ -│ │ assistant │ │ • Role-based access │ │ -│ │ • File organiz- │ │ • Shared workspaces │ │ -│ │ ation on │ │ • Company-wide │ │ -│ │ autopilot │ │ automation │ │ -│ │ • Smart dash- │ │ • Self-hosted: │ │ -│ │ board with │ │ your data stays │ │ -│ │ your goals │ │ on your servers │ │ -│ │ • Voice notes, │ │ • Plugin ecosystem │ │ -│ │ OCR, TTS │ │ for custom needs │ │ -│ │ │ │ │ │ -│ │ [Try Free →] │ │ [Enterprise →] │ │ -│ │ │ │ │ │ -│ └─────────────────┘ └─────────────────────┘ │ -│ │ -└──────────────────────────────────────────────────┘ -``` - -#### Section 5: How It Works - -``` -┌──────────────────────────────────────────────────┐ -│ │ -│ Up and running in 5 minutes. │ -│ │ -│ 1. Install │ -│ ┌──────────────────────────────────┐ │ -│ │ $ curl -fsSL install.officer.dev │ │ -│ │ | sh │ │ -│ └──────────────────────────────────┘ │ -│ One command. That's it. │ -│ │ -│ 2. Open your browser │ -│ Navigate to localhost:5000. │ -│ Create your admin account. │ -│ │ -│ 3. Start automating │ -│ Your AI assistant is ready. │ -│ Your files are connected. │ -│ Your first automation is one click away. │ -│ │ -│ [Get Started — Free] │ -│ │ -└──────────────────────────────────────────────────┘ -``` - -#### Section 6: Open Source & Community - -``` -┌──────────────────────────────────────────────────┐ -│ │ -│ Built in the open. Extended by everyone. │ -│ │ -│ Officer is open source under [LICENSE]. │ -│ Read every line. Modify anything. │ -│ Self-host for free, forever. │ -│ │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ -│ │ ⭐ │ │ 🔌 │ │ 🎨 │ │ -│ │ [count] │ │ Plugins │ │ Themes │ │ -│ │ GitHub │ │ Build & │ │ Make it │ │ -│ │ Stars │ │ share │ │ yours │ │ -│ └──────────┘ └──────────┘ └──────────┘ │ -│ │ -│ Marketplace coming soon. │ -│ Build plugins. Sell themes. Earn money. │ -│ │ -│ [Star on GitHub ⭐] [Join the community] │ -│ │ -└──────────────────────────────────────────────────┘ -``` - -#### Section 7: Pricing Preview - -``` -┌──────────────────────────────────────────────────┐ -│ │ -│ Simple pricing. No surprises. │ -│ │ -│ ┌──────────┐ ┌───────────┐ ┌──────────┐ │ -│ │ Self- │ │ Cloud │ │ Enter- │ │ -│ │ Hosted │ │ │ │ prise │ │ -│ │ │ │ │ │ │ │ -│ │ FREE │ │ $XX/mo │ │ Custom │ │ -│ │ forever │ │ per user │ │ │ │ -│ │ │ │ │ │ │ │ -│ │ Full │ │ Everything│ │ SLA, │ │ -│ │ features │ │ hosted & │ │ support, │ │ -│ │ Your │ │ managed │ │ custom │ │ -│ │ servers │ │ for you │ │ features │ │ -│ │ │ │ │ │ │ │ -│ │ [Install]│ │ [Start] │ │ [Talk] │ │ -│ └──────────┘ └───────────┘ └──────────┘ │ -│ │ -│ All plans include all features. │ -│ The only difference is who runs the server. │ -│ │ -└──────────────────────────────────────────────────┘ -``` - -**Key messaging**: "All plans include all features. The only difference is who runs the server." This is a powerful differentiator. No feature gating. - -#### Section 8: CTA / Footer - -``` -┌──────────────────────────────────────────────────┐ -│ │ -│ Ready to stop wasting time? │ -│ │ -│ [Get Started — Free] [Book a Demo] │ -│ │ -│ ───────────────────────────────────────────── │ -│ │ -│ officer.dev │ -│ Product: Features | Pricing | Docs │ -│ Community: GitHub | Discord | Blog │ -│ Company: About | Enterprise | Contact │ -│ │ -│ © 2026 Officer.dev │ -│ │ -└──────────────────────────────────────────────────┘ -``` - ---- - -### 3.2 Features Page (`/features`) - -Overview page with anchor-linked sections for each feature area. Each section has: -- Feature title & one-line pitch -- 3-4 bullet capabilities -- Embedded demo video or animated screenshot -- CTA to try it - -**Feature areas:** - -#### AI Assistant (`/features/ai-assistant`) -- Multi-provider (Claude, OpenCode, Pi-Mono) -- File-aware — reads, edits, and creates files -- Task-aware — runs automation on your behalf -- Voice input, image analysis, code understanding -- Session persistence across devices - -**Demo video**: Show a conversation where the user asks "organize my downloads folder by file type" and the AI does it, showing the file browser updating in real-time. - -#### File Management (`/features/file-management`) -- Browse, upload, download, search -- Built-in viewers: text, images, PDFs, audio, video -- AI-powered: OCR, text-to-speech, transcription, audio extraction -- Video transcoding for any format -- Archive extraction (zip, tar, 7z, rar) -- Git clone, yt-dlp download integration - -**Demo video**: Upload a photo of a receipt → OCR extracts the text → AI categorizes the expense. All in Officer. - -#### Automation (`/features/automation`) -- Tasks triggered by file type, schedule, or manually -- Workflows chaining multiple steps -- Cron jobs for recurring work -- Background processes -- Skills system — teach AI new capabilities - -**Demo video**: Show setting up a task that compresses images when they're uploaded to a specific folder. - -#### Workspaces (`/features/workspaces`) -- Multi-panel layouts -- Combine chat + files + any tool -- Save and switch between workspace configurations -- Create workspace templates for team - -**Demo video**: Building a "Content Creation" workspace with file browser on the left, AI chat in the middle, and preview on the right. - ---- - -### 3.3 Pricing Page (`/pricing`) - -Three tiers, feature-complete across all. The difference is hosting and support. - -**Self-Hosted (Free)** -- All features, unlimited users -- You host, you manage -- Community support (GitHub, Discord) -- "Perfect for developers, homelab enthusiasts, and teams who want full control." - -**Cloud (Subscription — $XX/user/month)** -- All features, unlimited -- We host and manage everything -- Automatic updates, backups, SSL -- Email support -- "For teams who want Officer without the DevOps." - -**Enterprise (Custom)** -- Everything in Cloud -- SLA with guaranteed uptime -- Priority support with dedicated account manager -- Custom feature development -- SSO/SAML integration -- Audit logging -- On-premises deployment assistance -- "For organizations that need enterprise-grade guarantees." - -**Below the pricing cards:** -- FAQ section (Is it really free? Can I migrate between plans? What about data portability?) -- "Need something custom?" → Contact form -- "Building plugins?" → Marketplace waitlist signup - ---- - -### 3.4 Enterprise Page (`/enterprise`) - -**Audience**: IT decision-makers, CTOs, operations managers. - -**Tone**: Professional, emphasizing reliability, security, and ROI. - -**Sections:** - -1. **Hero**: "The company intranet that works for you — literally." -2. **Problem**: "Your team uses 12 different tools. None of them talk to each other. Officer replaces the glue." -3. **Security**: "Self-hosted means your data never leaves your servers. Full audit logging. Role-based access. SOC 2 compliance roadmap." -4. **ROI Calculator**: Interactive widget — input team size, estimated hours on repetitive tasks → shows annual savings -5. **Consultancy**: "Our team builds custom integrations, plugins, and workflows tailored to your operations." -6. **Case studies**: (placeholder for future customer stories) -7. **CTA**: "Book a Demo" → Calendly or contact form - ---- - -### 3.5 Open Source Page (`/open-source`) - -**Audience**: Developers, contributors, plugin builders. - -**Sections:** - -1. **Hero**: "Built in the open. Extended by everyone." -2. **Why Open Source**: Philosophy statement — transparency, community ownership, no vendor lock-in -3. **Contributing**: Quick guide to getting started, link to CONTRIBUTING.md -4. **Plugin Development**: Overview of the plugin system, link to docs -5. **Marketplace Preview**: "Coming soon — build and sell plugins, themes, and automations. Earn money from your work." -6. **GitHub Stats**: Stars, forks, contributors, recent commits -7. **CTA**: "Star on GitHub" / "Join Discord" - ---- - -## 4. Copy Bank - -### Headlines (A/B test candidates) - -**Automation-focused:** -- "Your AI-powered operating system — everywhere." -- "Stop doing. Start automating." -- "The work that works itself." -- "Automate everything. Miss nothing." - -**For individuals:** -- "Your second brain. But it actually does things." -- "AI that doesn't just answer — it acts." -- "Automate your life. Have more time to live it." - -**For companies:** -- "What if your team's busywork just... disappeared?" -- "The company intranet that works for you — literally." -- "Fortunes are lost to repetitive work every day. Meet the fix." -- "Every employee deserves an AI assistant. Now they can have one." - -**Open source angle:** -- "Open source. Self-hosted. No strings attached." -- "Your data. Your server. Your AI." -- "The power of enterprise AI. The freedom of open source." - -### Social Proof (to collect/create) - -- GitHub stars count -- "Used by X developers/companies" -- Testimonials (collect after launch) -- "Featured in [publications]" (aim for Hacker News, ProductHunt, etc.) - -### Microcopy - -- Install CTA: "Get Started — Free" -- Cloud CTA: "Start your trial" -- Enterprise CTA: "Book a demo" -- GitHub CTA: "Star on GitHub" -- Newsletter CTA: "Get updates" -- Marketplace waitlist: "Join the waitlist" - ---- - -## 5. Visual Identity for Marketing - -### Design System Adaptation - -The product uses a duck-themed design (teal, yellow, forest green, glass-morphism with pixel grid). The marketing site should feel like the same brand but optimized for conversion: - -**Colors:** -- Primary: `#F4C430` (Duck Yellow) — CTAs, highlights -- Secondary: `#0891B2` (Duck Teal) — links, accents -- Dark: `#14532D` (Duck Dark) — text, headings -- Background: Soft cream/beige (`#F5F0E8`) or white with subtle grid texture -- Dark mode: Support it, matching the product's dark theme - -**Typography:** -- Headings: Bold, system-ui stack with the same skewed/3D shadow effect as the logo (but subtler for readability) -- Body: Clean sans-serif (Inter or system-ui), 18px base -- Code: Monospace for install commands and API examples - -**The Duck:** -- Hero: Subtle walking animation (lightweight 2D sprite or CSS, not the 3D model — save loading time) -- Scroll companion: Small duck that appears in corners, reacts to scroll -- 404 page: Lost duck illustration -- Loading states: Duck waddle animation - -**Photography/Visuals:** -- Product screenshots with the landscape backgrounds -- Minimal mockups (no fake Chrome windows — just clean screenshots with rounded corners and shadow) -- Feature diagrams: Simple, geometric, using brand colors - -**Grid Pattern:** -- Carry the pixel grid texture from the product into section backgrounds -- Use it subtly — don't overwhelm the content - -### Section Visual Hierarchy - -| Section | Background | Text Color | -|---------|-----------|------------| -| Hero | landscape1.png with dark overlay | White | -| Problem | White/cream | Dark green | -| Solution | Subtle grid pattern | Dark green | -| For You/Company | Split — light teal / light yellow | Dark | -| How It Works | White | Dark | -| Open Source | Dark (forest green) | Yellow/white | -| Pricing | White/cream | Dark | -| CTA | Teal gradient | White/yellow | - ---- - -## 6. Demo Videos Plan - -### Product Demo Reel (60s — for hero) - -A fast-paced showcase that cycles through the major features: - -| Time | Scene | Description | -|------|-------|-------------| -| 0-5s | Cold open | Tagline appears over landscape. Duck walks in. | -| 5-12s | Chat | User asks AI to "summarize all PDFs in my project folder." AI responds with tool use, result appears. | -| 12-20s | Files | File browser opens. User uploads files, previews images, plays audio. Quick montage. | -| 20-30s | Automation | User creates a task. It runs automatically. Toast notification: "Task complete." | -| 30-40s | Workspace | Multi-panel workspace assembles itself — chat + files + viewer. User drags to resize. | -| 40-48s | Dashboard | Widgets dashboard: clock, weather, goals getting checked off, pomodoro timer running. | -| 48-55s | Scale | "For you. For your team. For your company." — zoom out to show multiple users. | -| 55-60s | CTA | Logo + "Open source. Self-hosted. Free forever." + URL | - -### Feature-Specific Demos (30s each) - -**AI Assistant Demo:** -- Show real conversation with tool use -- AI reads a file, suggests changes, user approves -- Emphasis on the AI *doing things*, not just chatting - -**File Management Demo:** -- Upload → organize → preview → AI actions (OCR, transcribe) -- Show the breadth of file types supported -- yt-dlp download as a wow moment - -**Automation Demo:** -- Create a task that processes files automatically -- Show it triggering on file upload -- End with "Set it up once. It runs forever." - -**Workspaces Demo:** -- Start with empty screen -- Build a workspace: add chat, files, viewer -- Split panels, resize -- "Your desk. Your way." - -### Recording Guidelines - -- **Resolution**: 1920x1080 for landscape, 1080x1920 for portrait (social) -- **Browser**: Clean browser, no bookmarks bar, no extensions visible -- **Data**: Use realistic-looking sample data (not lorem ipsum) -- **Cursor**: Smooth, deliberate movements. No jitter. -- **Speed**: 1.5x natural speed for repetitive parts, real-time for "wow" moments -- **Music**: Upbeat instrumental for playful, ambient electronic for professional - ---- - -## 7. Technical Implementation - -### Stack Recommendation - -The marketing site should be **separate from the main monorepo** — it's a public website with different deployment, SEO, and performance requirements. - -**Recommended stack:** -- **Framework**: Astro (static-first, great SEO, supports React islands for interactive parts) -- **Styling**: Tailwind CSS (matches the product's design system) -- **Animations**: Framer Motion (for scroll-triggered animations) -- **Hosting**: Vercel or Cloudflare Pages (fast global CDN) -- **CMS**: Markdown files for blog posts (future) -- **Analytics**: Plausible or PostHog (privacy-friendly) - -**Alternative**: If the team prefers to keep everything in the monorepo's React ecosystem, a Next.js or Vite app could work. But Astro's static output and built-in SEO features make it better for a marketing site. - -### Project Location - -Create at `/home/pastilhas/projects/officer.dev/website/` — separate from the monorepo but within the project directory. - -### SEO Strategy - -**Target keywords:** -- "self-hosted AI platform" -- "open source AI assistant" -- "AI-powered intranet" -- "personal AI operating system" -- "self-hosted automation" -- "open source alternative to [Claude Work/Notion AI/etc.]" -- "AI file management" - -**Technical SEO:** -- Static HTML pages (Astro) -- Proper meta tags, OpenGraph images per page -- JSON-LD structured data -- Sitemap.xml -- Fast Core Web Vitals (landscape images need lazy loading + WebP conversion) - -### Performance Considerations - -- landscape1.png is 16MB — must be converted to WebP/AVIF and served responsive -- The 3D duck model (40MB total) should NOT be on the marketing site — use a lightweight 2D animation instead -- Use the rubber-duck.png (1.6MB) at reduced size for the duck character -- Lazy load everything below the fold - ---- - -## 8. Launch Considerations - -### Pre-Launch Checklist - -- [ ] Marketing site live with all sections -- [ ] Product demo video recorded and embedded -- [ ] GitHub repo public with README, CONTRIBUTING.md, LICENSE -- [ ] Installation script (`install.officer.dev`) working -- [ ] Documentation site (even minimal) live -- [ ] Discord/community channel created -- [ ] Social accounts created (Twitter/X, LinkedIn) -- [ ] ProductHunt launch page drafted -- [ ] Hacker News "Show HN" post drafted -- [ ] Email waitlist for cloud/marketplace - -### Launch Channels - -| Channel | Content | Timing | -|---------|---------|--------| -| Hacker News | "Show HN: Officer — open-source, AI-powered OS for automating your life" | Day 1 | -| ProductHunt | Full launch with screenshots, video, maker story | Day 1 | -| Reddit | r/selfhosted, r/homelab, r/opensource, r/artificial | Day 1 | -| Twitter/X | Thread: "I built an OS that automates my life. It's open source." | Day 1 | -| LinkedIn | Professional angle: "Every company wastes $X on repetitive work" | Day 2 | -| Dev.to / Hashnode | Technical deep-dive blog post | Week 1 | -| YouTube | Full demo video (5min) | Week 1 | - -### Post-Launch - -- Monitor GitHub issues and community channels -- Publish weekly blog posts (features, tutorials, philosophy) -- Start marketplace waitlist campaign -- Collect testimonials from early adopters -- Begin enterprise outreach - ---- - -## Appendix: Competitor Landscape - -| Product | What it is | Officer's advantage | -|---------|-----------|-------------------| -| **Notion** | Wiki + project management | Officer has AI that acts, not just organizes. Self-hosted. | -| **Obsidian** | Markdown knowledge base | Officer is broader — files, AI, automation, not just notes. | -| **Nextcloud** | Self-hosted file sync | Officer has native AI, automation, and workspaces. | -| **n8n** | Workflow automation | Officer combines automation with AI + file management + UI. | -| **Claude Work** | Enterprise AI chat | Officer is open source, self-hosted, and more extensible. | -| **OpenClaw** | Open source AI tools | Officer is friendlier, more polished, broader scope. | -| **Home Assistant** | Home automation | Different domain, but similar self-hosted philosophy. Potential integration. | - -Officer's unique position: **No one else combines AI + files + automation + workspaces in a single self-hosted platform.** That's the moat. diff --git a/MUSIC_API.md b/MUSIC_API.md index eb941bd1..d6431fd6 100644 --- a/MUSIC_API.md +++ b/MUSIC_API.md @@ -293,6 +293,24 @@ launch to offer "resume". --- +### Playlists + +Server-side playlists, scoped to the calling user. Items are track **keys** — the same +`/` strings favorites uses — so a playlist survives a reindex as long as the file stays +put. `404` throughout means "not yours or not there"; the two are deliberately indistinguishable. + +| method | path | body | returns | +|---|---|---|---| +| `GET` | `/api/music/playlists` | — | `[{ id, name, count, createdAt, updatedAt }]`, most recent first | +| `POST` | `/api/music/playlists` | `{ name }` | `201` with the row; `409` if the name is taken | +| `GET` | `/api/music/playlists/:id` | — | `{ id, name, items: [key], … }` | +| `PATCH` | `/api/music/playlists/:id` | `{ name }` | rename; `409` if taken | +| `DELETE` | `/api/music/playlists/:id` | — | deletes it, items cascade | +| `POST` | `/api/music/playlists/:id/items` | `{ keys: [] }` | append → `{ count }` | +| `PUT` | `/api/music/playlists/:id/items` | `{ keys: [] }` | replace the whole list → `{ count }` | + +`PUT` is how you reorder or remove: send the list you want, in order. There is no per-item delete. + ## Notes - **Covers are server-compressed** (≤600px / q5) — sync them as-is; no client-side resizing needed. diff --git a/PHONE_APP.md b/PHONE_APP.md deleted file mode 100644 index 661406d4..00000000 --- a/PHONE_APP.md +++ /dev/null @@ -1,1208 +0,0 @@ -# Officer Mobile App Plan - -> This document is written by Claude for Claude. It contains the full plan for native mobile apps (Kotlin/Android + Swift/iOS) for the Officer platform, based on a thorough study of the monorepo. When resuming this work, read this document first, then explain the plan to the user before starting implementation. - ---- - -## Table of Contents - -1. [Current Web App Summary](#1-current-web-app-summary) -2. [What to Include vs Exclude](#2-what-to-include-vs-exclude) -3. [Architecture Overview](#3-architecture-overview) -4. [Authentication](#4-authentication) -5. [Site Map](#5-site-map) -6. [Screen-by-Screen Breakdown](#6-screen-by-screen-breakdown) -7. [Tablet Adaptations](#7-tablet-adaptations) -8. [Technical Challenges](#8-technical-challenges) -9. [API Integration Notes](#9-api-integration-notes) -10. [Shared Design Language](#10-shared-design-language) -11. [Implementation Phases](#11-implementation-phases) - ---- - -## 1. Current Web App Summary - -Officer is an AI-assisted personal backend for life management. The web app (`officer-web`) is a React 19 SPA talking to a Hono API server (port 5000). Key features: - -| Feature | Description | -|---------|-------------| -| **Chat** | Multi-provider AI chat (Claude, OpenCode, Pi-Mono) via WebSockets. Sessions persisted as JSON files. Supports images, file attachments, model selection, working directory context. | -| **File Browser** | Full file manager with upload/download, rename, copy/move, search, archive extraction, git clone, yt-dlp download, OCR, TTS, transcription, audio extraction, video transcoding. Multiple "roots" (home, ~, officer.dev). | -| **Workspaces** | Multi-panel layouts combining chat, files, terminal, code editor. Panels can be split horizontally/vertically. State persisted per workspace. | -| **Terminal** | Sandboxed Docker terminals and host terminals (Super Admin). WebSocket-based PTY. | -| **Code Editor** | Text editor with syntax highlighting (PrismJS). | -| **Dashboard** | Widget panel (clock, weather, pomodoro, daily goals, quick notes) + workspace launcher + chat launcher. | -| **Automation** | Builder for workflows, pipelines, processes, services, cron jobs, tasks, skills. | -| **Tasks** | File-based task definitions (TASK.md) that can be triggered on files/directories. Native/global/user scopes. | -| **Skills** | AI skill library (SKILL.md files) injected into chat system prompts. | -| **Settings** | User profile, system settings, server resources, AI harness configuration. | -| **Auth** | Email/password + passkey (WebAuthn). JWT tokens. Role-based access (Member, Admin, Owner, Super Admin). | - -The API is at `/api/*` with JWT auth on all protected routes. WebSockets for chat (`/api/harness/*/ws`) and terminal (`/api/terminal/ws`). - ---- - -## 2. What to Include vs Exclude - -### Include (core mobile experience) - -| Feature | Rationale | -|---------|-----------| -| **Chat** | The #1 use case. Having an AI assistant in your pocket is the killer feature. Voice input makes it even better on mobile. | -| **File Browser** | Essential for viewing/managing files. Mobile adds camera upload, share sheet integration. Simplified but fully functional. | -| **Dashboard / Widgets** | Perfect for mobile - quick glance at clock, weather, goals, notes. Widget-style info is native to mobile platforms. | -| **Notifications** | Mobile-exclusive feature. Push notifications for chat completions, task results, long downloads finishing. | -| **Settings** | Profile, preferences. Subset of web settings. | -| **Session History** | Browse and resume past chat sessions. | -| **Quick Actions** | Share sheet integration (share URL/text/image to Officer for chat or file upload). | - -### Include (reduced scope) - -| Feature | What changes | -|---------|-------------| -| **File Viewer** | View files (text, images, PDFs, audio, video) but no full code editor. Read-only text with syntax highlighting. | -| **Tasks** | View and trigger tasks, see logs. No task creation/editing (too complex for mobile). | -| **Skills** | Browse skill library. No editing. | -| **Workspaces** | View workspace list, open a workspace (but as a single-panel experience, not multi-panel). | - -### Exclude (not suitable for phone) - -| Feature | Rationale | -|---------|-----------| -| **Terminal** | Typing shell commands on a phone keyboard is miserable. The sandboxed Docker terminal is a power-user web feature. | -| **Code Editor (write mode)** | Writing code on a phone is impractical. Read-only viewing with syntax highlighting is fine. | -| **Multi-panel workspaces** | Phone screens can't meaningfully split into panels. Tablet gets a simplified version (see section 7). | -| **Automation Builder** | Complex drag-and-drop/form-heavy workflow builder. Keep this web-only. | -| **Server/Resource Management** | Admin infrastructure management (installing databases, configuring services). Web-only. | -| **System Settings** | Server configuration, AI harness setup, plugin management. Web-only. | - -### Mobile-Exclusive Features (not on web) - -| Feature | Description | -|---------|-------------| -| **Push Notifications** | FCM (Android) / APNs (iOS) for chat completions, task results, downloads. | -| **Voice Input** | Native speech-to-text for chat messages. Much better than web speech API. | -| **Camera Integration** | Take photo and send to chat or upload to file browser directly. | -| **Share Sheet** | Receive shared content (URLs, text, images) from other apps. | -| **Biometric Auth** | Fingerprint/Face ID as alternative to passkey/password. | -| **Home Screen Widgets** | Android widgets / iOS widgets for quick notes, pomodoro, weather. | -| **Offline Queue** | Queue chat messages when offline, send when reconnected. | -| **Background Downloads** | File downloads and yt-dlp downloads continue in background. | - ---- - -## 3. Architecture Overview - -### Platform Strategy - -Two fully native apps sharing no code, but sharing identical: -- API contract (same REST + WebSocket endpoints) -- UX flows and information architecture -- Design language (adapted to each platform's conventions) - -``` -┌──────────────┐ ┌──────────────┐ -│ Android App │ │ iOS App │ -│ (Kotlin) │ │ (Swift) │ -│ │ │ │ -│ Jetpack │ │ SwiftUI │ -│ Compose │ │ │ -│ Material 3 │ │ Native iOS │ -│ │ │ Components │ -└──────┬───────┘ └──────┬───────┘ - │ │ - └────────┬───────────┘ - │ - ┌──────┴──────┐ - │ Officer API │ - │ (Hono) │ - │ port 5000 │ - └─────────────┘ -``` - -### Android Stack - -| Layer | Technology | -|-------|-----------| -| UI | Jetpack Compose + Material 3 | -| Navigation | Compose Navigation | -| Networking | Ktor Client (HTTP + WebSocket) | -| State | ViewModel + StateFlow | -| DI | Hilt | -| Storage | DataStore (preferences), Room (offline cache) | -| Images | Coil | -| Push | Firebase Cloud Messaging | -| Auth | BiometricPrompt API | -| Background | WorkManager | - -### iOS Stack - -| Layer | Technology | -|-------|-----------| -| UI | SwiftUI | -| Navigation | NavigationStack (iOS 16+) | -| Networking | URLSession + native WebSocket (URLSessionWebSocketTask) | -| State | @Observable (iOS 17+) / ObservableObject | -| DI | Swift native (Environment, protocol-based) | -| Storage | UserDefaults, SwiftData (offline cache) | -| Images | AsyncImage + custom cache | -| Push | APNs | -| Auth | LocalAuthentication (Face ID / Touch ID) | -| Background | BGTaskScheduler | - -### Minimum OS Versions - -- **Android**: API 26 (Android 8.0) - covers 95%+ of devices, gives us WorkManager, BiometricPrompt, etc. -- **iOS**: iOS 16 - gives us NavigationStack, modern SwiftUI features. iOS 17 for @Observable if we want it. - ---- - -## 4. Authentication - -### Flow - -``` -App Launch - │ - ├─ Has stored JWT? ──Yes──► Validate token (GET /api/auth/me) - │ │ - │ Valid? ──Yes──► Home Screen - │ │ - │ No ──► Login Screen - │ - └─ No ──► Login Screen - │ - ├─ Email/Password - │ POST /api/auth/signin - │ ► Store JWT securely - │ ► Home Screen - │ - ├─ Passkey (WebAuthn) - │ ► Platform passkey flow - │ ► Store JWT securely - │ - └─ Biometric Unlock (returning user) - ► Decrypt stored JWT - ► Validate & proceed -``` - -### Token Storage - -- **Android**: EncryptedSharedPreferences (AndroidX Security) -- **iOS**: Keychain Services - -### Biometric Integration - -On first successful login, offer to enable biometric unlock: -1. User logs in with email/password or passkey -2. App prompts: "Enable Face ID / Fingerprint for quick access?" -3. If yes: encrypt JWT with biometric-bound key, store in Keychain/Keystore -4. On next launch: biometric prompt → decrypt JWT → validate → proceed - -### Server URL Configuration - -The mobile app needs to know where the Officer API lives. First-launch flow: - -1. "Enter your Officer server URL" input -2. Validate by hitting `GET /api/server-settings/plugins` (public endpoint) -3. Store URL in app preferences -4. Proceed to login - -This is important because Officer is self-hosted - there's no central server. - ---- - -## 5. Site Map - -``` -App -├── Login -│ ├── Server URL Setup (first launch) -│ ├── Email/Password -│ ├── Passkey -│ └── Biometric Unlock -│ -├── Home (Tab 1) -│ ├── Widget Dashboard -│ │ ├── Clock -│ │ ├── Weather -│ │ ├── Pomodoro Timer -│ │ ├── Daily Goals -│ │ └── Quick Notes -│ └── Workspace Quick Access -│ -├── Chat (Tab 2) -│ ├── Session List -│ │ ├── Active Sessions -│ │ └── Archived Sessions -│ ├── New Chat -│ └── Chat Session -│ ├── Message Thread -│ ├── Model Selector -│ ├── Image Attachment -│ ├── Voice Input -│ └── Tool Use Display -│ -├── Files (Tab 3) -│ ├── Directory Browser -│ │ ├── Grid/List View -│ │ ├── Search -│ │ ├── Sort/Filter -│ │ └── Context Actions -│ │ ├── Open/Preview -│ │ ├── Share -│ │ ├── Rename -│ │ ├── Copy/Move -│ │ ├── Delete -│ │ ├── Download to Device -│ │ └── Upload (camera, gallery, files) -│ └── File Viewer -│ ├── Text (syntax highlighted, read-only) -│ ├── Image -│ ├── PDF -│ ├── Audio Player -│ ├── Video Player -│ └── AI Actions (OCR, TTS, Transcribe) -│ -├── Activity (Tab 4) -│ ├── Task List -│ │ ├── Native Tasks -│ │ ├── Global Tasks -│ │ └── User Tasks -│ ├── Task Logs -│ └── Running Processes -│ -└── Settings (Tab 5 / Profile) - ├── Profile - │ ├── Name, Username, Avatar - │ ├── Password Change - │ └── Passkey Management - ├── App Preferences - │ ├── Theme (Light/Dark/System) - │ ├── Notification Settings - │ ├── Default Chat Model - │ ├── Biometric Lock - │ └── Server URL - └── About / Logout -``` - -### Navigation Pattern - -**Bottom Tab Bar** with 4 primary tabs + profile access: - -``` -┌─────────────────────────────────────┐ -│ │ -│ [Screen Content] │ -│ │ -├─────┬─────┬─────┬─────┬────────────┤ -│ Home│ Chat│Files│ Act.│ Settings │ -│ 🏠 │ 💬 │ 📁 │ ⚡ │ ⚙️ │ -└─────┴─────┴─────┴─────┴────────────┘ -``` - -- **Home**: Dashboard with widgets -- **Chat**: Session list → chat view -- **Files**: File browser → file viewer -- **Activity**: Tasks, logs, processes -- **Settings**: Profile and preferences - -On Android: Material 3 NavigationBar. On iOS: UITabBarController / SwiftUI TabView. - ---- - -## 6. Screen-by-Screen Breakdown - -### 6.1 Login Screen - -``` -┌─────────────────────────┐ -│ │ -│ [Officer Logo] │ -│ │ -│ ┌───────────────────┐ │ -│ │ Server URL │ │ ← Only on first launch or -│ └───────────────────┘ │ tap "Change server" -│ │ -│ ┌───────────────────┐ │ -│ │ Email │ │ -│ └───────────────────┘ │ -│ ┌───────────────────┐ │ -│ │ Password │ │ -│ └───────────────────┘ │ -│ │ -│ [ Sign In ] │ -│ │ -│ ── or ── │ -│ │ -│ [ Sign in with Passkey ] │ -│ │ -│ Forgot password? │ -│ │ -└─────────────────────────┘ -``` - -**Behavior:** -- Server URL field shown on first launch or when tapped -- Email/password fields with proper keyboard types -- "Sign in with Passkey" triggers platform WebAuthn flow -- On success: store JWT, navigate to Home -- On returning user with biometric enabled: show biometric prompt immediately, with "Use password instead" fallback - ---- - -### 6.2 Home / Dashboard - -``` -┌─────────────────────────┐ -│ Officer [Avatar]│ -├─────────────────────────┤ -│ │ -│ ┌──────┐ ┌──────────┐│ -│ │ 14:32│ │ Weather ││ -│ │ Fri │ │ 22° ☀️ ││ -│ └──────┘ └──────────┘│ -│ │ -│ ┌──────────────────┐ │ -│ │ 🍅 Pomodoro │ │ -│ │ 18:42 remaining │ │ -│ │ [Start] [Reset] │ │ -│ └──────────────────┘ │ -│ │ -│ ┌──────────────────┐ │ -│ │ Daily Goals │ │ -│ │ ☑ Exercise │ │ -│ │ ☐ Read 30min │ │ -│ │ ☐ Journal │ │ -│ │ [+ Add goal] │ │ -│ └──────────────────┘ │ -│ │ -│ ┌──────────────────┐ │ -│ │ Quick Notes │ │ -│ │ Tap to add... │ │ -│ └──────────────────┘ │ -│ │ -│ Workspaces │ -│ ┌────┐ ┌────┐ ┌────┐ │ -│ │ WS1│ │ WS2│ │ WS3│ │ -│ └────┘ └────┘ └────┘ │ -│ │ -└─────────────────────────┘ -``` - -**Behavior:** -- Scrollable vertical layout -- Widgets are cards that can be reordered (long-press drag) -- Widget data syncs with web app via user settings API -- Workspace cards show name + icon, tap opens workspace (single-panel mode on phone) -- Pull-to-refresh updates widget data -- Avatar tap opens Settings - -**Widget Implementation:** -- Clock: Local device time (no API needed) -- Weather: Can use device location + weather API, or sync from web app settings -- Pomodoro: Local timer with state synced to server (so it persists across devices) -- Daily Goals: Stored in user settings, synced -- Quick Notes: Stored in user settings, synced - ---- - -### 6.3 Chat - Session List - -``` -┌─────────────────────────┐ -│ Chat [+ New]│ -├─────────────────────────┤ -│ [🔍 Search sessions...] │ -├─────────────────────────┤ -│ │ -│ Today │ -│ ┌──────────────────┐ │ -│ │ 🤖 Debug login │ │ -│ │ Claude · 2h ago │ │ -│ │ Last: "The issue │ │ -│ │ was in the..." │ │ -│ └──────────────────┘ │ -│ ┌──────────────────┐ │ -│ │ 🤖 Refactor API │ │ -│ │ Pi-Mono · 5h ago │ │ -│ │ Last: "I've upda- │ │ -│ │ ted the router..." │ │ -│ └──────────────────┘ │ -│ │ -│ Yesterday │ -│ ┌──────────────────┐ │ -│ │ 🤖 Recipe ideas │ │ -│ │ Claude · 1d ago │ │ -│ └──────────────────┘ │ -│ │ -│ Archived ▸ │ -│ │ -└─────────────────────────┘ -``` - -**Behavior:** -- Sessions fetched from `GET /api/sessions?provider=all` -- Grouped by date (Today, Yesterday, This Week, Older) -- Each card shows: session name, provider icon, time, last message preview -- Swipe left to delete, swipe right to archive -- Long-press for context menu (rename, archive, delete) -- "Archived" section expandable -- Search filters sessions by name -- FAB or top-right button for new chat - -**Data Source:** -- `GET /api/sessions?provider=claude` (and opencode, pi-mono) -- Sessions are JSON files on the server, API returns metadata -- Message preview from last assistant message - ---- - -### 6.4 Chat - Conversation - -``` -┌─────────────────────────┐ -│ ← Debug login [···] │ -│ Claude 3.5 Sonnet ▾ │ -├─────────────────────────┤ -│ │ -│ ┌─ You ────────────┐ │ -│ │ The login page │ │ -│ │ throws a 401... │ │ -│ └──────────────────┘ │ -│ │ -│ ┌─ Claude ─────────┐ │ -│ │ Looking at the │ │ -│ │ auth middleware... │ │ -│ │ │ │ -│ │ ┌─ Tool Use ────┐ │ │ -│ │ │ 📄 Read file │ │ │ -│ │ │ auth/jwt.ts │ │ │ -│ │ └──────────────┘ │ │ -│ │ │ │ -│ │ The issue is in │ │ -│ │ the token verify │ │ -│ │ ```ts │ │ -│ │ if (!jti) ... │ │ -│ │ ``` │ │ -│ └──────────────────┘ │ -│ │ -├─────────────────────────┤ -│ ┌───────────────┐ 📎 🎤│ -│ │ Message... │ [Send]│ -│ └───────────────┘ │ -└─────────────────────────┘ -``` - -**Behavior:** -- WebSocket connection to `/api/harness/{provider}/ws` -- Messages stream in real-time (assistant:partial → assistant:text) -- Tool use blocks shown as collapsible cards (collapsed by default) -- Code blocks with syntax highlighting and copy button -- Markdown rendering for assistant messages -- Model selector dropdown in the header (or a bottom sheet) -- Attachment button (📎) opens picker: Camera, Photo Library, Files -- Microphone button (🎤) for voice input (speech-to-text → send as text) -- Send button disabled while assistant is generating -- "Stop" button appears during generation -- Pull-down to load older messages (if session has many) -- `[···]` menu: Rename session, View in files, Delete, Share - -**WebSocket Message Protocol:** -``` -Client sends: - { type: 'chat', prompt, sessionId, model, images?, attachmentIds? } - { type: 'resume', sessionId } - { type: 'stop' } - -Server sends: - { type: 'session:init', sessionId, name } - { type: 'assistant:partial', text } - { type: 'assistant:text', text } - { type: 'tool:use', name, input } - { type: 'tool:result', result } - { type: 'result', cost?, duration?, turns? } - { type: 'error', message } - { type: 'stopped' } -``` - -**Offline Behavior:** -- If offline when sending, queue message locally -- Show "Queued - will send when online" indicator -- On reconnect, send queued messages in order -- Previously loaded messages remain visible offline (cached in local DB) - -**Voice Input:** -- Tap and hold microphone for continuous recording -- Or tap once to start, tap again to stop -- Platform native speech recognition -- Transcribed text placed in input field for review before sending -- User can edit before sending - ---- - -### 6.5 Files - Directory Browser - -``` -┌─────────────────────────┐ -│ ← Files [···] │ -│ / > Documents > Work │ -├─────────────────────────┤ -│ [🔍 Search files...] │ -├─────────────────────────┤ -│ Sort: Name ▾ [≡] [⊞] │ -├─────────────────────────┤ -│ │ -│ 📁 Projects → │ -│ 📁 Reports → │ -│ 📄 notes.md 3KB │ -│ 🖼️ photo.jpg 1.2MB │ -│ 🎵 song.mp3 4.5MB │ -│ 📹 demo.mp4 45.2MB │ -│ 📦 backup.zip 12.0MB │ -│ │ -│ [+ Upload] │ -│ │ -└─────────────────────────┘ -``` - -**Behavior:** -- Breadcrumb navigation at top (scrollable horizontal) -- Tap folder to navigate in, tap file to open viewer -- Long-press for context menu: - - Open / Preview - - Share (native share sheet) - - Rename - - Copy / Move (enter selection mode) - - Delete - - Download to device - - AI actions (OCR, TTS, Transcribe - based on file type) -- Pull-to-refresh -- FAB or bottom button for upload (Camera, Photo Library, Files picker) -- Multi-select mode (long-press first item, then tap others) -- Swipe actions: left = delete, right = share -- Grid/List view toggle -- Sort by name/date/size -- Search with debounce (calls `/api/file-browser/search`) - -**Root Selection:** -- Dropdown or segmented control at top for root selection -- Only show non-home roots for Super Admin users -- Default to "home" - -**Upload Sources:** -- Device file picker -- Camera (take photo) -- Photo library -- Share sheet (from other apps) -- Drag & drop (tablet only) - ---- - -### 6.6 Files - File Viewer - -``` -┌─────────────────────────┐ -│ ← notes.md [↗] [···]│ -├─────────────────────────┤ -│ │ -│ # Meeting Notes │ -│ │ -│ ## Action Items │ -│ - Fix login bug │ -│ - Update docs │ -│ - Review PR #42 │ -│ │ -│ ## Discussion │ -│ We talked about the │ -│ new mobile app and... │ -│ │ -│ │ -│ │ -│ │ -└─────────────────────────┘ -``` - -**Viewer Types:** - -| File Type | Viewer | Notes | -|-----------|--------|-------| -| `.md` | Rendered Markdown | With proper styling | -| `.txt`, `.json`, `.ts`, `.js`, etc. | Syntax-highlighted text | Read-only, with line numbers | -| `.jpg`, `.png`, `.gif`, `.svg`, `.webp` | Image viewer | Pinch to zoom, pan | -| `.pdf` | PDF viewer | Native PDF rendering | -| `.mp3`, `.wav`, `.flac`, `.ogg` | Audio player | Play/pause, seek, speed control | -| `.mp4`, `.webm`, `.mov` | Video player | Native player, fullscreen support | -| `.mkv`, `.avi` | Video player (transcoded) | Uses `/api/file-browser/transcode` endpoint | -| Other | Download prompt | "This file type can't be previewed. Download?" | - -**Header Actions:** -- [↗] Share via native share sheet -- [···] Menu: Download to device, AI actions (contextual), Open in chat, Delete - -**AI Actions (contextual):** -- Images: OCR (extract text) -- Text files: TTS (read aloud) -- Audio/Video: Transcribe -- Video: Extract audio - ---- - -### 6.7 Activity - -``` -┌─────────────────────────┐ -│ Activity │ -├─────────────────────────┤ -│ [Tasks] [Logs] [Procs] │ -├─────────────────────────┤ -│ │ -│ Native Tasks │ -│ ┌──────────────────┐ │ -│ │ 📋 Format Code │ │ -│ │ Formats source │ │ -│ │ files with... │ │ -│ │ [Run ▶] │ │ -│ └──────────────────┘ │ -│ ┌──────────────────┐ │ -│ │ 📋 Compress Imgs │ │ -│ │ Optimizes image │ │ -│ │ files in... │ │ -│ │ [Run ▶] │ │ -│ └──────────────────┘ │ -│ │ -│ User Tasks │ -│ ┌──────────────────┐ │ -│ │ 📋 Backup DB │ │ -│ │ Runs pg_dump... │ │ -│ │ [Run ▶] │ │ -│ └──────────────────┘ │ -│ │ -└─────────────────────────┘ -``` - -**Tabs:** -1. **Tasks**: List of available tasks (native/global/user). Each shows name, description, trigger types. "Run" button opens a sheet to select target file/directory. -2. **Logs**: Recent task execution logs. Each shows task name, status (success/failure), timestamp, duration. Tap to see full log output. -3. **Processes**: Currently running background processes. Show name, status, uptime. No start/stop controls (too dangerous on mobile - manage via web). - -**Task Runner:** -- When "Run" is tapped, show a bottom sheet: - - Select target file/directory (mini file browser) - - Confirm and run - - Show real-time output in a scrollable log view - - Toast on completion - ---- - -### 6.8 Settings - -``` -┌─────────────────────────┐ -│ Settings │ -├─────────────────────────┤ -│ │ -│ ┌──────────────────┐ │ -│ │ 👤 John Doe │ │ -│ │ john@example.com │ │ -│ │ Super Admin │ │ -│ └──────────────────┘ │ -│ │ -│ Profile │ -│ Name, Username, Avatar │ -│ Change Password → │ -│ Passkeys → │ -│ │ -│ ───────────────────── │ -│ │ -│ App │ -│ Theme System │ -│ Notifications → │ -│ Default Model Claude │ -│ Biometric Lock [🔘] │ -│ │ -│ ───────────────────── │ -│ │ -│ Connection │ -│ Server 192.168.1.5 → │ -│ Status Connected 🟢│ -│ │ -│ ───────────────────── │ -│ │ -│ [ Sign Out ] │ -│ │ -│ Officer v1.0.0 │ -│ │ -└─────────────────────────┘ -``` - -**Sections:** -1. **Profile card**: Avatar, name, email, role. Tap to edit. -2. **Profile**: Name/username editing, avatar upload (camera or gallery), password change, passkey management. -3. **App**: Theme (light/dark/system), notification preferences, default chat model/provider, biometric lock toggle. -4. **Connection**: Current server URL (editable), connection status indicator, last sync time. -5. **Sign Out**: Clears JWT, biometric keys, navigates to login. - ---- - -## 7. Tablet Adaptations - -Tablets (iPad, Android tablets/foldables) get an enhanced layout while using the same app binary. Detection via screen width: -- **Phone**: < 600dp (Android) / Compact (iOS) -- **Tablet**: >= 600dp (Android) / Regular (iOS) - -### 7.1 Navigation - -**Phone**: Bottom tab bar (5 tabs) -**Tablet**: Side navigation rail (Android) / Sidebar (iOS) - -``` -Tablet Layout: -┌────┬──────────────────────────────┐ -│ │ │ -│ 🏠 │ │ -│ 💬 │ [Main Content] │ -│ 📁 │ │ -│ ⚡ │ │ -│ │ │ -│ │ │ -│ ⚙️ │ │ -└────┴──────────────────────────────┘ -``` - -### 7.2 Chat on Tablet - -**Split view**: Session list on left (1/3), conversation on right (2/3). - -``` -┌────┬──────────┬───────────────────┐ -│ │Sessions │ Debug login │ -│ 🏠 │──────────│ Claude 3.5 Sonnet │ -│ 💬 │ Debug.. │───────────────────│ -│ 📁 │ Refact.. │ │ -│ ⚡ │ Recipe.. │ [Messages...] │ -│ │ │ │ -│ │ │ │ -│ │ ├───────────────────│ -│ ⚙️ │ │ [Input] [Send] │ -└────┴──────────┴───────────────────┘ -``` - -### 7.3 Files on Tablet - -**Split view**: Directory browser on left, file viewer on right. Tap a file to preview it in the right pane without navigating away. - -``` -┌────┬──────────┬───────────────────┐ -│ │ / > Docs │ notes.md │ -│ 🏠 │──────────│───────────────────│ -│ 💬 │ 📁 Proj │ # Meeting Notes │ -│ 📁 │ 📁 Reps │ │ -│ ⚡ │ 📄 note │ ## Action Items │ -│ │ 🖼️ phot │ - Fix login bug │ -│ │ 🎵 song │ - Update docs │ -│ │ │ │ -│ ⚙️ │ │ │ -└────┴──────────┴───────────────────┘ -``` - -### 7.4 Dashboard on Tablet - -Widgets in a 2-3 column grid instead of single column. More widgets visible at once. - -``` -┌────┬──────────────────────────────┐ -│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ -│ 🏠 │ │Clock │ │Weath.│ │Pomo │ │ -│ 💬 │ └──────┘ └──────┘ └──────┘ │ -│ 📁 │ ┌─────────────┐ ┌──────────┐│ -│ ⚡ │ │ Daily Goals │ │ Quick ││ -│ │ │ ☑ Exercise │ │ Notes ││ -│ │ │ ☐ Read 30min │ │ ... ││ -│ │ └─────────────┘ └──────────┘│ -│ ⚙️ │ Workspaces │ -│ │ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ -└────┴──────────────────────────────┘ -``` - -### 7.5 Tablet-Only Features - -| Feature | Description | -|---------|-------------| -| **Drag & Drop** | Drag files between panes, drag text into chat | -| **Keyboard Shortcuts** | External keyboard support with shortcuts (Cmd+N for new chat, etc.) | -| **Picture-in-Picture** | Video playback continues in PiP when navigating away | -| **Multi-Window** | Android: Split screen support. iPad: Stage Manager support. | - ---- - -## 8. Technical Challenges - -### 8.1 WebSocket Lifecycle on Mobile - -**Problem**: Mobile OSes aggressively kill background connections. WebSocket to chat/terminal will disconnect when app is backgrounded. - -**Solution**: -- Detect app going to background → gracefully close WebSocket -- On foreground → reconnect WebSocket, resume session -- Use `{ type: 'resume', sessionId }` to restore chat state -- Buffer any pending assistant output server-side (the server already does this - messages are saved to JSON files) -- Show "Reconnecting..." indicator when connection drops -- Implement exponential backoff for reconnection attempts - -**Android specifics:** -- Use `ProcessLifecycleOwner` to detect app lifecycle -- Consider foreground service for active chat sessions (shows notification "Chat in progress") - -**iOS specifics:** -- Use `UIApplication.willResignActiveNotification` / `didBecomeActiveNotification` -- Background URL session for critical requests -- Use `BGAppRefreshTask` for periodic sync - -### 8.2 Push Notifications - -**Problem**: The Officer API server currently has no push notification infrastructure. - -**Required Backend Changes:** -1. New endpoint: `POST /api/devices/register` — stores FCM/APNs token per user -2. New database table: `DeviceTokens` (userId, token, platform, createdAt) -3. Server-side notification triggers: - - Chat: When assistant finishes responding and user's WebSocket is disconnected - - Tasks: When a long-running task completes - - Downloads: When yt-dlp or git clone finishes -4. Firebase Admin SDK (Android) + APNs library (iOS) on the server - -**Notification Types:** -| Type | Title | Body | Action | -|------|-------|------|--------| -| Chat complete | "Claude responded" | First 100 chars of response | Open chat session | -| Task complete | "Task finished" | "Format Code completed successfully" | Open task log | -| Download complete | "Download ready" | "video.mp4 downloaded" | Open file browser | -| Error | "Task failed" | "Backup DB failed: connection refused" | Open task log | - -### 8.3 File Upload from Mobile - -**Problem**: Mobile file uploads have different sources than web (camera, photo library, share sheet). - -**Solution**: -- Use platform file pickers that support multiple sources -- Camera capture: Take photo → upload via `POST /api/file-browser/upload` -- Compress images before upload (configurable quality setting) -- Show upload progress (the existing XHR-based upload in `useFiles.ts` supports progress) -- Background upload for large files using WorkManager (Android) / BGTaskScheduler (iOS) -- Resume interrupted uploads if possible - -### 8.4 Offline Support - -**Problem**: Users may open the app with no connectivity. - -**Strategy**: Read-heavy offline, write-queued. - -| Feature | Offline Behavior | -|---------|-----------------| -| Dashboard | Cached widget data, local timer for pomodoro | -| Chat history | Cached session list and recent messages | -| New chat | Queue message, show "Will send when online" | -| File browser | Show last cached directory listing | -| File viewer | Show cached/downloaded files only | -| Settings | Show cached profile, edits queued | - -**Local Database Schema (Room / SwiftData):** -``` -ChatSessions: id, name, provider, lastMessagePreview, updatedAt, isArchived -ChatMessages: id, sessionId, role, content, timestamp (cache recent N per session) -DirectoryCache: path, root, entriesJson, cachedAt -FileCache: path, root, localPath, size, cachedAt (for downloaded/viewed files) -PendingActions: id, type, payload, createdAt, status -``` - -### 8.5 Deep Linking & Share Sheet - -**URL Scheme**: `officer://` -**Universal Links**: `https://officer.dev/app/...` (if applicable) - -**Deep Link Routes:** -- `officer://chat/{sessionId}` — open specific chat -- `officer://files?path=/Documents` — open file browser at path -- `officer://chat/new?prompt=...` — start new chat with prefilled text - -**Share Sheet Integration (receiving):** -- Register app as share target for: text, URLs, images, files -- When content is shared to Officer: - 1. Show a sheet: "Send to Chat" or "Upload to Files" - 2. If Chat: open new chat with shared content as first message - 3. If Files: open file browser with upload in current directory - -### 8.6 Image Handling in Chat - -**Problem**: The web app sends images as base64 in the WebSocket message. Large images on mobile could cause memory issues. - -**Solution**: -1. Before sending, resize images to max 2048px on longest edge -2. Compress to JPEG at 85% quality (unless PNG is needed for screenshots) -3. Convert to base64 and include in chat message -4. Show thumbnail in the message thread, tap to view full-size -5. Consider using the upload endpoint first, then sending attachment IDs instead of base64 (check if API supports this path — it does via `attachmentIds` in the chat message) - -### 8.7 Markdown & Code Rendering - -**Problem**: Rendering rich markdown with code blocks, tables, and images in native views. - -**Android Solution:** -- Use a Markdown library (Markwon or compose-markdown) -- Code blocks: custom span with monospace font + syntax highlighting -- Consider a lightweight WebView-based renderer for complex markdown as fallback - -**iOS Solution:** -- Use `AttributedString` with custom markdown parsing -- Or use a SwiftUI markdown library (MarkdownUI) -- Code blocks: custom view with monospace font + syntax highlighting - -**Code Syntax Highlighting:** -- Android: Highlight.js via WebView, or a native library like CodeView -- iOS: Splash or Highlightr library - -### 8.8 Streaming Text Display - -**Problem**: Chat responses stream token-by-token via WebSocket. Need smooth text rendering without layout thrashing. - -**Solution**: -- Buffer incoming tokens (e.g., collect for 50ms before rendering) -- Use a single mutable text state that appends -- Avoid re-rendering the entire message list on each token -- Only the last (active) message bubble needs updating -- Auto-scroll to bottom during streaming, unless user has scrolled up - -### 8.9 Security - -**Concerns:** -- JWT stored on device must be encrypted -- Biometric key binding for stored credentials -- Certificate pinning for API connections (optional but recommended for self-hosted) -- No sensitive data in logs -- Clear all data on sign out -- Jailbreak/root detection (optional) - -**Android:** -- EncryptedSharedPreferences for tokens -- Android Keystore for biometric-bound keys -- ProGuard/R8 for release builds - -**iOS:** -- Keychain with `kSecAttrAccessibleWhenUnlockedThisDeviceOnly` -- Secure Enclave for biometric keys -- App Transport Security (ATS) enforced - -### 8.10 Self-Hosted Server Discovery - -**Problem**: Officer is self-hosted. Users need to point the app at their server. The server might be on a local network, behind a VPN, or on the public internet. - -**Solution**: -- First-launch: manual URL entry with validation -- Local network: mDNS/Bonjour discovery (optional nice-to-have) -- QR code scanning from web app settings page (generate QR with server URL + optional auth token) -- Store multiple server profiles (for users who have dev/prod setups) -- Connection status indicator in settings - ---- - -## 9. API Integration Notes - -### Endpoints the Mobile App Will Use - -**Auth:** -- `POST /api/auth/signin` — login -- `POST /api/auth/signup` — register (if enabled) -- `POST /api/auth/signout` — logout -- `GET /api/auth/me` — validate token, get user info -- `POST /api/auth/change-password` — password change -- `*/passkeys/*` — passkey registration/auth - -**Chat:** -- `GET /api/sessions?provider={provider}` — list sessions -- `DELETE /api/sessions/{provider}/{id}` — delete session -- `POST /api/sessions/{provider}/{id}/rename` — rename session -- `POST /api/sessions/{provider}/{id}/archive` — archive session -- WebSocket `/api/harness/{provider}/ws` — chat communication - -**Files:** -- `GET /api/file-browser/ls?path={path}&root={root}` — list directory -- `GET /api/file-browser/read?path={path}` — read text file -- `GET /api/file-browser/raw?path={path}` — raw file (binary, supports Range) -- `GET /api/file-browser/search?q={query}` — search files -- `POST /api/file-browser/mkdir` — create directory -- `POST /api/file-browser/write` — write file -- `POST /api/file-browser/upload` — upload files (multipart) -- `POST /api/file-browser/rename` — rename -- `POST /api/file-browser/copy` — copy -- `POST /api/file-browser/move` — move -- `DELETE /api/file-browser/rm` — delete -- `GET /api/file-browser/download?path={path}` — download file -- `POST /api/file-browser/download` — download multiple as zip -- `GET /api/file-browser/transcode?path={path}` — transcode video -- `POST /api/file-browser/tts` — text-to-speech -- `POST /api/file-browser/ocr` — OCR image -- `POST /api/file-browser/transcribe` — transcribe audio -- `POST /api/file-browser/extract-audio` — extract audio from video -- `POST /api/file-browser/extract` — extract archive -- `POST /api/file-browser/git-clone` — clone git repo -- `POST /api/file-browser/download-video` — yt-dlp download - -**Tasks:** -- `GET /api/tasks` — list tasks -- `GET /api/tasks/{name}` — task details -- `POST /api/tasks/{name}/run` — run task - -**Task Logs:** -- `GET /api/task-logs` — list logs -- `GET /api/task-logs/{id}` — log details - -**Processes:** -- `GET /api/processes` — list processes - -**Settings:** -- `GET /api/user/settings` — user settings -- `PUT /api/user/settings` — update settings -- `PUT /api/auth/users` — update profile - -**Upload:** -- `POST /api/upload` — upload attachments (for chat) - -**Scrape:** -- `POST /api/scrape` — scrape URL (for sharing URLs to chat) - -### New Endpoints Needed - -| Endpoint | Purpose | -|----------|---------| -| `POST /api/devices/register` | Register push notification token | -| `DELETE /api/devices/{token}` | Unregister device on logout | -| `GET /api/sessions/{provider}/{id}/messages` | Get messages for a session (currently read from files, need API endpoint) | - -### Authentication Header - -All requests include: `Authorization: Bearer {jwt_token}` - -WebSocket connections pass token as query parameter: `?token={jwt_token}` - ---- - -## 10. Shared Design Language - -While each platform follows its native design guidelines (Material 3 for Android, Human Interface Guidelines for iOS), some design elements should be consistent: - -### Color Palette - -From the web app's Tailwind theme: -- **Primary (Teal)**: `duck-teal` — used for primary actions, active states -- **Accent (Yellow)**: `duck-yellow` — used for text on primary, highlights -- **Dark**: `duck-dark` — text, icons -- **Background**: Light/dark mode adaptive - -Both apps should use these brand colors while adapting to platform conventions: -- Android: Material 3 dynamic color with Officer palette as seed -- iOS: Officer palette with system-adaptive backgrounds - -### Typography - -- **Android**: Roboto (system default), with monospace for code -- **iOS**: SF Pro (system default), with SF Mono for code -- Both: Similar size scale, consistent heading hierarchy - -### Iconography - -- **Android**: Material Symbols (outlined) -- **iOS**: SF Symbols -- Map lucide-react icons used in web to platform equivalents - -### Animations - -- **Android**: Material Motion (shared element transitions, container transforms) -- **iOS**: Spring animations, matched geometry effects -- Both: Smooth transitions between screens, subtle feedback on interactions - ---- - -## 11. Implementation Phases - -### Phase 1: Foundation (MVP) - -**Goal**: Core functionality that makes the app useful enough to ship. - -| Feature | Details | -|---------|---------| -| Auth | Email/password login, token storage, biometric unlock | -| Server setup | URL configuration, validation | -| Chat | New chat, session list, real-time conversation with streaming | -| Chat basics | Text messages, model selection, session management | -| Settings | Profile view, theme, logout | - -**Estimated screens**: Login, Home (simple), Chat List, Chat Conversation, Settings - -### Phase 2: Files & Polish - -**Goal**: File management and mobile-specific enhancements. - -| Feature | Details | -|---------|---------| -| File browser | Directory listing, navigation, search | -| File viewer | Text, images, PDF, audio, video | -| File actions | Upload (camera, files), download, rename, delete | -| Chat attachments | Image attachment, voice input | -| Push notifications | Basic chat completion notifications | - -**Estimated screens**: File Browser, File Viewer, enhanced Chat - -### Phase 3: Productivity - -**Goal**: Dashboard, tasks, and deeper integration. - -| Feature | Details | -|---------|---------| -| Dashboard | Widget system (clock, weather, pomodoro, goals, notes) | -| Tasks | Task list, run tasks, view logs | -| Workspace quick access | Open workspaces (single-panel) | -| Share sheet | Receive content from other apps | -| Offline support | Cached data, queued actions | - -**Estimated screens**: Dashboard, Task List, Task Logs, enhanced Home - -### Phase 4: Tablet & Advanced - -**Goal**: Tablet optimization and advanced features. - -| Feature | Details | -|---------|---------| -| Tablet layouts | Split views for chat, files | -| Tablet navigation | Side rail / sidebar | -| Home screen widgets | Android widgets, iOS widgets | -| AI file actions | OCR, TTS, Transcribe from mobile | -| Multi-select | Batch file operations | -| Deep linking | URL scheme, universal links | - -### Phase 5: Nice-to-Haves - -| Feature | Details | -|---------|---------| -| QR code server setup | Scan from web to configure | -| Local network discovery | mDNS/Bonjour | -| Picture-in-Picture | Video PiP on tablet | -| Passkey auth | Full WebAuthn support | -| Keyboard shortcuts | External keyboard on tablet | -| Skills browser | View and search skills library | -| Background downloads | yt-dlp and git clone in background | - ---- - -## Appendix: Decision Log - -| Decision | Rationale | -|----------|-----------| -| Native (Kotlin + Swift) over cross-platform | User preference. Also gives best performance, platform-native UX, and full access to platform APIs (biometrics, push, background tasks, share sheet). | -| Exclude terminal | Phone keyboards make shell commands impractical. The sandboxed Docker setup is inherently desktop-oriented. | -| Exclude code editor (write) | Writing code on a phone is poor UX. Read-only with syntax highlighting is sufficient for review. | -| Exclude automation builder | Complex form-heavy UI that doesn't translate to small screens. | -| Include chat as primary feature | AI assistant in your pocket is the strongest mobile use case. Voice input makes it even more compelling on mobile. | -| Bottom tabs (phone) / Side rail (tablet) | Standard navigation patterns for each form factor. 5 top-level destinations fits within guidelines. | -| Offline-first for reads, queue for writes | Mobile connectivity is unreliable. Showing cached data is better than empty screens. | -| Phase 1 = Auth + Chat | Chat is the killer feature. Get it right first, everything else is complementary. | diff --git a/SECURITY_AUDIT.md b/SECURITY_AUDIT.md deleted file mode 100644 index 9f9dee81..00000000 --- a/SECURITY_AUDIT.md +++ /dev/null @@ -1,593 +0,0 @@ -# Security Audit — Officer.dev Pi-Monorepo - -**Date:** 2026-02-25 -**Scope:** Full-stack audit of server, frontend, and infrastructure code. - ---- - -## Executive Summary - -The codebase has solid foundations (JWT + argon2 auth, WebAuthn passkeys, token blacklisting, Docker-sandboxed terminals, role-based access control). However, several critical and high-severity vulnerabilities exist — primarily around CORS misconfiguration, weak secret management, unauthenticated admin routes, XSS via `rehype-raw`, and token exposure in URLs. - -**Totals:** 5 Critical, 13 High, 14 Medium, 9 Low, 5 Info - ---- - -## CRITICAL - -### C1. Weak JWT Secret — `"officer"` - -**Files:** `.env` (line 2), `src/servers/jwt.ts` (lines 2, 25) - -The live `.env` contains `JWT_SECRET="officer"` — a single dictionary word. The `.env.example` uses `"change-me"`. The server uses a non-null assertion (`JWT_SECRET!`) with no startup validation for length or complexity. - -**Impact:** Complete authentication bypass. Anyone who knows/guesses the secret can forge JWTs for any user including Super Admin. - -**Remediation:** -- Generate a cryptographically random secret: `openssl rand -base64 32` -- Add a startup guard: throw if `JWT_SECRET` is absent or shorter than 32 characters -- Update `.env.example` with a placeholder: `JWT_SECRET=` - ---- - -### C2. Global CORS Wildcard on All API Routes - -**File:** `src/servers/hono.ts` (lines 36–42) - -```ts -cors({ origin: '*', allowHeaders: ['Content-Type', 'Authorization'] }) -``` - -Applied to every route. The `Authorization` header allowlist means any website can make cross-origin requests using a victim's token (obtained via XSS or other leaks). - -**Impact:** Full cross-origin request forgery against all API endpoints for users tricked into visiting a malicious page. - -**Remediation:** Replace `origin: '*'` with the allowlist from `origin-validation.ts` (`ALLOWED_ORIGINS`). Use a dynamic origin validation function in the CORS middleware. - ---- - -### C3. Server-Settings Routes Entirely Unauthenticated - -**Files:** `src/servers/hono.ts` (lines 46–48), `src/servers/api/server-settings/server-settings.ts` - -The `serverSettingsRouter` is mounted on the **public** router (outside `protectedRouter`). All sub-routes — SMTP, TTS, STT, OCR, SearXNG, Pi-Mono, Claude Code, OpenCode, applications, resources — have no auth checks. Any unauthenticated request can read settings (including masked credentials), write new settings, and trigger software installs. - -**Impact:** Full server configuration takeover by any unauthenticated user. - -**Remediation:** Move `serverSettingsRouter` inside `protectedRouter`. Add Super Admin role checks on all write operations. Exempt only `GET /api/server-settings/onboarding-complete` as public. - ---- - -### C4. Unauthenticated Dev-Server WebSocket Proxy - -**Files:** `src/server.tsx` (lines 114–139), `src/servers/api/dev-server/router.ts` (lines 241–268), `src/servers/hono.ts` (line 49) - -The dev-server proxy (`/api/dev-server-proxy/*`) is mounted on the public router. WebSocket upgrades carry no authentication. The HTTP proxy has no auth gate either. Additionally, the Referer header fallback allows probing any running dev server. - -**Impact:** Unauthenticated access to dev-servers spawned for any user, which may expose internal APIs, HMR endpoints, or local services. - -**Remediation:** Require a valid JWT (via query param) before upgrading WebSocket connections. Apply `userMiddleware` to the HTTP proxy router. - ---- - -### C5. AI Chat Messages Rendered with `rehype-raw` — LLM-Driven XSS - -**File:** `src/workspaces/officerdev/src/apps/Chat/components/MessageBubble.tsx` (lines 132, 181) - -```tsx -{assistantText} -``` - -AI-generated assistant responses containing HTML tags (`