# 2026-02-19

## Bebot - Gee's Personal Assistant Bot

### Project Setup Complete
- **GCP Project:** `gee-assistant` (under Symph Products folder 436092539710)
- **APIs Enabled:** Gmail API, Google Calendar API
- **OAuth Scopes:** gmail.readonly, calendar.readonly, calendar.events
- **Credentials:** `~/.config/bebot/` (google-tokens.json, google-oauth.json, discord-token.txt, memory.json)
- **Discord Bot:** Bebot#4927 (App ID: 1473951417440931881)
- **Code Location:** `/home/aria/projects/bebot/index.js`
- **Process:** PM2 (`pm2 restart bebot`)

### Implemented Features
- Calendar checks and event creation
- Memory system (facts stored as JSON)
- Proxy mode: @Gee mentions trigger Bebot response + DM to Gee
- Document/link review via content extraction
- No-hallucination rules
- Username addressing ("Hi [Name]! It's Bebot, Gee's girl 💁‍♀️")

### Key Context
- Gee's email: gee@symph.co
- Gee's Discord ID: 688903298501443625
- Bebot only in server ID 688634391660068872 (old Symph server)
- Using GPT-4o-mini currently (will switch to Claude when key provided)

### Pending Work
1. **Urgency filtering** - Bebot shouldn't respond to ALL @Gee mentions, especially in sales/production channels. Need to implement urgency detection.
2. **Perplexity API** - Waiting for Gee to provide API key from https://www.perplexity.ai/settings/api
3. **Claude API** - Waiting for key from https://console.anthropic.com/ → switch Bebot's brain to Claude

### Design Decision
Bebot should only respond to urgent @Gee tags, not every mention. Sales and production channels especially need filtered responses.

---

## Bebot Update: CRSO Document Review Mode

### Feature Added
When someone @Gee and asks to "review" or "check" a document/proposal with a URL, Bebot now does a full CRSO pass using Gee's 4-lens framework.

### Review Framework (saved to `~/.config/bebot/review-framework.md`)
- 💰 **Revenue Lens** — pricing integrity, scope-to-revenue alignment, payment terms, cash flow, upsell potential
- ⚙️ **Solutions Lens** — technical feasibility, resource availability, tech stack, timeline realism, dependencies
- ⚖️ **Legal Lens** — IP ownership, liability caps, confidentiality, termination, warranty, data privacy, governing law
- 🔍 **Details Lens** — language precision, consistency, defined terms, attachments, version control

### Response Format
- 🟢 **LOOKS GOOD:** positive points
- 🟡 **CLARIFY:** questions/unclear items
- 🔴 **FLAG:** concerns needing attention
- 📋 **RECOMMENDATION:** quick take

### Trigger Keywords
"review", "check", "look at", "feedback", "thoughts on", "opinion on" + URL

### Limitations
- Google Docs/Sheets/Slides: Can't access directly (no Drive API) — asks user to paste key sections
- Bebot does quick first-pass, explicitly says "Gee will review this herself"

---

## 02:55-10:35 UTC - Heartbeat Monitoring & Security Review

### .env Migration to XDG (Raven — 03:00 UTC)
- **Issue:** Found `~/.openclaw/.env` with OpenAI API key (should use ~/.config/)
- **Action:** Migrated to `~/.config/openai/api-key` (chmod 600)
- **Removed:** `~/.openclaw/.env`
- **Updated:** TOOLS.md with API Keys section documenting XDG-compliant locations

### Gateway Device Token Mismatch (03:32 UTC - ONGOING)
- Gateway started failing with "device token mismatch (rotate/reissue device token)" at 03:32 UTC
- Multiple restarts attempted (04:16, 06:40, 07:31, 08:52, 09:50, 09:59, 10:02 UTC) — none resolved the issue
- **Impact:**
  - sessions_list blocked → no usage tracking
  - Job spawning blocked → pending jobs accumulated (peaked at 21, later cleared to 0-1)
  - Cron deliveries failing
- **Status:** 7+ hours ongoing, escalated to Raven multiple times
- **Root cause:** Unknown — process restart doesn't fix it, suggests token state issue

### Security Monitoring Review (Raven — 10:10 UTC)
Documented current security monitoring in place:

1. **Rogue Process Monitor** (every 15 min)
   - Checks /dev/shm/, /tmp/ for suspicious processes
   - CPU >500% sustained detection
   - Random 8-char binary names (cryptominer pattern)
   - Orphan processes (PPid=1)

