# Privatefolio Docs > Documentation for users & developers. ## AI setup ### Overview * Leverages Vercel AI SDK for an interactive portfolio analysis assistant in both frontend and backend. * Users chat with an AI that can query on-chain data, run SQL via tools, and fetch current market info via web search. ### Providers & SDKs * **Vercel AI SDK** (`ai`, `@ai-sdk/react`, `@ai-sdk/ui-utils`): powers chat streaming and UI hooks in the frontend. * **OpenAI** (`@ai-sdk/openai` v1.3.22): used for chat completions and tool-enabled search via `createOpenAI().responses(modelId)` and `tools.webSearchPreview()`. * **Anthropic** (`@ai-sdk/anthropic` v1.2.12): language models via `createAnthropic({ apiKey }).languageModel(modelId)`. * **Perplexity** (`@ai-sdk/perplexity` v1.1.9): language models via `createPerplexity({ apiKey }).languageModel(modelId)`. ### Frontend Integration * **Assistant Page**: `packages/frontend/src/pages/AssistantPage/AssistantPage.tsx` sets up tabs and routes. * **Chat UI**: `AssistantChat.tsx` uses `useChat` from `@ai-sdk/react` to manage messages, stream responses, and handle stops. * **State Management**: nanostores (`$assistantModel`, `$assistantMode`, `$activeAccount`) control model selection and account context. * **UI Components**: model selector (`AssistantModelSelect.tsx`), settings (`AssistantSettings.tsx`), message toolbar and history components. ### Backend / API Integration * **Assistant HTTP API**: `packages/backend/src/api/account/assistant-http-api.ts` exports `handleAssistantChat`. * Endpoint: `POST /assistant-chat` * Request: JSON `{ accountName, id (conversationId), modelId, messages: Message[] }`. * Response: chunked streaming (`Transfer-Encoding: chunked`) via `streamText` from Vercel AI SDK. * **Business Logic**: * Fetch encrypted API key (`getApiKey`) from KV store. * Select model and provider options based on `model.family` and `model.capabilities`. * Assemble system prompt (`getAssistantSystemPrompt` in `settings/assistant.ts`). * Initialize tools (`getAssistantTools`) for on-chain data access. * **Chat Persistence**: `assistant-api.ts` provides upsert and query functions (`upsertChatMessage`, `getChatHistoryByConversation`). ### Environment Variables & Configuration * **Backend Service**: * `JWT_SECRET`: decrypts per-account AI keys stored in KV. * `PORT`: HTTP server port (default 5555). * **Provider Credentials** (per account, stored encrypted in KV): * `assistant_openai_key` (prefixed `sk-`) * `assistant_anthropic_key` (prefixed `sk-ant-`) * `assistant_perplexity_key` (prefixed `pplx-`) ### Prompt & Model Management * **System Prompt**: template in `packages/backend/src/settings/assistant.ts` via `getAssistantSystemPrompt`, includes timestamp and tool descriptions. * **Models**: definitions in `packages/backend/src/settings/assistant-models.ts`, listing IDs, families, capabilities, context windows, and cost per 1k tokens. * **Metadata**: each chat message stores `modelId`, `usage`, `finishReason`, and prompt context in JSON metadata. ### Development & Testing * **Local Setup**: run `yarn dev` (frontend & backend) or `yarn dev:electron` for desktop. * **AI Keys**: load provider API keys into KV using the `AuthSecrets` mechanism and `assistant_*_key` entries. * **Testing**: * Frontend: `packages/frontend` uses Vitest and mocks `useChat` as needed. * Backend: run `vitest` in `packages/backend`, stub `streamText` or mock `createOpenAI`/`createAnthropic` calls. ### Security & Cost Considerations * Store AI keys encrypted; never log raw keys. * Monitor token usage via metadata (`usage` returned by `streamText`) and use cost settings in `assistant-models.ts`. * Choose smaller, cost-efficient models (`o4-mini`, `gpt-4.1-mini`) when high throughput is needed. * Rate limits and authentication enforced via JWT and per-account secrets; no built-in rate throttling in AI API layer—implement externally if needed. ## Backend ### Overview Privatefolio Backend is a Node.js/Bun service that aggregates multi-chain cryptocurrency data, provides a REST and WebSocket API, and persists data in a local SQLite database. It powers the desktop app and frontend with real-time account balances, transactions, and price history. ### Architecture ``` Frontend <── HTTP/WebSocket ──> Backend Server <── API SDK ──> Data Aggregator (Relayer) │ └── SQLite (persistent storage) ``` * **API Server** handles HTTP routes and WebSocket RPC for frontend communication. * **Backend Relayer** schedules tasks for data fetching, processing, and side-effects. * **Database** uses SQLite for fast, local persistence. * **Utilities** provide config management, process control, and inter-service communications. ### Package structure ```text packages/backend/ ├── src/ │ ├── api/ # HTTP & WebSocket API definitions │ ├── config/ # Environment and settings loaders │ ├── sqlite/ # Schema and migration logic │ ├── utils/ # Helper functions │ ├── backend-server.ts # HTTP/WebSocket server implementation │ ├── backend-relayer.ts # Task scheduler and data aggregator │ └── start.ts # Entry point wiring server + relayer ├── data/ # Runtime database and log files ├── build/ # Compiled outputs for production ├── test/ # Vitest test suites organized by feature └── package.json # Scripts, dependencies, and build setup ``` ### Core Components * **API Server** (`src/backend-server.ts`): serves REST (`/ping`, `/info`, `/download`, `/upload`) and WebSocket RPC. Serves static frontend build. * **Backend Relayer** (`src/backend-relayer.ts`, `src/start.ts`): uses Cron via `croner` and audit-log subscriptions to enqueue data tasks (balances, prices, net worth). * **Database** (`src/sqlite/`): initializes and migrates SQLite database; defines interfaces in `src/interfaces.ts`. * **Utilities** (`src/utils/`, `src/backend-comms.ts`): config parsing, throttling, file upload/download handlers, and inter-process messaging. * **Configuration** (`src/server-env.ts`, `src/settings.ts`): loads environment variables (PORT, APP\_VERSION, GIT\_HASH, GIT\_DATE) and default settings (throttle durations, data dirs). ### API Endpoints * **HTTP** * `GET /ping` → `pong` * `GET /info` → build metadata (version, commit, build date) * `GET /download` & `POST /upload` → file operations for account backups * `OPTIONS /*` → CORS preflight * Static file serving from frontend build * **WebSocket RPC** * Dynamic method invocation: send `{ id, method, params }`, receives `{ id, result }` or error. * Supports callback functions via `FunctionReference` messages. ### Database * Uses SQLite via `sqlite3` (Node.js) and `sqlite` (Bun) packages. * Database files located under `packages/backend/data/databases/`. * Schema and migrations defined in `src/sqlite/`; initialized on startup. * Data access via typed interfaces (`src/interfaces.ts`). ### Configuration * Environment variables: * `PORT` (default 4001 dev, 5555 prod) * `APP_VERSION`, `GIT_HASH`, `GIT_DATE` (populated from git/npm) * `DATA_LOCATION` (overrides default data directory) * `BUN_SQL`, `GITHUB_CI` (test flags) * Settings file: `src/settings.ts` defines throttle durations and cron schedule. ### Development Prerequisites: Node.js v20+, Bun, Yarn. ```sh yarn # install dependencies yarn build # compile TypeScript & build frontend yarn dev # runs backend (watch) + relayer ``` ### Testing ```sh yarn test # run Vitest (Node SQLite) yarn test:bun # run Bun-specific SQLite tests yarn test:ci # CI mode (Node + Bun) ``` Tests located in `packages/backend/test/` organized by feature (e.g., `balances`, `tags`, `bun`). ### Deployment ```sh # build production bundle yarn build # Docker image build & run (from packages/backend) yarn docker:build yarn docker:run yarn docker:remove ``` In Electron, backend is started automatically on app launch. ## Desktop Apps This document describes the Electron setup for the Privatefolio desktop application. ### Overview Privatefolio uses Electron to package and distribute the frontend as a desktop application. The Electron setup is located in the `packages/electron` directory and is built using Electron Forge. ### Project Structure ``` packages/electron/ ├── build/ # Output directory for compiled TypeScript ├── out/ # Output directory for packaged app ├── src/ # Source code │ ├── api.ts # API definitions │ ├── backend-manager.ts # Backend process manager │ ├── ipc-main.ts # IPC communication setup │ ├── preload.ts # Preload script for renderer │ ├── start.ts # Main entry point │ └── utils.ts # Utility functions ├── forge.config.js # Electron Forge configuration ├── package.json # Package configuration └── tsconfig.json # TypeScript configuration ``` ### Main Components #### Entry Point (`start.ts`) The main entry point for the Electron app handles: * Window creation and configuration * System tray setup * Development reloading (when not in production) * Custom title bar configuration * App lifecycle management * Starting and stopping the backend server #### Backend Manager (`backend-manager.ts`) Manages the backend server process: * Starting the backend server when the app starts * Keeping the backend running when the app is minimized to tray * Stopping the backend server when the app is closed * Provides methods to check if the backend is running * Handles backend server port management #### IPC Communication (`ipc-main.ts`) Handles communication between the main and renderer processes: * Notifications * Theme mode switching * Log directory access * Log reading * Backend server management (getting URL, checking status, restarting) #### Preload Script (`preload.ts`) Exposes a secure API to the renderer process via the contextBridge: * Notification sending * Log access * Platform information * Theme mode switching * Backend server operations (getting URL, checking status, restarting) ### Build Process The application uses Electron Forge for packaging and distribution: 1. TypeScript is compiled to JavaScript (`yarn build`) 2. Icons are generated from source images (`yarn gen-icons`) 3. The app is packaged with Electron Forge (`yarn package`) 4. Platform-specific installers are created (`yarn bundle:win`, `yarn bundle:linux`, `yarn bundle:mac`) ### Development To start the development environment: ```bash yarn dev ``` This command: 1. Compiles TypeScript in watch mode 2. Starts Electron with hot reloading enabled 3. Starts the backend server automatically ### Production Builds To create production builds: ```bash # Build for development yarn build # Create production installers yarn bundle:win yarn bundle:linux yarn bundle:mac ``` The build process creates platform-specific installers: * Windows: Nsis installer (.exe) * macOS: ZIP archive * Linux: DEB and RPM packages ### Configuration The application uses `electron-forge` for building and packaging, with configuration in `forge.config.js`. Key configurations include: * Custom app icons * App metadata * Build targets per platform * Dependency inclusion rules ### Backend Integration The Electron app integrates with the Privatefolio backend server: 1. In production, the backend server is started automatically when the app starts 2. In development, the backend server is started separately by lerna, not by the Electron app 3. The backend continues running when the app is minimized to tray 4. The backend is gracefully stopped when the app is closed (in production) 5. The frontend communicates with the backend via HTTP/WebSocket on localhost 6. Different ports are used in development (4001) and production (5555) #### Development Setup In development mode: * The backend server is started by lerna through the `yarn dev` command in the root directory * The Electron app connects to this already-running backend server * The backend runs on port 4001 #### Production Setup In production mode: * The backend server is started by the Electron app itself * The backend process is managed by the BackendManager * The backend runs on port 5555 #### Backend API Access The frontend can access backend functionality through the Electron preload API: ```typescript // Get the backend URL (which includes the correct port based on environment) const backendUrl = window.electron.backend.getUrl(); // Check if the backend is running const isRunning = window.electron.backend.isRunning(); // Restart the backend if needed (only works in production) await window.electron.backend.restart(); ``` ### Privatefolio Expo (Mobile) Setup This document explains how to run, build, and publish the Privatefolio mobile app powered by Expo. #### Overview * The mobile app currently wraps the hosted web app in a React Native `WebView` and provides a native shell for distribution on iOS/Android. Native features can be layered in incrementally. * Source lives in `packages/expo` and uses Expo SDK 53, React 19, React Native 0.79. #### Project Layout * `packages/expo/package.json`: scripts and dependencies * `packages/expo/eas.json`: EAS build/submit profiles * `packages/expo/app.json`: Expo config (name, icons, Android package, splash, plugin config) * `packages/expo/app/index.tsx`: App entry using `WebView` pointing to `https://privatefolio.app` #### Prerequisites * Node.js 20+ * Yarn 1.x (workspaces) * Expo tooling: you can use `npx expo` without a global install * For EAS builds: `eas-cli` (`yarn` will install it locally) and an Expo account (`eas login`) #### Install Dependencies From the repository root: ```bash yarn ``` #### Run in Development You can run from the workspace root using Yarn workspaces or by `cd` into the package. Option A (from root, via workspace): ```bash yarn workspace privatefolio-expo dev ``` Option B (inside the package): ```bash cd packages/expo yarn dev # starts Expo with a tunnel # or yarn dev:android # open Android emulator/device yarn dev:ios # open iOS simulator (macOS) yarn dev:web # run via web target ``` Notes: * First run will prompt you to open the app on a device/simulator or a browser. * If Metro cache causes issues, restart with `npx expo start -c`. #### What the App Does (Today) `packages/expo/app/index.tsx` renders a `WebView` pointing to `https://privatefolio.app` with sensible defaults (loading spinner, storage enabled, mixed content compatibility for charts, etc.). This enables a fast mobile presence while preserving the web UI. The `app.json` sets the deeplink scheme to `privatefolio` for future use. #### Configuration Reference * `package.json` (scripts & deps) * `dev`, `dev:android`, `dev:ios`, `dev:web` * EAS: `build:*`, `submit:*`, `publish` * Key deps: `expo`, `expo-router`, `react-native-webview`, `@react-navigation/native` * `app.json` (Expo config) * Name/slug: `Privatefolio` / `privatefolio` * Scheme: `privatefolio` (deeplinks like `privatefolio://`) * Android: package `xyz.privatefolio.mobile`, edge-to-edge enabled, adaptive icon * Web: uses `metro` bundler, static output for previews * Plugins: `expo-router`, `expo-splash-screen` * `eas.json` (EAS profiles) * `build.production`: auto-increment version, caching enabled * `submit.production.android`: uses `GOOGLE_SERVICE_ACCOUNT_KEY_PATH` for Play Store submission, track `production` #### Building with EAS Login once (only needed on a new environment): ```bash npx eas login ``` Build commands (run from repo root or `packages/expo`): ```bash yarn workspace privatefolio-expo bundle:android yarn workspace privatefolio-expo bundle:ios ``` Artifacts are created on EAS servers; the CLI will provide download/install links. #### Submitting to Stores Android (requires a Google Cloud service account JSON with Play Console access): ```bash export GOOGLE_SERVICE_ACCOUNT_KEY_PATH=/absolute/path/to/google-service-account.json yarn workspace privatefolio-expo submit:android ``` iOS submission requires App Store Connect credentials and an Apple Developer account: ```bash yarn workspace privatefolio-expo submit:ios ``` You can chain build+submit via: ```bash yarn workspace privatefolio-expo publish ``` #### App Identity and Linking * Android package: `xyz.privatefolio.mobile` * Deeplink scheme: `privatefolio://` (reserved for future native navigation/deeplinks) * If you add native navigation in the future, use `expo-linking` to handle incoming URLs and map them to screens. #### Permissions The `WebView` enables geolocation and file access. If you add native geolocation or file pickers, declare platform permissions in `app.json` and follow Expo documentation for permissions prompts. #### Troubleshooting * Clear Metro cache: `npx expo start -c` * Kill stray Metro processes: close all `expo start` processes and restart * Android emulator not detected: ensure Android Studio SDK tools and AVD are installed; run `adb devices` * iOS simulator boot issues: open Xcode once and accept license; run `xcrun simctl list devices` #### Roadmap for Native Enhancements (Optional) * Add account storage using secure storage modules * Implement push notifications for balance alerts * Integrate native share sheets and file import/export * Use `expo-router` to progressively introduce native screens #### Notes * This is a Yarn workspaces monorepo; prefer running scripts via `yarn workspace privatefolio-expo