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

216 lines
7.0 KiB
Markdown

# 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:
```json
{"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
```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/<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
```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 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