2. **Netscan Detection** (every 15 min)
   - `ss -tn state syn-sent | wc -l`
   - Alert threshold: >20 connections
   - Added after Hetzner IP block incident

3. **Security Daily Report** (00:03 UTC daily)
   - Failed SSH attempts, fail2ban stats
   - Posted to #aria-status

4. **Canary Honeypot Files** — working (detected Feb 18 intrusion)

### Feb 18 Credential Scanning — Confirmed Real Intrusion
Investigated the incident flagged at 21:48 UTC Feb 18:

- **NOT a false positive** — actual attacker processes detected
- **Patterns searched:** `AKIA[A-Z0-9]{16}` (AWS), `sk_live_` (Stripe), `ghp_` (GitHub), `SG\.` (SendGrid)
- **Canary files accessed** at 21:45:22 UTC (automated/scripted)
- **Attack vector:** UNKNOWN — ruled out SSH, cron jobs, Claude CLI
- **Possible vectors:** Vulnerable Next.js app, supply chain, prompt injection
- **auditd enabled after incident** for future forensics

### Heartbeat Status Throughout Session
- ✅ No suspicious processes detected
- ✅ Clean /dev/shm (only PostgreSQL)
- ✅ Netscan normal (1 connection, threshold 20)
- ⚠️ Pending jobs fluctuated (0-21) due to gateway issues
- ❌ Usage tracking blocked by gateway error

---

## Worklane Backend Development (Jude — Evening UTC)

### Completed Today

**WL-001 Test Mode Backend**
- Created `/home/aria/products/worklane/app/src/app/api/workflows/[id]/test/route.ts`
- BFS algorithm for workflow traversal handling parallel paths + conditional branching
- Returns simulated approval path without creating real records

**WL-002 Test Mode Frontend**
- Created `TestModeModal.tsx` component
- Form field inputs for testing, step-by-step visualization
- Shows expected approval path based on routing rules

**WL-003 Routing Rules Backend**
- Created `/home/aria/products/worklane/app/src/lib/entities/routing.ts`
- Rule types: `value`, `field`, `role`, `amount`
- Operators: `equals`, `not_equals`, `contains`, `greater_than`, `less_than`, `in_list`
- `evaluateRoutingRule()` and `evaluateRoutingRules()` functions
- Supports AND/OR logic for complex conditions

**WL-004 Routing Rules Frontend**
- `RoutingRuleEditor.tsx` — UI for configuring routing conditions
- `EdgeConfigModal.tsx` — Modal for routing rules on workflow edges (double-click edge)
- `ApprovalNodeConfigModal.tsx` — Modal for approval nodes with skip rules + dynamic approvers

**Entity Updates**
- Added `WorkflowNodeData` and `WorkflowEdgeData` interfaces to workflow.ts
- Added index signatures `[key: string]: unknown` for React Flow compatibility
- Updated form submission API to evaluate routing rules for approval step determination

### Key Technical Decisions
- **React Flow compatibility:** Index signatures required because React Flow passes extra props
- **Routing evaluation:** Happens at form submission time, not workflow design time
- **Test mode:** Simulates entire workflow path without creating Firestore records

### Files Created
- `/home/aria/products/worklane/app/src/lib/entities/routing.ts`
- `/home/aria/products/worklane/app/src/components/workflow/RoutingRuleEditor.tsx`
- `/home/aria/products/worklane/app/src/components/workflow/EdgeConfigModal.tsx`
- `/home/aria/products/worklane/app/src/components/workflow/ApprovalNodeConfigModal.tsx`
- `/home/aria/products/worklane/app/src/components/workflow/TestModeModal.tsx`
- `/home/aria/products/worklane/app/src/app/api/workflows/[id]/test/route.ts`

### Next Steps
1. Verify build compiles with routing changes
2. Test edge/node config modals in workflow builder
3. Integrate TestModeModal with workflow page "Test" button
4. Continue to WL-005/006: Conditional Fields

---

## Overture — Build Session (Jap, David, Nicolas)

