From 5b51de12147abb7db1bf7dc880d832597ecae2a8 Mon Sep 17 00:00:00 2001 From: lotherk Date: Fri, 27 Mar 2026 13:56:47 +0000 Subject: [PATCH] docs: update README, clean up old files --- Dockerfile.old | 46 ---- PLAN.md.old | 444 ------------------------------------ README.md | 55 +++-- README.md.old | 130 ----------- docker-compose.prod.yml.old | 30 --- docker-compose.yml.old | 24 -- nginx.conf.old | 21 -- 7 files changed, 34 insertions(+), 716 deletions(-) delete mode 100644 Dockerfile.old delete mode 100644 PLAN.md.old delete mode 100644 README.md.old delete mode 100644 docker-compose.prod.yml.old delete mode 100644 docker-compose.yml.old delete mode 100644 nginx.conf.old diff --git a/Dockerfile.old b/Dockerfile.old deleted file mode 100644 index 06b039a..0000000 --- a/Dockerfile.old +++ /dev/null @@ -1,46 +0,0 @@ -# Multi-stage build: Backend + Frontend -FROM oven/bun:1.1-alpine AS backend-builder - -WORKDIR /app/backend -COPY backend/package*.json ./ -RUN bun install -COPY backend/prisma ./prisma -RUN bunx prisma generate -COPY backend/src ./src -RUN bun build src/index.ts --outdir ./dist --target bun - -FROM node:20-alpine AS frontend-builder - -WORKDIR /app/frontend -COPY frontend/package*.json ./ -RUN npm install -COPY frontend ./ -RUN npm run build - -FROM oven/bun:1.1-alpine AS runner - -WORKDIR /app - -ENV NODE_ENV=production - -RUN addgroup --system --gid 1001 nodejs || true - -# Install nginx for serving frontend -RUN apk add --no-cache nginx - -# Copy backend -COPY --from=backend-builder /app/backend/dist ./dist -COPY --from=backend-builder /app/backend/node_modules ./node_modules -COPY backend/package.json . -COPY backend/prisma ./prisma - -# Copy frontend build -COPY --from=frontend-builder /app/frontend/dist ./public - -# Setup nginx -COPY nginx.conf /etc/nginx/http.d/default.conf - -RUN mkdir -p /data /run /app/nginx_tmp /var/lib/nginx/logs && chmod 777 /var/lib/nginx/logs /var/lib/nginx/tmp && chown -R bun:nodejs /data /app - -# Start everything as root -CMD sh -c "nginx -g 'daemon off;' & bunx prisma db push --accept-data-loss & bun ./dist/index.js" diff --git a/PLAN.md.old b/PLAN.md.old deleted file mode 100644 index a3ffbb1..0000000 --- a/PLAN.md.old +++ /dev/null @@ -1,444 +0,0 @@ -# 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). diff --git a/README.md b/README.md index 8000fad..75228b7 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ Self-hosted AI-powered daily journaling application. Capture events throughout the day and let AI generate thoughtful diary pages from your entries. -[![Deploy to Docker](https://img.shields.io/badge/Deploy-Docker-blue)](https://github.com/lotherk/deardiary) - ## Features - Quick event capture with keyboard shortcut (Ctrl+J) @@ -25,33 +23,47 @@ Self-hosted AI-powered daily journaling application. Capture events throughout t ```bash # Clone the repository -git clone https://github.com/lotherk/deardiary.git +git clone git@git.kropa.tech:lotherk/deardiary.git cd deardiary +# Configure environment (optional - defaults work out of box) +cp .env.example .env + # Start with Docker docker compose up -d ``` -Access the app at `http://localhost:5173` +Access the app at `http://localhost:3000` Default credentials: `admin@localhost` / `changeme123` -## Documentation - -Documentation is included in the `www/` directory. Run the website container: - -```bash -docker compose up -d docs -``` - -Access at `http://localhost:4000` - ## Configuration -1. Go to Settings and select your AI provider (Groq, OpenAI, Anthropic, Ollama, LM Studio) -2. Enter your API key for the selected provider -3. Optionally customize the model and base URL -4. Test the connection before saving +### Environment Variables + +Copy `.env.example` to `.env` and configure: + +```bash +# Backend +BACKEND_JWT_SECRET=your-secret-key +BACKEND_DEFAULT_USER_EMAIL=admin@example.com +BACKEND_DEFAULT_USER_PASSWORD=your-password + +# Default AI for new users (optional) +BACKEND_DEFAULT_AI_PROVIDER=groq +BACKEND_DEFAULT_AI_MODEL=llama-3.3-70b-versatile +BACKEND_DEFAULT_AI_API_KEY=your-api-key + +# Website links (for product website) +WEBSITE_APP_URL=https://your-app.example.com +GIT_URL=https://git.kropa.tech/lotherk/deardiary +``` + +### AI Providers + +Go to Settings and select your AI provider (Groq, OpenAI, Anthropic, Ollama, LM Studio, xAI, Custom). + +New users will use the system default AI settings by default. Users can uncheck "Use system default settings" to configure their own. ## Development @@ -96,9 +108,10 @@ docker compose build && docker compose up -d │ ├── components/ │ └── lib/ # API client, geolocation ├── www/ # Product website with docs -├── Dockerfile # App container -├── Dockerfile.docs # Website container -└── docker-compose.yml +├── Dockerfile # App container (frontend + backend + nginx) +├── Dockerfile.website # Website container with envsubst +├── docker-compose.yml +└── docker-entrypoint.d/ # Entrypoint scripts ``` ## Routes diff --git a/README.md.old b/README.md.old deleted file mode 100644 index 694d72e..0000000 --- a/README.md.old +++ /dev/null @@ -1,130 +0,0 @@ -# TotalRecall - -> Your day, analyzed. A journal that writes itself. - -AI-powered daily journal that captures life through multiple input methods and generates thoughtful, reflective journal entries. - -## Features - -- **Multiple Input Types**: Text notes, photos, voice memos, health data -- **AI Journal Generation**: OpenAI, Anthropic, Ollama, or LM Studio -- **Self-Hostable**: Run it yourself or use any hosted version -- **Same Codebase**: Single deployment works for single-user or multi-tenant - -## Quick Start - -### Docker (Recommended) - -```bash -git clone https://github.com/totalrecall/totalrecall.git -cd totalrecall - -# Create .env file -cp backend/.env.example .env -# Edit .env and set JWT_SECRET - -# Start -docker-compose up -d -``` - -Visit http://localhost:5173 - -### Manual Development - -```bash -# Backend -cd backend -bun install -bunx prisma generate -bunx prisma db push -bun run dev - -# Frontend (separate terminal) -cd frontend -npm install -npm run dev -``` - -## Configuration - -### Environment Variables - -| Variable | Default | Description | -|----------|---------|-------------| -| `DATABASE_URL` | `file:./data/totalrecall.db` | SQLite, PostgreSQL, or MySQL | -| `JWT_SECRET` | (required) | Secret for JWT signing | -| `MEDIA_DIR` | `./data/media` | Directory for uploads | -| `PORT` | `3000` | Server port | -| `CORS_ORIGIN` | `*` | Allowed origins | - -### Database Examples - -```bash -# SQLite (default) -DATABASE_URL="file:./data/totalrecall.db" - -# PostgreSQL -DATABASE_URL="postgresql://user:pass@host:5432/totalrecall" - -# MySQL -DATABASE_URL="mysql://user:pass@host:3306/totalrecall" -``` - -## AI Providers - -Configure in Settings after logging in: - -| Provider | Setup | -|----------|-------| -| **OpenAI** | API key required | -| **Anthropic** | API key required | -| **Ollama** | Local URL (default: http://localhost:11434) | -| **LM Studio** | Local URL (default: http://localhost:1234/v1) | - -## Project Structure - -``` -totalrecall/ -├── backend/ # Bun + Hono API server -│ ├── src/ -│ │ ├── routes/ # API endpoints -│ │ ├── services/ # AI providers -│ │ └── middleware/ -│ └── prisma/ # Database schema -├── frontend/ # React + Vite web app -├── android/ # Native Android app (Kotlin + Compose) -│ └── app/src/main/java/com/totalrecall/ -├── docker-compose.yml -└── PLAN.md # Full specification -``` - -## API - -All endpoints require `Authorization: Bearer {api_key}` header. - -``` -POST /api/v1/auth/register -POST /api/v1/auth/login -POST /api/v1/auth/api-key - -GET /api/v1/days -GET /api/v1/days/:date -DELETE /api/v1/days/:date - -POST /api/v1/entries -GET /api/v1/entries/:id -PUT /api/v1/entries/:id -DELETE /api/v1/entries/:id -POST /api/v1/entries/:id/photo -POST /api/v1/entries/:id/voice - -POST /api/v1/journal/generate/:date -GET /api/v1/journal/:date - -GET /api/v1/settings -PUT /api/v1/settings -``` - -## License - -MIT diff --git a/docker-compose.prod.yml.old b/docker-compose.prod.yml.old deleted file mode 100644 index 8c49d25..0000000 --- a/docker-compose.prod.yml.old +++ /dev/null @@ -1,30 +0,0 @@ -version: '3.8' - -services: - backend: - image: ghcr.io/totalrecall/totalrecall:latest - ports: - - "3000:3000" - environment: - - DATABASE_URL=file:/data/totalrecall.db - - MEDIA_DIR=/data/media - - JWT_SECRET=${JWT_SECRET} - - PORT=3000 - - CORS_ORIGIN=https://your-domain.com - volumes: - - ./data:/data - restart: unless-stopped - healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/health"] - interval: 30s - timeout: 10s - retries: 3 - - # Uncomment to use with a reverse proxy like Traefik - # frontend: - # image: ghcr.io/totalrecall/frontend:latest - # labels: - # - "traefik.enable=true" - # - "traefik.http.routers.totalrecall.rule=Host(`your-domain.com`)" - # - "traefik.http.routers.totalrecall.entrypoints=websecure" - # - "traefik.http.routers.totalrecall.tls=true" diff --git a/docker-compose.yml.old b/docker-compose.yml.old deleted file mode 100644 index 3ca6aec..0000000 --- a/docker-compose.yml.old +++ /dev/null @@ -1,24 +0,0 @@ -services: - app: - build: - context: . - dockerfile: Dockerfile - ports: - - "3000:3000" - - "5173:80" - environment: - - DATABASE_URL=file:/data/totalrecall.db - - MEDIA_DIR=/data/media - - JWT_SECRET=${JWT_SECRET:-change-me-in-production} - - PORT=3000 - - CORS_ORIGIN=${CORS_ORIGIN:-*} - volumes: - - ./data:/data - restart: unless-stopped - extra_hosts: - - "host.docker.internal:host-gateway" - healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/health"] - interval: 30s - timeout: 10s - retries: 3 diff --git a/nginx.conf.old b/nginx.conf.old deleted file mode 100644 index 13eb93c..0000000 --- a/nginx.conf.old +++ /dev/null @@ -1,21 +0,0 @@ -server { - listen 80; - root /app/public; - index index.html; - - client_body_temp_path /app/nginx_tmp/client_body; - proxy_temp_path /app/nginx_tmp/proxy; - - location / { - try_files $uri $uri/ /index.html; - } - - location /api/ { - proxy_pass http://127.0.0.1:3000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_cache_bypass $http_upgrade; - } -}