Initial commit: deardiary project setup

This commit is contained in:
lotherk
2026-03-26 19:57:20 +00:00
commit 3f9bc1f484
73 changed files with 8627 additions and 0 deletions

444
PLAN.md.old Normal file
View File

@@ -0,0 +1,444 @@
# TotalRecall - AI-Powered Daily Journal
> Your day, analyzed. A journal that writes itself.
---
## Concept
TotalRecall is a privacy-first, self-hostable daily journal application that captures life through multiple input methods (text, photos, voice, data) and uses AI to generate thoughtful, reflective journal entries at the end of each day.
The core philosophy: **your data is yours**. Whether you host it yourself or use a hosted service, you own everything. The same codebase runs everywhere.
---
## The Problem
- Most journaling apps are siloed, paid, or data-mining platforms
- Manual journaling is time-consuming and inconsistent
- People capture moments (photos, voice memos, scattered notes) but never reflect on them
- AI tools exist but require manual input of context
## The Solution
TotalRecall aggregates all your daily inputs throughout the day, then at your command (or scheduled), sends everything to an AI to synthesize your day into a coherent, reflective journal entry.
---
## Features
### Input Capture
| Type | Description | Storage |
|------|-------------|---------|
| **Text Notes** | Quick thoughts, feelings, observations | Markdown |
| **Photos** | Camera or gallery uploads | JPEG/PNG in media folder |
| **Voice Memos** | Audio recordings | WebM/Opus |
| **Location** | Optional GPS tagging of entries | Lat/long metadata |
| **Health Data** | Manual entry (steps, mood, sleep) | JSON metadata |
### AI Journal Generation
- Aggregates all entries for a day
- Sends to configurable AI provider
- Generates reflective, narrative journal entry
- Stores generated journal alongside raw entries
### AI Provider Support (Pluggable)
- **OpenAI** - GPT-4, GPT-4-Turbo, GPT-3.5
- **Anthropic** - Claude 3 Opus, Sonnet, Haiku
- **Ollama** - Local LLM (Llama, Mistral, etc.)
- **LM Studio** - Local LLM with OpenAI-compatible API
---
## Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ End User │
│ │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ Web App │ │ Mobile App │ │
│ │ (React/PWA) │ │ (Future: iOS) │ │
│ └─────────┬──────────┘ └─────────┬──────────┘ │
│ │ │ │
│ └──────────┬─────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ REST API │ │
│ │ /api/v1/* │ │
│ │ │ │
│ │ - Authentication │ │
│ │ - Entries CRUD │ │
│ │ - Journal Gen │ │
│ │ - Settings │ │
│ └──────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ SQLite Database │ │
│ │ + Media Storage │ │
│ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```
### Tech Stack
| Layer | Technology | Reason |
|-------|------------|--------|
| Backend Runtime | **Bun** | Fast startup, native TypeScript, small Docker image |
| API Framework | **Hono** | Lightweight, fast, works everywhere |
| Database | **SQLite / MySQL / PostgreSQL** (via Prisma ORM) | Switch databases with one line, zero-config for SQLite |
| Frontend | **React + Vite** | Fast dev, PWA capable |
| Styling | **Tailwind CSS** | Rapid UI development |
| Container | **Docker + Docker Compose** | One-command deployment |
---
## Deployment Modes
TotalRecall runs the same codebase whether self-hosted or on a SaaS platform.
### Single-User (Self-Hosted)
```yaml
services:
totalrecall:
image: ghcr.io/totalrecall/totalrecall:latest
ports:
- "3000:3000"
volumes:
- ./data:/data
```
- Users create accounts locally
- No external dependencies
- One Docker command to run
### Multi-Tenant (SaaS)
```yaml
services:
totalrecall:
image: ghcr.io/totalrecall/totalrecall:latest
ports:
- "3000:3000"
environment:
- DEPLOYMENT_MODE=multi-tenant
- JWT_SECRET=${JWT_SECRET}
- DATABASE_URL=file:/data/totalrecall.db
volumes:
- ./data:/data
```
- Multiple users with accounts
- API key authentication
- Same features as self-hosted
---
## API Design
### Authentication
```
Authorization: Bearer {api_key}
```
All requests (except auth endpoints) require a valid API key.
### Endpoints
```
POST /api/v1/auth/register # Create account
POST /api/v1/auth/login # Get API key
POST /api/v1/auth/logout # Invalidate session
GET /api/v1/days # List days with entries
GET /api/v1/days/:date # Get day's data (entries + journal)
DELETE /api/v1/days/:date # Delete day and all entries
POST /api/v1/entries # Create entry
GET /api/v1/entries/:id # Get entry
PUT /api/v1/entries/:id # Update entry
DELETE /api/v1/entries/:id # Delete entry
POST /api/v1/entries/:id/photo # Upload photo to entry
POST /api/v1/entries/:id/voice # Upload voice to entry
POST /api/v1/journal/generate/:date # Generate AI journal for date
GET /api/v1/journal/:date # Get generated journal
GET /api/v1/settings # Get user settings
PUT /api/v1/settings # Update settings (AI provider, etc.)
GET /api/v1/health # Health check (no auth)
```
### Response Format
```typescript
// Success
{ "data": { ... }, "error": null }
// Error
{ "data": null, "error": { "code": "NOT_FOUND", "message": "Entry not found" } }
```
---
## Data Models
### User
```typescript
interface User {
id: string; // UUID
email: string; // Unique
passwordHash: string; // bcrypt
createdAt: string; // ISO timestamp
}
```
### API Key
```typescript
interface ApiKey {
id: string;
userId: string;
keyHash: string; // SHA-256 hash, not stored plaintext
name: string; // "iPhone", "Web", etc.
lastUsedAt: string;
createdAt: string;
}
```
### Entry
```typescript
type EntryType = 'text' | 'voice' | 'photo' | 'health' | 'location';
interface Entry {
id: string;
userId: string;
date: string; // YYYY-MM-DD
type: EntryType;
content: string; // Text or metadata JSON
mediaPath?: string; // Path to uploaded file
metadata?: {
source?: 'manual' | 'health' | 'calendar';
location?: { lat: number; lng: number };
duration?: number; // For voice entries
[key: string]: unknown;
};
createdAt: string;
}
```
### Journal
```typescript
interface Journal {
id: string;
userId: string;
date: string; // YYYY-MM-DD
content: string; // Markdown
entryCount: number; // How many entries were used
generatedAt: string;
}
```
### Settings
```typescript
interface Settings {
userId: string;
aiProvider: 'openai' | 'anthropic' | 'ollama' | 'lmstudio';
aiConfig: {
// Provider-specific config (API keys stored encrypted)
model?: string;
baseUrl?: string; // For Ollama/LM Studio
};
journalPrompt?: string;
language: string;
}
```
---
## File Storage
```
/data/
├── totalrecall.db # SQLite database
└── media/
└── {user_id}/
└── {date}/
├── entry-{uuid}.webm # Voice recordings
└── entry-{uuid}.jpg # Photos
```
---
## Project Structure
```
totalrecall/
├── backend/
│ ├── src/
│ │ ├── index.ts # Entry point
│ │ ├── app.ts # Hono app setup
│ │ ├── routes/
│ │ │ ├── auth.ts # Registration, login
│ │ │ ├── days.ts # Day operations
│ │ │ ├── entries.ts # Entry CRUD
│ │ │ ├── journal.ts # Journal generation
│ │ │ └── settings.ts # User settings
│ │ ├── services/
│ │ │ ├── db.ts # Database connection
│ │ │ ├── storage.ts # File storage operations
│ │ │ └── ai/
│ │ │ ├── mod.ts # Provider interface
│ │ │ ├── openai.ts
│ │ │ ├── anthropic.ts
│ │ │ └── ollama.ts
│ │ ├── middleware/
│ │ │ └── auth.ts # API key validation
│ │ └── types.ts
│ ├── prisma/
│ │ └── schema.prisma # Database schema
│ ├── Dockerfile
│ └── package.json
├── frontend/
│ ├── src/
│ │ ├── main.tsx
│ │ ├── App.tsx
│ │ ├── pages/
│ │ │ ├── Home.tsx # Today's view
│ │ │ ├── History.tsx # Browse past days
│ │ │ ├── Journal.tsx # View generated journals
│ │ │ └── Settings.tsx # Configuration
│ │ ├── components/
│ │ │ ├── EntryInput.tsx
│ │ │ ├── PhotoCapture.tsx
│ │ │ ├── VoiceRecorder.tsx
│ │ │ ├── EntryList.tsx
│ │ │ └── JournalView.tsx
│ │ ├── lib/
│ │ │ └── api.ts # API client
│ │ └── hooks/
│ ├── Dockerfile
│ └── package.json
├── docker-compose.yml # Full stack
├── docker-compose.prod.yml # Production overrides
├── Dockerfile # Multi-stage build
└── README.md
```
---
## Implementation Phases
### Phase 1: Backend Foundation ✅
- [x] Bun + Hono setup
- [x] Prisma ORM with SQLite (dev) / PostgreSQL (prod)
- [x] User registration & login (JWT)
- [x] API key authentication
- [x] Basic CRUD routes
### Phase 2: Data Management ✅
- [x] Entry CRUD with media support
- [x] File upload handling (photos, voice)
- [x] Day aggregation queries
- [x] Media file storage
### Phase 3: AI Integration ✅
- [x] AI provider interface
- [x] OpenAI implementation
- [x] Anthropic implementation
- [x] Ollama implementation
- [x] Journal generation endpoint
### Phase 4: Frontend Core ✅
- [x] React + Vite setup
- [x] API client library
- [x] Authentication flow
- [x] Home page (today's entries)
- [x] Entry creation (text input)
### Phase 5: Media Inputs ✅
- [x] Photo capture/upload
- [x] Voice recording
- [x] Entry list with media preview
### Phase 6: Journal & Settings ✅
- [x] Journal viewing
- [x] Settings page
- [x] AI provider configuration
- [x] Prompt customization
### Phase 7: Deployment ✅
- [x] Docker multi-stage build
- [x] Docker Compose setup
- [x] Health checks
- [ ] PWA manifest
### Phase 8: Future
- [ ] iOS app (SwiftUI)
- [ ] Android app (Kotlin)
- [ ] Calendar integration
- [ ] Health data sync
---
## Security Considerations
- API keys hashed with SHA-256 (never stored plaintext)
- Passwords hashed with bcrypt
- CORS configurable for domain restriction
- Rate limiting on auth endpoints
- File upload validation (type, size)
- SQL injection prevention via ORM
---
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `DATABASE_URL` | `file:./data/totalrecall.db` | SQLite/PostgreSQL/MySQL connection |
| `MEDIA_DIR` | `./data/media` | Directory for uploaded files |
| `JWT_SECRET` | (required) | Secret for JWT signing |
| `PORT` | `3000` | Server port |
| `CORS_ORIGIN` | `*` | Allowed origins |
| `RATE_LIMIT` | `100/hour` | Auth endpoint rate limit |
### Database Connection Examples
```bash
# SQLite (development, default)
DATABASE_URL="file:./data/totalrecall.db"
# PostgreSQL (production)
DATABASE_URL="postgresql://user:password@localhost:5432/totalrecall"
# MySQL
DATABASE_URL="mysql://user:password@localhost:3306/totalrecall"
```
---
## Licensing
This project is open source under [MIT License](LICENSE). You are free to:
- Use it for yourself
- Host it for others
- Modify and redistribute
No attribution required (but appreciated).