### Completed
- **Dashboard personalization** — Updated tabs to match onboarding: My Metrics, Revenue, Growth, Engagement, Sales, Support
- **Onboarding reset on logout** — Dev mode clears preferences for testing (documented in PRD)
- **Google OAuth fixed** — Removed placeholder credentials, David configured real OAuth client in Firebase Console
- **PRD v1.1** — Updated with all onboarding/personalization features, shared with Jap
- **QA test coverage** — Generated 92 test cases for Nicolas (45 smoke, 47 full)

### Technical Details
- Dev URL: `https://overture.dev.apps.symph.co` (port 3080)
- Server runs in standalone mode: `PORT=3080 node .next/standalone/server.js`
- Firebase project: `symph-overture`
- Google OAuth client: `77215696877-ktdbmjg8v3tsa7ndfsfl6fm4o99gqms8.apps.googleusercontent.com`

### Pending
- Nicolas needs to share Google Sheet with `aria-firebase-admin@the-agency-symph.iam.gserviceaccount.com` to push QA test cases
- Phase 2: Real integrations (Stripe, GA4, HubSpot) — backlog

### Learnings
- Next.js standalone mode requires `PORT=3080 node server.js` not `npm run start`
- Firebase OAuth placeholder credentials cause "Access blocked" error — need real client ID
- `export const dynamic = 'force-dynamic'` doesn't work on client components

---

## Clocklane — Google Sign-In & QA Completion (Zel, Ragan, Tom)

### Production Deployment Complete
- **Revision:** `clocklane-00002-9lt` deployed to Cloud Run
- **QA Results:** 119 tests, 115 passed, 0 failed, 4 blocked (96.6% pass rate)
- **Blocked tests:** Bulk import, break tracking, timesheet export (not in PRD scope)

### Google Sign-In Implementation
- **OAuth Client:** `884792979624-vgql2fii92cdio7chrf3qk17d8scu1c9.apps.googleusercontent.com` (created via Firebase Console)
- **Approach:** `signInWithPopup` (redirect returned null — popup works with relaxed CSP)
- **CSP Changes:** `script-src 'self' 'unsafe-inline' 'unsafe-eval' https:` for GTM compatibility
- **COOP Header:** `same-origin-allow-popups` required for popup auth flow
- **Commit:** `a9bb3033` — "feat(auth): Add Google Sign-In with popup flow"

### Current Issue: Google Button Not Visible on Prod (Zel report)
- Code verified: "Continue with Google" exists in LoginPage.tsx
- Built JS chunk contains correct code (`.next/server/chunks/ssr/apps_main_5a07614d._.js`)
- Page is client-side rendered (HTML shows "Loading..." placeholder until JS hydrates)
- Fresh rebuild completed (`rm -rf .next && npm run build`)
- **Suspected cause:** CDN/browser caching or deployment not pushed to Cloud Run
- **Next step:** Force redeploy to Cloud Run, have Zel clear browser cache

### Key Files Modified
- `/home/aria/products/clocklane/apps/main/src/lib/auth.tsx` — signInWithPopup implementation
- `/home/aria/products/clocklane/apps/main/src/components/LoginPage.tsx` — enabled Google button
- `/home/aria/products/clocklane/apps/main/next.config.ts` — relaxed CSP + COOP header

### Tickets Completed This Session
- **CLOCK-017:** Google Sign-In — DEPLOYED TO PROD
- **CLOCK-025:** Timesheets mobile responsive
- **CLOCK-026:** Settings page logo fixed
- **CLOCK-027:** Block /join if user already belongs to store

### Technical Learnings
- `signInWithRedirect` can return null result in some environments — `signInWithPopup` more reliable
- IAP OAuth clients (`gcloud iap oauth-clients create`) incompatible with Firebase Auth popup/redirect flows
- Firebase Console creates proper external-capable OAuth clients for web apps

## TIL (Today I Learned)
- Raven requested Phase 1 security remediation: restart vulnerable Next.js processes (worklane PID 3588903, overture PID 1411193) + block C2 domain jolaibantot.xyz
- Exec commands hit approval gates — security actions need manual approval even for critical incidents
- Memory cleanup executed successfully by user request — killed stale dev processes, freed ~9GB RAM (from 28GB to 19GB used)
- End-of-day memory consolidation added to HEARTBEAT.md — runs at last heartbeat after 22:00 PHT

---

## Encore QA Session (Afternoon) — Zel

### Issues Fixed (ENCORE-011 through ENCORE-018)

