# Bugger for macOS — High-Level Design ## Overview **Bugger** is a lightweight macOS menu bar application that surfaces bugs assigned to you from a Feishu Bitable. It mirrors the experience of the Windows Bugger tool: a glanceable badge in the menu bar, a popover with your active bugs, native notifications when bugs are assigned or changed, and an optional floating widget. ## Architecture ``` ┌──────────────────────────────────────────────────────┐ │ User's Mac │ │ │ │ ┌─────────────┐ ┌──────────────┐ │ │ │ Menu Bar │ │ Floating │ │ │ │ Icon+Badge │ │ Widget │ │ │ │ [🐛 3] │ │ (optional) │ │ │ └──────┬──────┘ └──────┬───────┘ │ │ │ │ │ │ ┌──────┴──────────────────┴───────┐ │ │ │ BugStore │ │ │ │ (ObservableObject) │ │ │ │ - bugs: [Bug] │ │ │ │ - unseenCount: Int │ │ │ │ - lastUpdated: Date │ │ │ └──────┬──────────────────────────┘ │ │ │ │ │ ┌──────┴──────────┐ ┌─────────────┐ │ │ │ PollerService │───▶│ FeishuService│ │ │ │ (Timer, 5min) │ │ │ │ │ └─────────────────┘ └──────┬──────┘ │ │ │ │ │ ┌──────────────┐ ┌────────┴───────┐ │ │ │ Notification │ │ TokenManager │ │ │ │ Service │ │ (Keychain) │ │ │ └──────────────┘ └────────────────┘ │ │ │ └──────────────────────────────────────────────────────┘ │ │ HTTPS (OAuth Bearer) ▼ ┌──────────────────────────────────────────────────────┐ │ Feishu Cloud │ │ ┌──────────────┐ ┌──────────────────┐ │ │ │ OAuth │ │ Bitable API │ │ │ │ /authen/v1/ │ │ /bitable/v1/ │ │ │ │ oidc/ │ │ apps/{token}/ │ │ │ │ access_token│ │ tables/{id}/ │ │ │ └──────────────┘ │ records │ │ │ └──────────────────┘ │ └──────────────────────────────────────────────────────┘ ``` ## Key Design Decisions ### 1. Native SwiftUI (not cross-platform) The app targets macOS exclusively. SwiftUI + AppKit bridging gives the best integration with macOS idioms — `MenuBarExtra`, `NSPanel` floating windows, Keychain, and `UserNotifications` — while keeping the binary under 10 MB. ### 2. Poll-based sync, not push Feishu webhooks require a public-facing HTTP endpoint. For a personal tool, polling the Bitable API every N minutes is simpler, safer, and sufficient. Default interval: 5 minutes. ### 3. OAuth user_access_token with refresh Uses Feishu's OAuth 2.0 authorization code flow to get a `user_access_token` (valid 2h) and `refresh_token` (valid 30 days). Tokens are stored in the macOS Keychain. The app acts on behalf of the user — no admin approval needed. ### 4. No backend server Everything runs locally. No database, no server, no cloud hosting. The app stores only: - OAuth tokens (Keychain) - Configuration (UserDefaults: table ID, polling interval, etc.) - Cached bug state (in-memory, rebuilt on launch) ### 5. Menu bar first, floating widget second The menu bar popover is the primary interaction surface. The floating widget is an optional companion — a small always-on-top window showing the count, which clicks through to open the menu bar popover. ## Component Map | Component | Responsibility | |---|---| | `App` | `@main` entry, sets activation policy to `.accessory` (no dock icon) | | `AppDelegate` | Menu bar icon registration, window management | | `BugStore` | Central observable state: bug list, unseen count, loading/error | | `FeishuService` | HTTP client for Feishu Open API (bitable records, OAuth) | | `TokenManager` | OAuth flow orchestration, Keychain read/write, token refresh | | `PollerService` | Configurable timer driving the fetch cycle | | `NotificationService` | Diff engine + `UNUserNotificationCenter` push | | `MenuBarView` | Menu bar icon with badge count | | `BugListPopover` | Popover containing the scrollable bug list | | `BugRow` | Single bug: title, priority pill, age, clickable | | `FloatingWidget` | Optional `NSPanel`-based always-on-top overlay | | `SettingsWindow` | Preferences: table config, poll interval, widget toggle | | `KeychainHelper` | Thin wrapper around Security framework | ## Data Flow ``` 1. App Launch ├── Load tokens from Keychain ├── If no token → show OAuth setup window ├── If token expired → refresh via refresh_token └── Start PollerService 2. Poll Cycle (every 5 min, configurable) ├── FeishuService.fetchRecords(table_id, filter=assignee=me) ├── Parse response → [Bug] ├── BugStore.diff(old, new) │ ├── New bugs → NotificationService.fire() │ ├── Status changes → NotificationService.fire() │ └── Assignee changes → NotificationService.fire() └── BugStore.bugs = new; BugStore.lastUpdated = now 3. User Interaction ├── Click menu bar icon → toggle popover ├── Click bug in popover → open in Feishu (browser / Feishu app URL) ├── "Mark all seen" → reset badge count └── Floating widget click → open menu bar popover ``` ## Feishu API Surface | API | Method | Purpose | |---|---|---| | `/authen/v1/oidc/access_token` | POST | Exchange authorization code for user_access_token | | `/authen/v1/refresh_access_token` | POST | Refresh expired user_access_token | | `/bitable/v1/apps/{app_token}/tables/{table_id}/records` | GET | Fetch bug records with filter | All calls use `Authorization: Bearer ` and go to `https://open.feishu.cn`. ## Non-Functional Requirements - **Memory**: < 80 MB at steady state - **CPU**: idle < 0.1%, spike < 2% during poll - **Binary**: < 15 MB - **Startup**: < 2 seconds to menu bar icon visible - **Offline**: graceful degradation (show stale data, retry on next interval) - **macOS**: 14.0+ (Sonoma) — `MenuBarExtra` is stable from 13.3, but 14.0 is a reasonable floor for 2024+