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.
|
||||
|
||||
[](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
|
||||
|
||||
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