| Issue | Description | Revision |
|-------|-------------|----------|
| ENCORE-011 | Documents page mobile — hide sidebar, add folder dropdown | 00039-zkz |
| ENCORE-012 | Messages page mobile — stack thread list/conversation | 00041-v4f |
| ENCORE-013 | Invoices table mobile — action buttons visible | 00042-xk9 |
| ENCORE-014 | Reports/Support/Approvals mobile fixes | 00043-pp9, 00044-k7g |
| ENCORE-015 | AppHeader text cut off on iPhone 12 Pro (390px) | 00045-p6x |
| ENCORE-016 | Client view toast message — clarified support ticket creation | 00046-hdc |
| ENCORE-017 | Client can Approve/Reject — should be Admin only | 00047-6c9 |
| ENCORE-018 | Password show/hide toggle on login form | 00048-hmv |

### Key Decisions
- **Support tickets:** Clients CAN create tickets (asking for help) — this is correct behavior
- **Approvals:** Clients can VIEW only, not Approve/Reject — that's Admin-only
- **Toast message updated:** "You can view content and submit support requests. Admin features are hidden."

### Mobile Responsiveness Pattern Applied
- Use `hidden lg:block` for sidebar on mobile, show dropdown instead
- Use `flex-col sm:flex-row` for stacking on mobile
- Use `whitespace-nowrap` + reduced padding for action buttons
- Use `min-h-X` instead of fixed `h-X` for flexible headers

### Production URL
- https://encoreclients.com
- Latest revision: encore-00048-hmv

### QA Backlog Updated
- All issues logged to `/home/aria/projects/encore/qa/backlog.md`
- Pushed to GitHub

---

## Alignly QA Session (Med, Nicolas — Evening UTC)

### Security Audit Completed
- Headers: CSP present (needs Google Fonts whitelist), HSTS, X-Frame-Options, X-Content-Type-Options ✅
- Auth: Firebase Auth with proper session management ✅
- Firestore: Rules enforce org-scoped access ✅

### Nicolas Bug Fixes (BUG-010 through BUG-018)

| Bug | Page | Mode | Issue | Fix | Status |
|-----|------|------|-------|-----|--------|
| BUG-010 | Time Off | Logged in | "No matching document" | Auto-create employee on org creation | ✅ |
| BUG-011 | Handbook | Logged in | Same error | Same root cause fix | ✅ |
| BUG-012 | Time Tracking | Demo | Client-side exception | In Progress — formatTime() validation needed | ⏳ |
| BUG-013 | Templates | Demo | Redirect to handbook | Demo mode admin check added | ✅ |
| BUG-014 | Start Onboarding | Demo | Modal broken | Full demo mode support added | ✅ |
| BUG-015 | Settings | Logged in | Same error as BUG-010 | Same root cause fix | ✅ |
| BUG-016 | Time Off | Demo | "No data found" | Changed emp-001 to emp_alex | ✅ |
| BUG-017 | Handbook | Demo | Same error | Changed emp-001 to emp_alex | ✅ |
| BUG-018 | Settings | Demo | Works | Already functional | ✅ |

### Root Causes Identified
1. **Logged-in bugs (BUG-010, 011, 015):** Org creator didn't get employee record — fixed in `user-organization.service.ts` to auto-create employee when organization is created
2. **Demo bugs (BUG-016, 017):** Employee ID mismatch — demo API returns data for `emp_alex` but pages queried `emp-001`

### Key Files Modified
- `src/lib/services/firebase/user-organization.service.ts` — Create employee record on org creation
- `src/app/[orgSlug]/time-off/page.tsx` — Use emp_alex for demo
- `src/app/[orgSlug]/handbook/page.tsx` — Use emp_alex for demo
- `src/app/[orgSlug]/time-tracking/page.tsx` — User ID extraction + localStorage persistence
- `src/app/[orgSlug]/onboarding/templates/page.tsx` — Demo mode admin check
- `src/components/onboarding/start-onboarding-modal.tsx` — Full demo mode support

### Technical Details
- Dev URL: https://alignly.dev.apps.symph.co (port 3060)
- GitHub: symphco/alignly-app
- Test account: nicolas+testqa@symph.co / P@ssword123! / org: testqainc
- QA Google Sheet: 129 test cases generated

### Remaining Work
- BUG-012: Time Tracking demo crash — `formatTime()` expects "HH:MM" format, API may return different
- BUG-002: CSP blocks Google Fonts
- BUG-003: Demo Dashboard slow
- BUG-004: Add password reset link

