docs: update README, clean up old files
This commit is contained in:
@@ -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"
|
|
||||||
444
PLAN.md.old
444
PLAN.md.old
@@ -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).
|
|
||||||
55
README.md
55
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.
|
Self-hosted AI-powered daily journaling application. Capture events throughout the day and let AI generate thoughtful diary pages from your entries.
|
||||||
|
|
||||||
[](https://github.com/lotherk/deardiary)
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Quick event capture with keyboard shortcut (Ctrl+J)
|
- Quick event capture with keyboard shortcut (Ctrl+J)
|
||||||
@@ -25,33 +23,47 @@ Self-hosted AI-powered daily journaling application. Capture events throughout t
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone the repository
|
# Clone the repository
|
||||||
git clone https://github.com/lotherk/deardiary.git
|
git clone git@git.kropa.tech:lotherk/deardiary.git
|
||||||
cd deardiary
|
cd deardiary
|
||||||
|
|
||||||
|
# Configure environment (optional - defaults work out of box)
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
# Start with Docker
|
# Start with Docker
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Access the app at `http://localhost:5173`
|
Access the app at `http://localhost:3000`
|
||||||
|
|
||||||
Default credentials: `admin@localhost` / `changeme123`
|
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
|
## Configuration
|
||||||
|
|
||||||
1. Go to Settings and select your AI provider (Groq, OpenAI, Anthropic, Ollama, LM Studio)
|
### Environment Variables
|
||||||
2. Enter your API key for the selected provider
|
|
||||||
3. Optionally customize the model and base URL
|
Copy `.env.example` to `.env` and configure:
|
||||||
4. Test the connection before saving
|
|
||||||
|
```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
|
## Development
|
||||||
|
|
||||||
@@ -96,9 +108,10 @@ docker compose build && docker compose up -d
|
|||||||
│ ├── components/
|
│ ├── components/
|
||||||
│ └── lib/ # API client, geolocation
|
│ └── lib/ # API client, geolocation
|
||||||
├── www/ # Product website with docs
|
├── www/ # Product website with docs
|
||||||
├── Dockerfile # App container
|
├── Dockerfile # App container (frontend + backend + nginx)
|
||||||
├── Dockerfile.docs # Website container
|
├── Dockerfile.website # Website container with envsubst
|
||||||
└── docker-compose.yml
|
├── docker-compose.yml
|
||||||
|
└── docker-entrypoint.d/ # Entrypoint scripts
|
||||||
```
|
```
|
||||||
|
|
||||||
## Routes
|
## Routes
|
||||||
|
|||||||
130
README.md.old
130
README.md.old
@@ -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
|
|
||||||
@@ -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"
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user