Files
deardiary/AGENTS.md
2026-03-27 10:42:47 +00:00

7.0 KiB

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

API Design

All endpoints return: { data: T | null, error: { code, message } | null }

Authentication

  • API key in Authorization: Bearer <key> 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:

{"title": "Short title", "content": "Diary text..."}

Provider Settings Storage

Settings stored as providerSettings: { "groq": { apiKey, model, baseUrl }, ... } with aiProvider determining which is active.

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

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/<provider>.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

cd backend
bunx prisma migrate dev --name migration_name

Docker rebuild

docker compose build && docker compose up -d

Running Tests

cd backend
bun run test:server

Tests require the server running. The test script starts the server, runs tests, then stops it.

Version History

  • 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