### Commit History
- `c2038b7` — All Nicolas bug fixes (BUG-010,011,013-018)

## ReadStreak E2E Health Check - 2026-02-19 19:02 UTC

**All tests PASS** ✅

| Test | Result |
|------|--------|
| Homepage (readstreak.app) | HTTP 200 |
| Dashboard | HTTP 200 (via redirect) |
| Library | HTTP 200 (via redirect) |
| Friends | HTTP 200 |
| API Healthcheck | ok (v1.0.0) |
| Auth (test account) | Success |

No issues detected.

---

## Alignly Employee Management Fixes (Nicolas — Late Evening UTC)

### Issues Fixed
1. **Employees API auth** — `/api/v1/orgs/[orgId]/employees/route.ts` only accepted API key auth, blocking browser requests. Added Bearer token auth support.
2. **Employee persistence** — `handleAddEmployee` had TODO placeholder — only updated local state, not database. Fixed to POST to `/employees` API.
3. **Data source** — Employees page fetched from `/members` endpoint (user membership data). Changed to fetch from `/employees` endpoint (employee records).

### Technical Details
- **Dual auth pattern:** APIs now accept BOTH `x-api-key` header AND `Authorization: Bearer <token>` for flexibility
- **Employee record creation:** Auto-creates employee record when user creates organization (in `user-organization.service.ts`)
- **Commits:** `e6cf520`, `ca9af3a`

### Files Modified
- `/api/v1/orgs/[orgId]/employees/route.ts` — Added Bearer token auth
- Employees page — Changed data source + added DB persistence
- `user-organization.service.ts` — Employee auto-creation on org creation

### Learnings
- **TODO placeholders in handlers** — Always check for `// TODO` comments when debugging data persistence issues
- **Auth flexibility** — Browser requests use Bearer tokens, server-to-server uses API keys — support both
- **Members vs Employees** — These are different concepts: members are user-org relationships, employees are HR records


---

## Worklane UI/UX Improvements (Jude — Evening Session)

### Completed Tasks (WL-UI-003 through WL-UI-010)

| Task | Description | Status |
|------|-------------|--------|
| WL-UI-003 | Tablet Responsiveness | ✅ Sidebar auto-collapses, hamburger menu on mobile |
| WL-UI-004 | Workflows Mobile View | ✅ Card layout on mobile, table on desktop |
| WL-UI-005 | Mobile Panel Overlap | ✅ Master-detail pattern for workflow builder |
| WL-UI-006 | Logo Consistency | ✅ Created `WorklaneLogo`/`WorklaneLogoIcon` components |
| WL-UI-007 | Favicon Update | ✅ New logo SVG in icon.tsx/apple-icon.tsx |
| WL-UI-008 | Node Delete Feature | ✅ Red X button on hover for deletable nodes |
| WL-UI-009 | X Button Fix | ✅ `userClosedBuilder` flag prevents auto-reselect |
| WL-UI-010 | Dropdown Clipping | ✅ React Portal fix for WorkflowStatusSelector |

### Key Technical Decisions

**Dropdown Clipping Fix (WL-UI-010):**
- Used React Portal (`createPortal` to `document.body`) for dropdown menu
- Fixed positioning calculated from button ref's bounding rect
- z-index 100 ensures dropdown stays above all content
- Pattern: `dropdownPosition` state + `buttonRef` + `useEffect` for position calculation

**Mobile Workflow Builder Pattern:**
- Master-detail: Show EITHER workflow list OR builder (not both overlapping)
- `selectedWorkflowId` and `userClosedBuilder` flags control visibility
- Clear separation improves mobile UX significantly

**Node Delete Protection:**
- Start/End nodes are protected (no delete button)
- Only Form/Approval/Notification nodes can be deleted
- DeleteButton component with red X icon on hover

### New Components Created
- `src/components/ui/worklane-logo.tsx` — Reusable SVG logo components
- `src/components/ui/password-input.tsx` — Password input with visibility toggle
- `src/hooks/use-media-query.ts` — Responsive breakpoint detection

### Production Deployment
- Cloud Run revision: `worklane-00059-7rd` (building)
- Dev URL: https://worklane.dev.apps.symph.co/ (port 3050)
- Prod URL: https://getworklane.com

### Remaining Work
- Phases A-G from UI/UX improvement plan
- WL-005/006 Conditional Fields
- 70 backend QA tests (need multi-user scenarios)
- Domain email verification in Resend

