# DearDiary - AI-Powered Daily Journal Self-hosted journaling app where users capture events throughout the day and AI generates diary pages. Events become immutable once a diary is generated (locked). ## Tech Stack - **Backend**: Bun + Hono + Prisma (SQLite) - **Frontend**: React + Vite + TypeScript + Tailwind CSS - **Database**: SQLite (file-based) - **Deployment**: Docker ## Project Structure ``` /backend /prisma schema.prisma # Database schema (models: User, Event, Journal, Task, Settings) /src index.ts # Main API routes, journal generation logic /services/ai # AI provider implementations (Groq, OpenAI, Anthropic, Ollama, LMStudio) /__tests__/ # API unit tests (Bun test) /frontend /src /pages # Page components (Dashboard, Home, Journal, Diary, Settings, Day, Tasks, Calendar) /components # Reusable components (QuickAddWidget, SearchModal, DateNavigator, EntryList, etc.) /lib api.ts # API client with typed methods geolocation.ts # Browser geolocation with reverse geocoding ThemeContext.tsx # Dark/light theme /www index.html # Product landing page /css # Stylesheets /js # JavaScript /docs # HTML documentation pages ``` ## Key Concepts ### Event vs Journal - **Event**: User input during the day (immutable after journal is generated) - **Journal**: AI-generated diary page from events (can regenerate, title + content) ### Terminology - "Diary Page" not "Journal" - "Event" not "Entry" - "Generate" not "Create" - "Rewrite" not "Regenerate" - "Today" is the event stream page (`/today`) ### Routes - `/` - Dashboard (recent diary pages with excerpts) - `/today` - Today's event stream (main capture page) - `/diary` - Paginated diary reader (10/50/100 per page) - `/journal/:date` - View/edit diary page with generation tasks - `/day/:date` - View day's events with DateNavigator - `/settings` - Configuration - `/calendar` - Month calendar view ## Database Schema ### Journal Model (key fields) ``` id, userId, date, title, content, eventCount, generatedAt ``` ### Task Model Stores generation attempts with full request/response JSON for debugging. ``` id, userId, journalId, type, status, provider, model, prompt, request, response, error, title, createdAt, completedAt ``` ### Event Model (key fields) ``` id, userId, date, type, content, mediaPath, metadata, latitude, longitude, placeName, createdAt ``` - Location is captured automatically from browser geolocation when creating events - Reverse geocoding via OpenStreetMap Nominatim API provides place names ### Settings Model ``` userId, aiProvider, aiApiKey, aiModel, aiBaseUrl, journalPrompt, language, timezone, providerSettings, journalContextDays, useSystemDefault ``` - `useSystemDefault`: When true, user uses system-default AI settings from environment variables ## API Design All endpoints return: `{ data: T | null, error: { code, message } | null }` ### Authentication - API key in `Authorization: Bearer ` header - Keys stored as SHA-256 hashes ### Key Endpoints ``` POST /api/v1/journal/generate/:date # Generate diary (with optional instructions) GET /api/v1/journal/:date # Get diary page DELETE /api/v1/journal/:date # Delete to unlock events GET /api/v1/journal/:date/tasks # Generation tasks (includes title per task) GET /api/v1/journals # List journals with pagination (?page=1&limit=10) GET /api/v1/days # List days with journal info (includes excerpt) POST /api/v1/events # Create event GET /api/v1/export # Export all user data (JSON) POST /api/v1/import # Import data (with version checking) ``` ## Export/Import ### Export Format Exports include: - `version`: DearDiary version string (e.g., "0.1.0") - `exportedAt`: ISO timestamp of export - `settings`: User settings including AI provider configuration - `events`: All user events (includes latitude, longitude, placeName) - `journals`: All generated diary pages - `tasks`: All generation tasks ### Version Compatibility - Minimum supported import version: 0.0.3 - Import validates version compatibility - Warns if importing older/newer version - Older exports may fail or lose data ### Import Behavior - Duplicates are skipped (based on date + content + timestamp for events) - Journals matched by date - Tasks linked to journals by date - Settings are overwritten ## AI Integration ### Providers - Groq (default, uses llama-3.3-70b-versatile) - OpenAI - Anthropic - Ollama (local) - LM Studio (local) ### Prompt System - Default system prompt is defined in `backend/src/index.ts` (hardcoded, not user-configurable) - User can add custom instructions via `settings.journalPrompt` field (labeled "Prompt" in UI) - Custom instructions are prepended to the default prompt when set - Default prompt includes anti-hallucination rules and structure guidelines ### JSON Mode AI is configured to return JSON with `response_format: { type: "json_object" }` where supported. Journal generation prompts instruct AI to return: ```json {"title": "Short title", "content": "Diary text..."} ``` ### Provider Settings Storage Settings stored as `providerSettings: { "groq": { apiKey, model, baseUrl }, ... }` with `aiProvider` determining which is active. ### System Default AI Configuration Administrators can configure default AI settings via environment variables that apply to all new users: ``` BACKEND_DEFAULT_AI_PROVIDER="groq" BACKEND_DEFAULT_AI_MODEL="llama-3.3-70b-versatile" BACKEND_DEFAULT_AI_API_KEY="" BACKEND_DEFAULT_AI_BASE_URL="" ``` - New users automatically use system defaults (`useSystemDefault: true`) - Users can override with their own settings by unchecking "Use system default settings" - When `useSystemDefault` is true, the system ignores user's individual AI settings and uses env defaults ## Coding Guidelines ### TypeScript - Use explicit interfaces for API responses - Avoid `any` types - Use optional chaining and nullish coalescing ### React Components - Functional components with hooks - Props interfaces defined at top of file - Use `useState` for local state, `useEffect` for data loading ### Tailwind CSS - Dark theme by default (slate color palette) - Use `text-slate-400` for muted text - Use `purple-*` for primary actions - Use `slate-900` for cards/containers ### API Response Handling ```typescript const res = await api.someMethod(); if (res.error) { // handle error } else if (res.data) { // use res.data } ``` ### Error Handling - Backend returns `{ code, message }` errors - Frontend displays errors inline or as toast notifications - Generation errors shown in red banner ## Common Tasks ### Adding a new AI provider 1. Create `/backend/src/services/ai/.ts` 2. Implement `AIProvider` interface with `generate(prompt, systemPrompt, options?)` 3. Add to `provider.ts` `createAIProvider()` switch 4. Add `jsonMode` parsing if supported ### Database migrations ```bash cd backend bunx prisma migrate dev --name migration_name ``` ### Docker rebuild ```bash docker compose build && docker compose up -d ``` ### Running Tests ```bash cd backend bun run test:server ``` Tests require the server running. The test script starts the server, runs tests, then stops it. ## Version Management Version is managed via `VERSION.txt` (single source of truth). All other version references (`backend/package.json`, `frontend/package.json`, `backend/src/index.ts`) use placeholder `{{VERSION}}` and are replaced at build time. ### Versioning Rules - Bump micro version (0.1.x) on every commit - Update `VERSION.txt` before committing - Never commit actual version numbers in source files ## Version History - 0.1.6: Add comprehensive API docs and additional documentation pages - 0.1.5: Fix ENV syntax in website Dockerfile - 0.1.4: Version links to git releases on website - 0.1.3: Add VERSION to website build - 0.1.2: VERSION.txt build-time injection, docs nav fixes, blog link - 0.1.1: System default AI configuration via env vars, "Use system default" checkbox in settings - 0.1.0: Automatic geolocation capture, Starlight documentation site - 0.0.6: Automatic geolocation capture on event creation, reverse geocoding to place names - 0.0.5: Export/Import feature with version checking - 0.0.4: /diary page with pagination (10/50/100), Task.title field, dashboard excerpts - 0.0.3: AI returns JSON with title + content, UI shows titles - 0.0.2: Dashboard, Quick Add widget (Ctrl+J), rewrite modal - 0.0.1: Initial release with Entry->Event terminology fix