Keep/docs/deployment-guide.md
sepehr 640fcb26f7 fix: improve note interactions and markdown LaTeX support
## Bug Fixes

### Note Card Actions
- Fix broken size change functionality (missing state declaration)
- Implement React 19 useOptimistic for instant UI feedback
- Add startTransition for non-blocking updates
- Ensure smooth animations without page refresh
- All note actions now work: pin, archive, color, size, checklist

### Markdown LaTeX Rendering
- Add remark-math and rehype-katex plugins
- Support inline equations with dollar sign syntax
- Support block equations with double dollar sign syntax
- Import KaTeX CSS for proper styling
- Equations now render correctly instead of showing raw LaTeX

## Technical Details

- Replace undefined currentNote references with optimistic state
- Add optimistic updates before server actions for instant feedback
- Use router.refresh() in transitions for smart cache invalidation
- Install remark-math, rehype-katex, and katex packages

## Testing

- Build passes successfully with no TypeScript errors
- Dev server hot-reloads changes correctly
2026-01-09 22:13:49 +01:00

1215 lines
23 KiB
Markdown

# Deployment Guide - Memento Project
## Overview
Complete deployment guide for the Memento note-taking application using Docker and Docker Compose. Covers production deployment, environment configuration, and service orchestration.
**Architecture:** Multi-container deployment with keep-notes (Next.js web app) and mcp-server (Express MCP server)
---
## Prerequisites
### Required Software
| Tool | Version | Purpose |
|------|---------|---------|
| **Docker** | 20.10+ | Container runtime |
| **Docker Compose** | 2.0+ | Multi-container orchestration |
| **Git** | Latest | Clone repository |
### Verify Installation
```bash
docker --version
docker compose version
```
---
## Quick Start (Docker Compose)
### 1. Clone Repository
```bash
git clone <repository-url>
cd Keep
```
### 2. Configure Environment
```bash
# Copy environment template
cp .env.example .env
# Edit with your configuration
nano .env
```
### 3. Start Services
```bash
# Build and start all services
docker compose up -d
# View logs
docker compose logs -f
# Check service status
docker compose ps
```
### 4. Access Application
- **Web Application:** http://localhost:3000
- **Prisma Studio:** http://localhost:5555 (when running)
### 5. Stop Services
```bash
# Stop all services
docker compose down
# Stop and remove volumes (⚠️ deletes data)
docker compose down -v
```
---
## Docker Configuration Files
### Root Directory Structure
```
Keep/
├── docker-compose.yml # Main orchestration
├── .env # Environment variables
├── keep-notes/
│ ├── Dockerfile # Web app container
│ ├── .dockerignore # Build exclusions
│ └── next.config.ts # Next.js config
└── mcp-server/
├── Dockerfile # MCP server container
└── .dockerignore # Build exclusions
```
---
## Docker Compose Configuration
### Complete docker-compose.yml
```yaml
version: '3.8'
services:
# ============================================
# keep-notes - Next.js Web Application
# ============================================
keep-notes:
build:
context: ./keep-notes
dockerfile: Dockerfile
container_name: memento-web
ports:
- "3000:3000"
environment:
- DATABASE_URL=file:/app/prisma/dev.db
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- NEXTAUTH_URL=${NEXTAUTH_URL:-http://localhost:3000}
- NODE_ENV=production
# Email Configuration (SMTP)
- SMTP_HOST=${SMTP_HOST}
- SMTP_PORT=${SMTP_PORT:-587}
- SMTP_USER=${SMTP_USER}
- SMTP_PASS=${SMTP_PASS}
- SMTP_FROM=${SMTP_FROM:-noreply@memento.app}
# AI Providers
- OPENAI_API_KEY=${OPENAI_API_KEY}
- OLLAMA_API_URL=${OLLAMA_API_URL:-http://ollama:11434}
volumes:
- db-data:/app/prisma
- uploads-data:/app/public/uploads
depends_on:
- ollama
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- memento-network
# ============================================
# mcp-server - MCP Protocol Server
# ============================================
mcp-server:
build:
context: ./mcp-server
dockerfile: Dockerfile
container_name: memento-mcp
volumes:
- db-data:/app/db
depends_on:
- keep-notes
restart: unless-stopped
networks:
- memento-network
# ============================================
# Ollama - Local LLM Provider (Optional)
# ============================================
ollama:
image: ollama/ollama:latest
container_name: memento-ollama
ports:
- "11434:11434"
volumes:
- ollama-data:/root/.ollama
restart: unless-stopped
networks:
- memento-network
# ============================================
# Prisma Studio - Database GUI (Optional)
# ============================================
prisma-studio:
build:
context: ./keep-notes
dockerfile: Dockerfile
container_name: memento-studio
command: npx prisma studio
ports:
- "5555:5555"
environment:
- DATABASE_URL=file:/app/prisma/dev.db
volumes:
- db-data:/app/prisma
depends_on:
- keep-notes
restart: unless-stopped
networks:
- memento-network
profiles:
- admin # Only start with: docker compose --profile admin up
# ============================================
# Volumes - Data Persistence
# ============================================
volumes:
db-data:
driver: local
uploads-data:
driver: local
ollama-data:
driver: local
# ============================================
# Networks - Service Communication
# ============================================
networks:
memento-network:
driver: bridge
```
---
## Dockerfile: keep-notes
### Complete Dockerfile
```dockerfile
# ============================================
# Multi-stage build for Next.js 16
# ============================================
# Stage 1: Dependencies
FROM node:20-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on package manager
COPY package*.json ./
RUN npm ci
# Stage 2: Builder
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Generate Prisma client
RUN npx prisma generate
# Build Next.js application
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
# Stage 3: Production Runner
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy necessary files
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
COPY --from=builder /app/node_modules/@prisma ./node_modules/@prisma
# Create directories with proper permissions
RUN mkdir -p /app/prisma /app/public/uploads/notes
RUN chown -R nextjs:nodejs /app
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
CMD ["node", "server.js"]
```
### Update next.config.ts for Standalone Output
```typescript
// keep-notes/next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
// ... existing config
// Enable standalone output for Docker
output: 'standalone',
// Optimize for production
reactStrictMode: true,
swcMinify: true,
// Image optimization
images: {
unoptimized: true, // Required for standalone
},
}
export default nextConfig
```
### .dockerignore for keep-notes
```
node_modules
.next
.git
.gitignore
*.md
.env*.local
.vscode
idea
.DS_Store
*.log
coverage
test-results
playwright-report
```
---
## Dockerfile: mcp-server
### Complete Dockerfile
```dockerfile
# Base image
FROM node:20-alpine
# Install dependencies
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Copy Prisma schema and client
COPY prisma ./prisma
# Create non-root user
RUN addgroup -g 1001 -S mcp && \
adduser -u 1001 -S mcp -G mcp
# Create database directory
RUN mkdir -p /app/db && \
chown -R mcp:mcp /app
USER mcp
WORKDIR /app
# Expose (not needed for stdio, but useful for SSE variant)
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD node -e "console.log('healthy')" || exit 1
# Start MCP server
CMD ["node", "index.js"]
```
### .dockerignore for mcp-server
```
node_modules
.git
.gitignore
*.md
.env
.env.*
*.log
.DS_Store
index-sse.js # Only use main index.js
README-SSE.md
N8N-CONFIG.md
```
---
## Environment Configuration
### .env.example (Root Directory)
```bash
# ============================================
# Database Configuration
# ============================================
DATABASE_URL="file:/app/prisma/dev.db"
# ============================================
# NextAuth Configuration
# ============================================
# Generate with: openssl rand -base64 32
NEXTAUTH_SECRET="your-secret-key-here-min-32-chars"
NEXTAUTH_URL="http://localhost:3000"
# ============================================
# Email Configuration (SMTP)
# ============================================
# Required for password reset and reminders
SMTP_HOST="smtp.gmail.com"
SMTP_PORT="587"
SMTP_USER="your-email@gmail.com"
SMTP_PASS="your-app-password"
SMTP_FROM="noreply@memento.app"
# ============================================
# AI Provider Configuration
# ============================================
# OpenAI (Optional - for GPT models)
OPENAI_API_KEY="sk-..."
# Ollama (Optional - for local models)
OLLAMA_API_URL="http://ollama:11434"
# ============================================
# Application Settings
# ============================================
NODE_ENV="production"
PORT="3000"
# ============================================
# Docker-Specific Settings
# ============================================
# These are usually set in docker-compose.yml
# Keep for local development reference
```
### Generate NEXTAUTH_SECRET
```bash
# Linux/Mac
openssl rand -base64 32
# Windows (PowerShell)
-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 32 | % {[char]$_})
```
---
## Production Deployment
### Option 1: Docker Compose (Recommended)
```bash
# 1. Clone repository
git clone <repository-url>
cd Keep
# 2. Configure environment
cp .env.example .env
nano .env # Edit configuration
# 3. Start services
docker compose up -d
# 4. Initialize database (first time only)
docker compose exec keep-notes npx prisma migrate deploy
# 5. Create admin user (optional)
docker compose exec keep-notes node scripts/promote-admin.js your-email@example.com
# 6. Check status
docker compose ps
docker compose logs -f keep-notes
```
### Option 2: Individual Containers
#### Build keep-notes Image
```bash
cd keep-notes
docker build -t memento-web:latest .
docker run -d \
--name memento-web \
-p 3000:3000 \
-v $(pwd)/prisma:/app/prisma \
-e DATABASE_URL=file:/app/prisma/dev.db \
-e NEXTAUTH_SECRET=your-secret \
-e NEXTAUTH_URL=http://localhost:3000 \
memento-web:latest
```
#### Build mcp-server Image
```bash
cd mcp-server
docker build -t memento-mcp:latest .
docker run -d \
--name memento-mcp \
-v /path/to/keep-notes/prisma:/app/db \
memento-mcp:latest
```
---
## Database Management in Docker
### Run Migrations
```bash
# Apply pending migrations
docker compose exec keep-notes npx prisma migrate deploy
# Create new migration
docker compose exec keep-notes npx prisma migrate dev --name my_changes
# Reset database (⚠️ deletes all data)
docker compose exec keep-notes npx prisma migrate reset
```
### Seed Database (Optional)
```bash
# Create seed file
# keep-notes/prisma/seed.ts
# Run seed
docker compose exec keep-notes npx prisma db seed
```
### Access Database Directly
```bash
# Open SQLite CLI
docker compose exec keep-notes sqlite3 /app/prisma/dev.db
# Query notes
SELECT * FROM Note LIMIT 10;
# Exit
.quit
```
### Backup Database
```bash
# Backup database
docker compose exec keep-notes \
sqlite3 /app/prisma/dev.db ".backup /app/prisma/backup.db"
# Copy backup to host
docker cp memento-web:/app/prisma/backup.db ./backup-$(date +%Y%m%d).db
```
### Restore Database
```bash
# Copy backup to container
docker cp ./backup.db memento-web:/app/prisma/restore.db
# Restore
docker compose exec keep-notes \
sqlite3 /app/prisma/dev.db ".restore /app/prisma/restore.db"
```
---
## Service Management
### View Logs
```bash
# All services
docker compose logs -f
# Specific service
docker compose logs -f keep-notes
docker compose logs -f mcp-server
# Last 100 lines
docker compose logs --tail=100 keep-notes
```
### Restart Services
```bash
# Restart all
docker compose restart
# Restart specific service
docker compose restart keep-notes
# Rebuild and restart
docker compose up -d --build
```
### Update Services
```bash
# Pull latest code
git pull
# Rebuild and restart
docker compose up -d --build
# Or force rebuild without cache
docker compose build --no-cache
docker compose up -d
```
### Scale Services
```bash
# Scale keep-notes (requires load balancer)
docker compose up -d --scale keep-notes=3
```
---
## Reverse Proxy Configuration
### Nginx Configuration
```nginx
# /etc/nginx/sites-available/memento
server {
listen 80;
server_name your-domain.com;
# Redirect to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL certificates
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
# Next.js application
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
# WebSocket support (if needed)
location /ws {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
### Traefik Configuration (Alternative)
```yaml
# docker-compose.yml addition
services:
traefik:
image: traefik:v2.10
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
keep-notes:
# ... existing config
labels:
- "traefik.enable=true"
- "traefik.http.routers.keep-notes.rule=Host(`your-domain.com`)"
- "traefik.http.routers.keep-notes.entrypoints=websecure"
- "traefik.http.services.keep-notes.loadbalancer.server.port=3000"
```
---
## SSL/TLS Setup
### Let's Encrypt with Certbot
```bash
# Install Certbot
sudo apt install certbot python3-certbot-nginx
# Get certificate
sudo certbot --nginx -d your-domain.com
# Auto-renewal (configured automatically)
sudo certbot renew --dry-run
```
### Self-Signed Certificate (Development)
```bash
# Generate self-signed certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/memento-selfsigned.key \
-out /etc/ssl/certs/memento-selfsigned.crt
```
---
## Monitoring & Logging
### Container Health
```bash
# Check health status
docker compose ps
# Inspect container
docker inspect memento-web
# Resource usage
docker stats
```
### Log Aggregation
```bash
# View logs from all services
docker compose logs > logs-$(date +%Y%m%d).txt
# Rotate logs
logrotate configure in /etc/logrotate.d/docker-compose
```
### Monitoring Tools
**Prometheus + Grafana** (Optional):
```yaml
# docker-compose.yml addition
services:
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana
ports:
- "3001:3000"
volumes:
- grafana-data:/var/lib/grafana
```
---
## Backup & Disaster Recovery
### Automated Backup Script
```bash
#!/bin/bash
# backup.sh - Daily backup script
BACKUP_DIR="/backups/memento"
DATE=$(date +%Y%m%d_%H%M%S)
# Create backup directory
mkdir -p "$BACKUP_DIR/$DATE"
# Backup database
docker compose exec keep-notes \
sqlite3 /app/prisma/dev.db ".backup /app/prisma/backup.db"
# Copy to host
docker cp memento-web:/app/prisma/backup.db \
"$BACKUP_DIR/$DATE/database.db"
# Backup uploads
docker cp memento-web:/app/public/uploads \
"$BACKUP_DIR/$DATE/"
# Compress
tar -czf "$BACKUP_DIR/memento-$DATE.tar.gz" -C "$BACKUP_DIR" $DATE
rm -rf "$BACKUP_DIR/$DATE"
# Keep last 7 days
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete
echo "Backup completed: memento-$DATE.tar.gz"
```
### Schedule with Cron
```bash
# Edit crontab
crontab -e
# Add daily backup at 2 AM
0 2 * * * /path/to/backup.sh
```
### Restore from Backup
```bash
# Extract backup
tar -xzf memento-20240109_020000.tar.gz
# Restore database
docker cp memento-20240109_020000/database.db \
memento-web:/app/prisma/restore.db
docker compose exec keep-notes \
sqlite3 /app/prisma/dev.db ".restore /app/prisma/restore.db"
# Restore uploads
docker cp memento-20240109_020000/uploads/. \
memento-web:/app/public/uploads/
# Restart services
docker compose restart
```
---
## Security Hardening
### 1. Docker Security
```yaml
# docker-compose.yml hardening
services:
keep-notes:
# ... existing config
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
```
### 2. Network Security
```yaml
# Isolate services
networks:
memento-network:
driver: bridge
internal: false # Set to true to block external access
ipam:
config:
- subnet: 172.20.0.0/16
```
### 3. Secrets Management
```bash
# Use Docker Secrets (Swarm mode)
echo "your-secret" | docker secret create nextauth_secret -
# In docker-compose.yml
services:
keep-notes:
secrets:
- nextauth_secret
environment:
NEXTAUTH_SECRET_FILE: /run/secrets/nextauth_secret
secrets:
nextauth_secret:
external: true
```
### 4. Update Base Images
```bash
# Update to latest Alpine
docker pull node:20-alpine
# Rebuild
docker compose build --no-cache
```
---
## Troubleshooting
### Container Won't Start
```bash
# Check logs
docker compose logs keep-notes
# Inspect container
docker inspect memento-web
# Check resource usage
docker stats
# Restart Docker daemon
sudo systemctl restart docker
```
### Database Connection Issues
```bash
# Verify database file exists
docker compose exec keep-notes ls -la /app/prisma/dev.db
# Check permissions
docker compose exec keep-notes ls -la /app/prisma/
# Re-run migrations
docker compose exec keep-notes npx prisma migrate deploy
```
### Port Conflicts
```bash
# Check what's using port 3000
sudo lsof -i :3000
# Change port in docker-compose.yml
ports:
- "3001:3000" # Use 3001 instead
```
### Out of Memory
```bash
# Increase Docker memory limit
# Docker Desktop -> Settings -> Resources -> Memory: 4GB+
# Or add memory limit in docker-compose.yml
services:
keep-notes:
deploy:
resources:
limits:
memory: 2G
```
### Permission Issues
```bash
# Fix file permissions
docker compose exec keep-notes chown -R nextjs:nodejs /app/prisma
docker compose exec keep-notes chmod 644 /app/prisma/dev.db
```
---
## Performance Optimization
### 1. Enable BuildKit
```bash
# Set environment variable
export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
```
### 2. Multi-Stage Build
Already implemented in Dockerfiles to reduce image size.
### 3. Layer Caching
```dockerfile
# Cache node_modules
COPY package*.json ./
RUN npm ci
COPY . .
```
### 4. Resource Limits
```yaml
# docker-compose.yml
services:
keep-notes:
deploy:
resources:
limits:
cpus: '1'
memory: 2G
reservations:
cpus: '0.5'
memory: 1G
```
### 5. Database Optimization
```bash
# Run VACUUM to optimize SQLite
docker compose exec keep-notes sqlite3 /app/prisma/dev.db "VACUUM;"
# Analyze query performance
docker compose exec keep-notes npx prisma studio
```
---
## CI/CD Integration
### GitHub Actions Example
```yaml
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
run: |
docker build -t yourusername/memento-web:latest ./keep-notes
docker push yourusername/memento-web:latest
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /app/memento
docker compose pull
docker compose up -d
```
---
## Development vs Production
### Development (Local)
```bash
# Use local Next.js dev server
npm run dev
# Hot reload enabled
# Source maps enabled
# Detailed error messages
```
### Production (Docker)
```bash
# Use optimized production build
docker compose up -d
# Minified code
# Optimized images
# Server-side rendering
# Health checks enabled
```
---
## Migration from Local to Docker
### 1. Export Existing Data
```bash
# From local development
sqlite3 keep-notes/prisma/dev.db ".dump" > backup.sql
# Or copy database file
cp keep-notes/prisma/dev.db ./dev-backup.db
```
### 2. Import to Docker
```bash
# Copy to container
docker cp ./dev-backup.db memento-web:/app/prisma/dev.db
# Verify
docker compose exec keep-notes sqlite3 /app/prisma/dev.db "SELECT COUNT(*) FROM Note;"
```
### 3. Update Environment
```bash
# Copy .env to .env.production
cp .env .env.production
# Update URLs for production
NEXTAUTH_URL="https://your-domain.com"
```
---
## Update Strategy
### Rolling Updates
```bash
# Zero-downtime deployment
docker compose up -d --no-deps --build keep-notes
# Or use multiple instances
docker compose up -d --scale keep-notes=2
```
### Rollback
```bash
# Revert to previous version
docker compose down
git checkout <previous-commit>
docker compose up -d --build
```
---
## Cost Estimation (Cloud Deployment)
### Self-Hosted Options
| Provider | Instance | Monthly Cost | Capacity |
|----------|----------|--------------|----------|
| DigitalOcean | Basic Droplet | $6-12 | 1-2 GB RAM, 1 vCPU |
| Linode | Nanode | $5 | 1 GB RAM, 1 vCPU |
| AWS EC2 | t3.micro | $8-15 | 1 GB RAM, 2 vCPU |
| Google Cloud | e2-micro | $6-12 | 1 GB RAM, 1 vCPU |
| Hetzner | CX11 | €4.20 | 4 GB RAM, 1 vCPU |
### Managed Services
| Service | Cost | Notes |
|---------|------|-------|
| Render | Free+$7/plan | Free tier available |
| Railway | $5-20/plan | Simple setup |
| Fly.io | $0-16/plan | Pay per use |
| Vercel | $0-20/plan | Next.js optimized |
---
## Summary
This deployment guide provides:
- ✅ Complete Docker setup for both services
- ✅ Docker Compose orchestration
- ✅ Production-ready configuration
- ✅ Database management in containers
- ✅ SSL/TLS setup
- ✅ Backup and restore procedures
- ✅ Security hardening
- ✅ Monitoring and troubleshooting
- ✅ CI/CD integration
**Quick Start:**
```bash
git clone <repo> && cd Keep
cp .env.example .env && nano .env
docker compose up -d
```
**Access:** http://localhost:3000
---
## Next Steps
After deployment:
1. Create admin user
2. Configure AI providers (OpenAI or Ollama)
3. Set up email for password reset
4. Configure backups
5. Enable SSL/TLS for production
6. Set up monitoring
7. Review security settings