---

## ContentVane Build Setup (Jeremy — tsumugyu)

### Product Overview
- **Slug:** contentvane
- **Location:** `/home/aria/products/contentvane/`
- **Firebase:** `symph-contentvane`
- **Dev URL:** https://contentvane.dev.apps.symph.co
- **Port:** 3001

### What Was Built
ContentVane is an AI-powered content research platform that delivers weekly content briefings to creators. Jeremy provided PRD/BRD docs and a Lovable UI reference.

**Stack:**
- Next.js 16 + Tailwind CSS v4 + shadcn/ui
- Firebase Auth (Email/Password enabled)
- Purple primary color scheme (#7c3aed / hsl 263 70% 50%)
- Space Grotesk for headings, Inter for body

**Pages Created:**
- `/` — Landing page with hero, features, pricing
- `/login` — Auth with Firebase
- `/register` — Auth with Firebase
- `/onboarding` — 3-step setup (niche, competitors, preferences)
- `/dashboard` — Main briefing view with progressive disclosure
- `/dashboard/ideas` — Mood board grid with status filters
- `/dashboard/settings` — Workspace, niche, delivery config
- `/privacy`, `/terms` — Legal pages

**Key Design Elements (from Lovable export):**
- Glass card styling: `bg-card/80 backdrop-blur-xl border border-border/50 rounded-xl`
- Light mode default with dark mode toggle in sidebar
- Progressive disclosure pattern (collapsible sections)
- Opportunity labels with confidence scores
- Sidebar with theme toggle button

### PRD Location
- `/home/aria/products/contentvane/discovery/` — Contains PRD, BRD, Napkin PRD

### Next Steps
- Wire up Firestore for saving ideas, settings, user preferences
- Implement actual scraper integrations (YouTube API, Reddit, Twitter)
- LLM analysis pipeline with Claude API
- Email delivery with Resend/Postmark for Monday briefings

---

## Overture — Extended Build Session (continued Feb 20)

### Additional Fixes Implemented

**Auth & Routing (Jap)**
- Dual-context routing: login checks `onboardingCompleted && primaryMetrics.length > 0`; useRequireAuth only checks `onboardingCompleted` (removes-all-metrics stays on dashboard)
- `refreshOnboardingPrefs()` added to AppContext — called after onboarding saves so dashboard shows metrics instantly without refresh

**My Metrics Management**
- Remove card: X button on hover (admin mode), saves updated primaryMetrics to Firestore
- Drag-to-reorder: fixed (was blocked by `activeTab !== "sales"` guard), saves to `dev_user_preferences`
- `setPrimaryMetrics()` in AppContext persists to Firestore + localStorage count
- Empty state when all metrics removed (dashed border, "Set up My Metrics" CTA)
- `metricsSkeletonCount` from localStorage so correct N skeletons show on refresh

**Alerts Page**
- Removed all hardcoded mock alert data
- New Firestore collection: `dev_system_alerts/{uid}/items/{alertId}`
- Seeded 12 real alerts for all 3 user accounts
- Skeleton loading (5 rows), proper empty state (context-aware message)
- Refresh button now actually re-fetches from Firestore + spins icon

**UI Polish**
- Avatar dropdown: closes on click-outside (useRef + mousedown listener)
- Removed non-functional ChevronDown from tab row
- Admin/Viewer toggle: removed redundant CheckCircle2 from Admin button (centering fix)
- Settings flash fix: theme/companyName/logo/role all read from localStorage for initial state

**PRD**
- Updated to v1.3, uploaded to Discord
- Changelog tracks v1.0 → v1.1 → v1.2 → v1.3

### QA Test Coverage
- 98 test cases written to Google Sheet (Nic's request)
- Sheet ID: 16vZd1gSLnIvmX66JXfIYpdaxm5cLRniW8q5ra3ix0Lg
- Service account: aria-firebase-admin@the-agency-symph.iam.gserviceaccount.com

### Key Architecture Notes
- Overture Firebase project: `symph-overture`
- Alert data path: `dev_system_alerts/{uid}/items/{alertId}`
- Settings cache keys: `overture_logo`, `overture_company_name`, `overture_theme`, `overture_role`
- Metrics count key: `overture_metrics_count`
- All localStorage cleared on logout to prevent cross-account bleed
