This document serves as an onboarding guide for developers contributing to the Flumen macOS app.
The app uses a Hybrid Architecture combining a native Swift wrapper with a React + TypeScript frontend. This provides full control over native macOS behaviors (tray icons, non-activating panels) while allowing for rapid UI development with modern web tools.
graph LR
Swift[Swift Native Wrapper] <--> Bridge[WKScriptMessageHandler]
Bridge <--> React[React Frontend]
Swift --> DB[SQLite Database]
Swift --> NS[NSStatusItem / NSPanel]
.
├── macos/Pomodoro/ # Native Swift Project (Swift Package Manager)
│ ├── Sources/ # Native source code
│ │ ├── Bridge.swift # Handle messages from JS to Swift
│ │ ├── DatabaseManager.swift # SQLite persistence layer
│ │ ├── WindowController.swift # NSPanel & WKWebView setup
│ │ └── StatusBarController.swift # Tray icon & right-click menu
├── src/ # React Frontend
│ ├── core/ # Pure logic (Timer, Session logic)
│ ├── state/ # Global state (Zustand stores)
│ ├── services/ # Bridge & Persistence abstractions
│ └── ui/ # React components & Design System
├── build_app.sh # Universal build & bundle script
└── index.html # Entry point with SVG grain filter
Communication between JavaScript and Swift happens through a custom bridge.
The NativeBridge object wraps window.webkit.messageHandlers.native.postMessage.
saveState(json): Writes app state to nativeUserDefaults(settings, tasks).db_logActivity(...): Logs focus sessions to the native SQLite database.db_getReports(): Requests aggregated report data from the database.db_exportCSV(): Triggers a native file save dialog for CSV export.updateMenuBar(text): Changes the status item title in the macOS menu bar.playClickSound(): Triggers nativeNSSoundplayback.
Messages are sent back to React using webView.evaluateJavaScript("window.receiveNativeMessage(...)").
- Action:
loadedState- Hydrates the frontend on launch. - Action:
menuAction- Responds to right-click tray menu clicks (Skip, Reset, etc.).
The app uses Zustand for state, split into three focused stores:
sessionStore.ts: Handles the timer, session cycles, and logic triggers.taskStore.ts: Manages the focus task list and project tags.statsStore.ts: Handles real-time logging and historical data aggregation.
Persistence: The PersistenceService subscribes to all three stores and debounces saves by 1 second. It bundles the state into a single JSON object which is then passed to the Swift layer for permanent storage.
The project is built using a custom build_app.sh script which automates:
- Building the React frontend via Vite.
- Compiling the Swift executable.
- Creating the
.appbundle structure. - Converting
icon.pnginto a native.icnsfile. - Ad-hoc signing the bundle (
codesign) to enable system notifications.
Developer Mode: In WindowController.swift, the app detects if it's running in Xcode or a debug build and automatically loads localhost:5173 instead of the bundled files for Hot Module Replacement.
- Grid: Base-8 grid system for all spacing and dimensions.
- Typography:
- DM Sans: Used for branding, headers, and reports.
- Inter: Used for utility, timer digits (tabular), and small text.
- Visuals: Styled with inline CSS objects for maximum portability and dynamic interaction (like the breath-sync blob animation).