Initial commit: deardiary project setup
This commit is contained in:
444
PLAN.md.old
Normal file
444
PLAN.md.old
Normal 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).
|
||||
Reference in New Issue
Block a user