feat: add demo user initialization for local development
- Add hattori@hanzo.ai demo user with password demo1234 - Create seed_demo_user.js script to initialize demo account - Add demo-init service to compose.yml for automatic setup - Add compose.dev.yml for development with mounted volumes - Create init-demo-user.sh for manual demo user creation - Add Makefile.hanzo with comprehensive stack management - Include README-demo-user.md with usage instructions - Configure Hanzo Router branding in hanzo-config.yaml
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Hanzo AI Chat Stack Environment Variables
|
||||
# Copy this file to .env and update with your values
|
||||
|
||||
# ==================================
|
||||
# LLM API Keys (at least one required)
|
||||
# ==================================
|
||||
OPENAI_API_KEY=sk-...
|
||||
ANTHROPIC_API_KEY=sk-ant-...
|
||||
TOGETHER_API_KEY=...
|
||||
|
||||
# ==================================
|
||||
# Database Configuration
|
||||
# ==================================
|
||||
POSTGRES_PASSWORD=hanzo123
|
||||
MONGO_PASSWORD=hanzo123
|
||||
REDIS_PASSWORD=hanzosecret
|
||||
|
||||
# ==================================
|
||||
# Service URLs
|
||||
# ==================================
|
||||
DOMAIN_CLIENT=http://localhost:3081
|
||||
DOMAIN_SERVER=http://localhost:3081
|
||||
|
||||
# ==================================
|
||||
# Security Keys (CHANGE IN PRODUCTION!)
|
||||
# ==================================
|
||||
ROUTER_MASTER_KEY=sk-hanzo-master-key
|
||||
JWT_SECRET=hanzo-jwt-secret-change-in-production
|
||||
JWT_REFRESH_SECRET=hanzo-refresh-secret-change-in-production
|
||||
CREDS_KEY=hanzo-creds-key-change-in-production
|
||||
CREDS_IV=hanzo-creds-iv-change
|
||||
MEILI_MASTER_KEY=HanzoMeiliMasterKey
|
||||
|
||||
# ==================================
|
||||
# Feature Flags
|
||||
# ==================================
|
||||
ALLOW_REGISTRATION=true
|
||||
ALLOW_UNVERIFIED_EMAIL_LOGIN=false
|
||||
DEBUG=false
|
||||
|
||||
# ==================================
|
||||
# Performance Tuning
|
||||
# ==================================
|
||||
ROUTER_WORKERS=4
|
||||
|
||||
# ==================================
|
||||
# Optional: Additional LLM Providers
|
||||
# ==================================
|
||||
# AZURE_API_KEY=...
|
||||
# AZURE_API_BASE=https://your-resource.openai.azure.com/
|
||||
# GROQ_API_KEY=...
|
||||
# COHERE_API_KEY=...
|
||||
|
||||
# ==================================
|
||||
# Optional: Observability
|
||||
# ==================================
|
||||
# LANGFUSE_PUBLIC_KEY=...
|
||||
# LANGFUSE_SECRET_KEY=...
|
||||
# LANGFUSE_HOST=https://cloud.langfuse.com
|
||||
|
||||
# ==================================
|
||||
# Optional: Authentication Providers
|
||||
# ==================================
|
||||
# GOOGLE_CLIENT_ID=...
|
||||
# GOOGLE_CLIENT_SECRET=...
|
||||
# GITHUB_CLIENT_ID=...
|
||||
# GITHUB_CLIENT_SECRET=...
|
||||
@@ -0,0 +1,21 @@
|
||||
# Hanzo Chat with Demo User
|
||||
FROM ghcr.io/danny-avila/librechat:latest
|
||||
|
||||
# Copy demo user initialization script
|
||||
COPY scripts/seed_demo_user.js /app/scripts/
|
||||
COPY docker/entrypoint-with-demo.sh /app/
|
||||
|
||||
# Install mongosh for the initialization script
|
||||
USER root
|
||||
RUN apt-get update && apt-get install -y gnupg wget && \
|
||||
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | apt-key add - && \
|
||||
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/7.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-7.0.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y mongodb-mongosh && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN chmod +x /app/entrypoint-with-demo.sh
|
||||
|
||||
# Use our custom entrypoint
|
||||
ENTRYPOINT ["/app/entrypoint-with-demo.sh"]
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
# Hanzo AI Chat Stack Makefile
|
||||
# One-command deployment and management
|
||||
|
||||
.PHONY: help up down restart logs build push deploy clean test status backup restore
|
||||
|
||||
# Color definitions
|
||||
YELLOW := \033[1;33m
|
||||
GREEN := \033[1;32m
|
||||
RED := \033[1;31m
|
||||
BLUE := \033[1;34m
|
||||
NC := \033[0m # No Color
|
||||
|
||||
# Configuration
|
||||
DOCKER_REGISTRY ?= ghcr.io/hanzoai
|
||||
ROUTER_IMAGE := $(DOCKER_REGISTRY)/router
|
||||
CHAT_IMAGE := $(DOCKER_REGISTRY)/chat
|
||||
VERSION ?= latest
|
||||
COMPOSE_FILE := docker-compose.hanzo.yml
|
||||
|
||||
# Default target
|
||||
help:
|
||||
@echo "$(BLUE)Hanzo AI Chat Stack Management$(NC)"
|
||||
@echo ""
|
||||
@echo "$(YELLOW)Quick Start:$(NC)"
|
||||
@echo " $(GREEN)make deploy$(NC) - Build and start the entire Hanzo stack"
|
||||
@echo ""
|
||||
@echo "$(YELLOW)Development:$(NC)"
|
||||
@echo " $(GREEN)make up$(NC) - Start all services"
|
||||
@echo " $(GREEN)make down$(NC) - Stop all services"
|
||||
@echo " $(GREEN)make restart$(NC) - Restart all services"
|
||||
@echo " $(GREEN)make logs$(NC) - View logs (all services)"
|
||||
@echo " $(GREEN)make logs-chat$(NC) - View chat service logs"
|
||||
@echo " $(GREEN)make logs-router$(NC) - View Hanzo Router logs"
|
||||
@echo " $(GREEN)make status$(NC) - Check service health"
|
||||
@echo ""
|
||||
@echo "$(YELLOW)Building:$(NC)"
|
||||
@echo " $(GREEN)make build$(NC) - Build Docker images"
|
||||
@echo " $(GREEN)make push$(NC) - Push images to registry"
|
||||
@echo " $(GREEN)make clean$(NC) - Clean up volumes and images"
|
||||
@echo ""
|
||||
@echo "$(YELLOW)Testing:$(NC)"
|
||||
@echo " $(GREEN)make test$(NC) - Run all tests"
|
||||
@echo " $(GREEN)make test-api$(NC) - Test API endpoints"
|
||||
@echo ""
|
||||
@echo "$(YELLOW)Data Management:$(NC)"
|
||||
@echo " $(GREEN)make backup$(NC) - Backup all data"
|
||||
@echo " $(GREEN)make restore$(NC) - Restore from backup"
|
||||
|
||||
# Quick deploy - builds and starts everything
|
||||
deploy: check-env build
|
||||
@echo "$(BLUE)🚀 Deploying Hanzo AI Chat Stack...$(NC)"
|
||||
@docker compose -f $(COMPOSE_FILE) up -d
|
||||
@echo "$(GREEN)✅ Deployment complete!$(NC)"
|
||||
@echo ""
|
||||
@echo "$(YELLOW)Access points:$(NC)"
|
||||
@echo " Chat UI: http://localhost:3081"
|
||||
@echo " Hanzo Router: http://localhost:4000"
|
||||
@echo " Router Admin: http://localhost:4000/ui"
|
||||
@echo ""
|
||||
@echo "$(YELLOW)Default credentials:$(NC)"
|
||||
@echo " Master Key: sk-hanzo-master-key"
|
||||
@echo ""
|
||||
@$(MAKE) wait-healthy
|
||||
|
||||
# Check required environment variables
|
||||
check-env:
|
||||
@echo "$(BLUE)🔍 Checking environment...$(NC)"
|
||||
@if [ -z "$$OPENAI_API_KEY" ] && [ -z "$$ANTHROPIC_API_KEY" ] && [ -z "$$TOGETHER_API_KEY" ]; then \
|
||||
echo "$(RED)❌ Error: At least one LLM API key must be set$(NC)"; \
|
||||
echo "$(YELLOW)Please set one of: OPENAI_API_KEY, ANTHROPIC_API_KEY, or TOGETHER_API_KEY$(NC)"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@if [ ! -f .env ]; then \
|
||||
echo "$(YELLOW)📝 Creating .env file from template...$(NC)"; \
|
||||
cp .env.example .env; \
|
||||
fi
|
||||
@echo "$(GREEN)✅ Environment check passed$(NC)"
|
||||
|
||||
# Build Docker images
|
||||
build:
|
||||
@echo "$(BLUE)🔨 Building Docker images...$(NC)"
|
||||
@docker compose -f $(COMPOSE_FILE) build
|
||||
@echo "$(GREEN)✅ Build complete$(NC)"
|
||||
|
||||
# Push images to registry
|
||||
push:
|
||||
@echo "$(BLUE)📤 Pushing images to registry...$(NC)"
|
||||
@docker tag hanzo/router:latest $(ROUTER_IMAGE):$(VERSION)
|
||||
@docker tag hanzo/chat:latest $(CHAT_IMAGE):$(VERSION)
|
||||
@docker push $(ROUTER_IMAGE):$(VERSION)
|
||||
@docker push $(CHAT_IMAGE):$(VERSION)
|
||||
@echo "$(GREEN)✅ Images pushed successfully$(NC)"
|
||||
|
||||
# Start services
|
||||
up:
|
||||
@echo "$(BLUE)▶️ Starting services...$(NC)"
|
||||
@docker compose -f $(COMPOSE_FILE) up -d
|
||||
@$(MAKE) wait-healthy
|
||||
|
||||
# Stop services
|
||||
down:
|
||||
@echo "$(BLUE)⏹️ Stopping services...$(NC)"
|
||||
@docker compose -f $(COMPOSE_FILE) down
|
||||
@echo "$(GREEN)✅ Services stopped$(NC)"
|
||||
|
||||
# Restart services
|
||||
restart:
|
||||
@echo "$(BLUE)🔄 Restarting services...$(NC)"
|
||||
@docker compose -f $(COMPOSE_FILE) restart
|
||||
@$(MAKE) wait-healthy
|
||||
|
||||
# View logs
|
||||
logs:
|
||||
@docker compose -f $(COMPOSE_FILE) logs -f
|
||||
|
||||
logs-chat:
|
||||
@docker compose -f $(COMPOSE_FILE) logs -f chat
|
||||
|
||||
logs-router:
|
||||
@docker compose -f $(COMPOSE_FILE) logs -f router
|
||||
|
||||
# Check service health
|
||||
status:
|
||||
@echo "$(BLUE)📊 Service Status:$(NC)"
|
||||
@echo ""
|
||||
@docker compose -f $(COMPOSE_FILE) ps
|
||||
@echo ""
|
||||
@echo "$(BLUE)🏥 Health Checks:$(NC)"
|
||||
@for service in postgres redis mongodb meilisearch router chat nginx; do \
|
||||
if docker compose -f $(COMPOSE_FILE) exec -T $$service echo "OK" >/dev/null 2>&1; then \
|
||||
echo " $$service: $(GREEN)✅ Healthy$(NC)"; \
|
||||
else \
|
||||
echo " $$service: $(RED)❌ Unhealthy$(NC)"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
# Wait for services to be healthy
|
||||
wait-healthy:
|
||||
@echo "$(BLUE)⏳ Waiting for services to be healthy...$(NC)"
|
||||
@for i in 1 2 3 4 5 6 7 8 9 10; do \
|
||||
if docker compose -f $(COMPOSE_FILE) exec -T router curl -f http://localhost:4000/health >/dev/null 2>&1 && \
|
||||
docker compose -f $(COMPOSE_FILE) exec -T chat curl -f http://localhost:3080/health >/dev/null 2>&1; then \
|
||||
echo "$(GREEN)✅ All services are healthy!$(NC)"; \
|
||||
break; \
|
||||
fi; \
|
||||
echo " Waiting... ($$i/10)"; \
|
||||
sleep 5; \
|
||||
done
|
||||
|
||||
# Run tests
|
||||
test: test-api test-chat
|
||||
|
||||
test-api:
|
||||
@echo "$(BLUE)🧪 Testing API endpoints...$(NC)"
|
||||
@curl -s -X GET http://localhost:4000/health | grep -q "healthy" && \
|
||||
echo "$(GREEN)✅ Hanzo Router: OK$(NC)" || \
|
||||
echo "$(RED)❌ Hanzo Router: Failed$(NC)"
|
||||
@curl -s -X GET http://localhost:3081/health | grep -q "OK" && \
|
||||
echo "$(GREEN)✅ Chat UI: OK$(NC)" || \
|
||||
echo "$(RED)❌ Chat UI: Failed$(NC)"
|
||||
|
||||
test-chat:
|
||||
@echo "$(BLUE)🧪 Testing chat functionality...$(NC)"
|
||||
@curl -s -X POST http://localhost:4000/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer sk-hanzo-master-key" \
|
||||
-d '{"model": "hanzo-zen-1", "messages": [{"role": "user", "content": "Hello"}]}' | \
|
||||
grep -q "content" && \
|
||||
echo "$(GREEN)✅ Chat completion: OK$(NC)" || \
|
||||
echo "$(RED)❌ Chat completion: Failed$(NC)"
|
||||
|
||||
# Clean up
|
||||
clean:
|
||||
@echo "$(BLUE)🧹 Cleaning up...$(NC)"
|
||||
@docker compose -f $(COMPOSE_FILE) down -v
|
||||
@docker rmi hanzo/router:latest hanzo/chat:latest || true
|
||||
@echo "$(GREEN)✅ Cleanup complete$(NC)"
|
||||
|
||||
# Backup data
|
||||
backup:
|
||||
@echo "$(BLUE)💾 Backing up data...$(NC)"
|
||||
@mkdir -p backups
|
||||
@BACKUP_NAME="hanzo-backup-$$(date +%Y%m%d-%H%M%S)"; \
|
||||
docker compose -f $(COMPOSE_FILE) exec -T postgres pg_dump -U hanzo hanzo_chat > backups/$$BACKUP_NAME-postgres.sql; \
|
||||
docker compose -f $(COMPOSE_FILE) exec -T mongodb mongodump --archive > backups/$$BACKUP_NAME-mongodb.archive; \
|
||||
echo "$(GREEN)✅ Backup saved to backups/$$BACKUP_NAME-*$(NC)"
|
||||
|
||||
# Restore from backup
|
||||
restore:
|
||||
@if [ -z "$(BACKUP)" ]; then \
|
||||
echo "$(RED)❌ Please specify BACKUP=<backup-name>$(NC)"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "$(BLUE)📥 Restoring from backup...$(NC)"
|
||||
@docker compose -f $(COMPOSE_FILE) exec -T postgres psql -U hanzo hanzo_chat < backups/$(BACKUP)-postgres.sql
|
||||
@docker compose -f $(COMPOSE_FILE) exec -T mongodb mongorestore --archive < backups/$(BACKUP)-mongodb.archive
|
||||
@echo "$(GREEN)✅ Restore complete$(NC)"
|
||||
|
||||
# Initialize demo user
|
||||
init-demo:
|
||||
@echo "$(BLUE)👤 Initializing demo user...$(NC)"
|
||||
@./init-demo-user.sh
|
||||
|
||||
# Development helpers
|
||||
dev-setup:
|
||||
@echo "$(BLUE)🛠️ Setting up development environment...$(NC)"
|
||||
@poetry install --with dev,proxy-dev --extras proxy
|
||||
@cd client && npm install
|
||||
@echo "$(GREEN)✅ Development setup complete$(NC)"
|
||||
|
||||
dev-frontend:
|
||||
@echo "$(BLUE)🎨 Starting frontend development server...$(NC)"
|
||||
@cd client && npm run dev
|
||||
|
||||
dev-backend:
|
||||
@echo "$(BLUE)⚙️ Starting Hanzo Router development server...$(NC)"
|
||||
@poetry run litellm --config hanzo-config.yaml --port 4000
|
||||
|
||||
# Production deployment
|
||||
prod-deploy:
|
||||
@echo "$(BLUE)🚀 Deploying to production...$(NC)"
|
||||
@$(MAKE) build VERSION=$(shell git rev-parse --short HEAD)
|
||||
@$(MAKE) push VERSION=$(shell git rev-parse --short HEAD)
|
||||
@echo "$(GREEN)✅ Production deployment complete$(NC)"
|
||||
@echo "$(YELLOW)Images tagged with version: $(shell git rev-parse --short HEAD)$(NC)"
|
||||
@@ -0,0 +1,54 @@
|
||||
# Hanzo Chat Demo User
|
||||
|
||||
When running Hanzo Chat locally, a demo user is automatically created for quick access.
|
||||
|
||||
## Demo User Credentials
|
||||
|
||||
- **Email**: `hattori@hanzo.ai`
|
||||
- **Password**: `demo1234`
|
||||
- **Role**: Admin
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Start the Hanzo stack:
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
2. Access Hanzo Chat:
|
||||
- Open your browser to http://localhost:3081
|
||||
- Log in with the demo credentials above
|
||||
|
||||
## Manual Demo User Creation
|
||||
|
||||
If you need to manually create the demo user (e.g., after resetting the database):
|
||||
|
||||
```bash
|
||||
./init-demo-user.sh
|
||||
```
|
||||
|
||||
Or using the Makefile:
|
||||
|
||||
```bash
|
||||
make -f Makefile.hanzo init-demo
|
||||
```
|
||||
|
||||
## Security Note
|
||||
|
||||
⚠️ **This demo user is for local development only!**
|
||||
|
||||
Never use these credentials in production. Always:
|
||||
- Change default passwords
|
||||
- Use proper authentication methods
|
||||
- Disable demo users in production environments
|
||||
|
||||
## Customizing the Demo User
|
||||
|
||||
To modify the demo user details, edit `scripts/seed_demo_user.js` and change:
|
||||
- Name
|
||||
- Email
|
||||
- Password
|
||||
- Role (USER or ADMIN)
|
||||
- Avatar URL
|
||||
|
||||
After making changes, restart the stack or run the initialization script again.
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
# Hanzo AI Chat Stack - Development Environment
|
||||
# This mounts source code for live editing
|
||||
# Use with: docker compose -f compose.dev.yml up
|
||||
|
||||
services:
|
||||
# PostgreSQL Database
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: hanzo-postgres-dev
|
||||
environment:
|
||||
POSTGRES_USER: hanzo
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-hanzo123}
|
||||
POSTGRES_DB: hanzo_chat
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data_dev:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U hanzo"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network-dev
|
||||
|
||||
# Redis Cache
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: hanzo-redis-dev
|
||||
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-hanzosecret}
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data_dev:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-hanzosecret}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network-dev
|
||||
|
||||
# MongoDB for Chat History
|
||||
mongodb:
|
||||
image: mongo:7-jammy
|
||||
container_name: hanzo-mongodb-dev
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: hanzo
|
||||
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD:-hanzo123}
|
||||
MONGO_INITDB_DATABASE: HanzoChat
|
||||
ports:
|
||||
- "27017:27017"
|
||||
volumes:
|
||||
- mongodb_data_dev:/data/db
|
||||
healthcheck:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network-dev
|
||||
|
||||
# Meilisearch for Full-Text Search
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:v1.9
|
||||
container_name: hanzo-meilisearch-dev
|
||||
environment:
|
||||
MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:-HanzoMeiliMasterKey}
|
||||
MEILI_ENV: development
|
||||
ports:
|
||||
- "7700:7700"
|
||||
volumes:
|
||||
- meilisearch_data_dev:/meili_data
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:7700/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network-dev
|
||||
|
||||
# Hanzo Router (Development Mode with Hot Reload)
|
||||
router:
|
||||
build:
|
||||
context: ../router
|
||||
dockerfile: Dockerfile.dev
|
||||
target: development
|
||||
container_name: hanzo-router-dev
|
||||
ports:
|
||||
- "4000:4000"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
# Database
|
||||
DATABASE_URL: postgresql://hanzo:${POSTGRES_PASSWORD:-hanzo123}@postgres:5432/hanzo_chat
|
||||
REDIS_URL: redis://:${REDIS_PASSWORD:-hanzosecret}@redis:6379
|
||||
|
||||
# Router Configuration
|
||||
ROUTER_MASTER_KEY: ${ROUTER_MASTER_KEY:-sk-hanzo-master-key}
|
||||
LITELLM_MASTER_KEY: ${ROUTER_MASTER_KEY:-sk-hanzo-master-key}
|
||||
|
||||
# LLM API Keys
|
||||
OPENAI_API_KEY: ${OPENAI_API_KEY}
|
||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
||||
TOGETHER_API_KEY: ${TOGETHER_API_KEY}
|
||||
|
||||
# Development
|
||||
LITELLM_LOG: DEBUG
|
||||
DEBUG: true
|
||||
PYTHONUNBUFFERED: 1
|
||||
volumes:
|
||||
# Mount source code for development
|
||||
- ../router/litellm:/app/litellm:ro
|
||||
- ../router/pyproject.toml:/app/pyproject.toml:ro
|
||||
- ./hanzo-config.yaml:/app/config.yaml:ro
|
||||
command: ["--config", "/app/config.yaml", "--port", "4000", "--num_workers", "1", "--detailed_debug"]
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:4000/health/readiness"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- hanzo-network-dev
|
||||
|
||||
# Hanzo Chat Frontend (Development Mode)
|
||||
chat:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.dev
|
||||
target: development
|
||||
container_name: hanzo-chat-dev
|
||||
ports:
|
||||
- "3081:3080"
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
meilisearch:
|
||||
condition: service_healthy
|
||||
router:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
# Server Configuration
|
||||
HOST: 0.0.0.0
|
||||
PORT: 3080
|
||||
NODE_ENV: development
|
||||
|
||||
# Database
|
||||
MONGO_URI: mongodb://hanzo:${MONGO_PASSWORD:-hanzo123}@mongodb:27017/HanzoChat?authSource=admin
|
||||
|
||||
# Domain
|
||||
DOMAIN_CLIENT: ${DOMAIN_CLIENT:-http://localhost:3081}
|
||||
DOMAIN_SERVER: ${DOMAIN_SERVER:-http://localhost:3081}
|
||||
|
||||
# Branding
|
||||
APP_TITLE: "Hanzo AI Chat (Dev)"
|
||||
CUSTOM_FOOTER: "Development Environment"
|
||||
|
||||
# Router Gateway
|
||||
OPENAI_API_KEY: proxy
|
||||
OPENAI_BASE_URL: http://router:4000/v1
|
||||
|
||||
# Auth & Security
|
||||
JWT_SECRET: ${JWT_SECRET:-dev-jwt-secret}
|
||||
JWT_REFRESH_SECRET: ${JWT_REFRESH_SECRET:-dev-refresh-secret}
|
||||
CREDS_KEY: ${CREDS_KEY:-dev-creds-key}
|
||||
CREDS_IV: ${CREDS_IV:-dev-creds-iv}
|
||||
|
||||
# Features
|
||||
ALLOW_REGISTRATION: true
|
||||
ALLOW_UNVERIFIED_EMAIL_LOGIN: true
|
||||
|
||||
# Search
|
||||
MEILI_HOST: http://meilisearch:7700
|
||||
MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:-HanzoMeiliMasterKey}
|
||||
|
||||
# MCP Integration
|
||||
MCP_ENABLED: true
|
||||
|
||||
# Logging
|
||||
DEBUG_LOGGING: true
|
||||
volumes:
|
||||
# Mount source for development
|
||||
- ./api:/app/api:ro
|
||||
- ./client:/app/client:ro
|
||||
- ./packages:/app/packages:ro
|
||||
- ./package.json:/app/package.json:ro
|
||||
- ./client/dist/assets:/app/client/dist/assets:ro
|
||||
- chat_uploads_dev:/app/uploads
|
||||
- chat_logs_dev:/app/logs
|
||||
# Node modules volume for faster rebuilds
|
||||
- node_modules:/app/node_modules
|
||||
command: ["npm", "run", "dev"]
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3080/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
networks:
|
||||
- hanzo-network-dev
|
||||
|
||||
volumes:
|
||||
postgres_data_dev:
|
||||
redis_data_dev:
|
||||
mongodb_data_dev:
|
||||
meilisearch_data_dev:
|
||||
chat_uploads_dev:
|
||||
chat_logs_dev:
|
||||
node_modules:
|
||||
|
||||
networks:
|
||||
hanzo-network-dev:
|
||||
driver: bridge
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
# Hanzo AI Chat Stack - Local Production Environment
|
||||
# This runs pre-built images suitable for local testing
|
||||
# For development with mounted volumes, use compose.dev.yml
|
||||
|
||||
services:
|
||||
# PostgreSQL Database
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: hanzo-postgres
|
||||
environment:
|
||||
POSTGRES_USER: hanzo
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-hanzo123}
|
||||
POSTGRES_DB: hanzo_chat
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U hanzo"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network
|
||||
|
||||
# Redis Cache
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: hanzo-redis
|
||||
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-hanzosecret}
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-hanzosecret}", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network
|
||||
|
||||
# MongoDB for Chat History
|
||||
mongodb:
|
||||
image: mongo:7-jammy
|
||||
container_name: hanzo-mongodb
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: hanzo
|
||||
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD:-hanzo123}
|
||||
MONGO_INITDB_DATABASE: HanzoChat
|
||||
ports:
|
||||
- "27017:27017"
|
||||
volumes:
|
||||
- mongodb_data:/data/db
|
||||
healthcheck:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network
|
||||
|
||||
# Meilisearch for Full-Text Search
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:v1.9
|
||||
container_name: hanzo-meilisearch
|
||||
environment:
|
||||
MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:-HanzoMeiliMasterKey}
|
||||
MEILI_ENV: production
|
||||
ports:
|
||||
- "7700:7700"
|
||||
volumes:
|
||||
- meilisearch_data:/meili_data
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:7700/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network
|
||||
|
||||
# Hanzo Router (LiteLLM Gateway)
|
||||
router:
|
||||
image: hanzo/router:latest
|
||||
container_name: hanzo-router
|
||||
ports:
|
||||
- "4000:4000"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
# Database
|
||||
DATABASE_URL: postgresql://hanzo:${POSTGRES_PASSWORD:-hanzo123}@postgres:5432/hanzo_chat
|
||||
REDIS_URL: redis://:${REDIS_PASSWORD:-hanzosecret}@redis:6379
|
||||
|
||||
# Router Configuration
|
||||
ROUTER_MASTER_KEY: ${ROUTER_MASTER_KEY:-sk-hanzo-master-key}
|
||||
LITELLM_MASTER_KEY: ${ROUTER_MASTER_KEY:-sk-hanzo-master-key} # For compatibility
|
||||
|
||||
# LLM API Keys
|
||||
OPENAI_API_KEY: ${OPENAI_API_KEY}
|
||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
||||
TOGETHER_API_KEY: ${TOGETHER_API_KEY}
|
||||
|
||||
# Logging
|
||||
ROUTER_LOG_LEVEL: INFO
|
||||
DEBUG: ${DEBUG:-false}
|
||||
volumes:
|
||||
- ./hanzo-config.yaml:/app/config.yaml:ro
|
||||
command: ["--config", "/app/config.yaml", "--port", "4000", "--num_workers", "${ROUTER_WORKERS:-4}"]
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:4000/health/readiness"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network
|
||||
|
||||
# Hanzo Chat Frontend
|
||||
chat:
|
||||
image: ghcr.io/hanzoai/chat:latest
|
||||
container_name: hanzo-chat
|
||||
ports:
|
||||
- "3081:3080"
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
meilisearch:
|
||||
condition: service_healthy
|
||||
router:
|
||||
condition: service_healthy
|
||||
demo-init:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
# Server Configuration
|
||||
HOST: 0.0.0.0
|
||||
PORT: 3080
|
||||
|
||||
# Database
|
||||
MONGO_URI: mongodb://hanzo:${MONGO_PASSWORD:-hanzo123}@mongodb:27017/HanzoChat?authSource=admin
|
||||
|
||||
# Domain
|
||||
DOMAIN_CLIENT: ${DOMAIN_CLIENT:-http://localhost:3081}
|
||||
DOMAIN_SERVER: ${DOMAIN_SERVER:-http://localhost:3081}
|
||||
|
||||
# Branding
|
||||
APP_TITLE: "Hanzo AI Chat"
|
||||
CUSTOM_FOOTER: "Powered by Hanzo AI"
|
||||
|
||||
# Router Gateway
|
||||
OPENAI_API_KEY: proxy
|
||||
OPENAI_BASE_URL: http://router:4000/v1
|
||||
|
||||
# Auth & Security
|
||||
JWT_SECRET: ${JWT_SECRET:-hanzo-jwt-secret-change-in-production}
|
||||
JWT_REFRESH_SECRET: ${JWT_REFRESH_SECRET:-hanzo-refresh-secret-change-in-production}
|
||||
CREDS_KEY: ${CREDS_KEY:-hanzo-creds-key-change-in-production}
|
||||
CREDS_IV: ${CREDS_IV:-hanzo-creds-iv-change}
|
||||
|
||||
# Features
|
||||
ALLOW_REGISTRATION: ${ALLOW_REGISTRATION:-true}
|
||||
ALLOW_UNVERIFIED_EMAIL_LOGIN: ${ALLOW_UNVERIFIED_EMAIL_LOGIN:-false}
|
||||
|
||||
# Search
|
||||
MEILI_HOST: http://meilisearch:7700
|
||||
MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:-HanzoMeiliMasterKey}
|
||||
|
||||
# MCP Integration
|
||||
MCP_ENABLED: true
|
||||
|
||||
# Logging
|
||||
DEBUG_LOGGING: ${DEBUG:-false}
|
||||
volumes:
|
||||
- ./scripts:/app/scripts:ro
|
||||
- ./client/dist/assets:/app/client/dist/assets:ro
|
||||
- chat_uploads:/app/uploads
|
||||
- chat_logs:/app/logs
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3080/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- hanzo-network
|
||||
|
||||
# Demo User Initialization Service
|
||||
demo-init:
|
||||
image: node:18-alpine
|
||||
container_name: hanzo-demo-init
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
MONGO_URI: mongodb://hanzo:${MONGO_PASSWORD:-hanzo123}@mongodb:27017/HanzoChat?authSource=admin
|
||||
volumes:
|
||||
- ./scripts/seed_demo_user.js:/app/seed_demo_user.js:ro
|
||||
working_dir: /app
|
||||
command: |
|
||||
sh -c "
|
||||
npm install mongoose bcryptjs
|
||||
node seed_demo_user.js
|
||||
"
|
||||
networks:
|
||||
- hanzo-network
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
mongodb_data:
|
||||
meilisearch_data:
|
||||
chat_uploads:
|
||||
chat_logs:
|
||||
|
||||
networks:
|
||||
hanzo-network:
|
||||
driver: bridge
|
||||
Executable
+89
@@ -0,0 +1,89 @@
|
||||
#!/bin/bash
|
||||
# Hanzo Chat entrypoint with demo user initialization
|
||||
|
||||
echo "🚀 Starting Hanzo Chat with demo user initialization..."
|
||||
|
||||
# Function to wait for MongoDB
|
||||
wait_for_mongodb() {
|
||||
echo "⏳ Waiting for MongoDB to be ready..."
|
||||
until mongosh "$MONGO_URI" --eval "db.adminCommand('ping')" > /dev/null 2>&1; do
|
||||
sleep 2
|
||||
done
|
||||
echo "✅ MongoDB is ready"
|
||||
}
|
||||
|
||||
# Function to create demo user
|
||||
create_demo_user() {
|
||||
echo "👤 Creating demo user..."
|
||||
|
||||
# Create a temporary Node.js script to add the user
|
||||
cat > /tmp/create_demo_user.js << 'EOF'
|
||||
const mongoose = require('mongoose');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
// Connect to MongoDB
|
||||
mongoose.connect(process.env.MONGO_URI)
|
||||
.then(async () => {
|
||||
console.log('Connected to MongoDB');
|
||||
|
||||
// Define User schema
|
||||
const userSchema = new mongoose.Schema({
|
||||
name: String,
|
||||
username: { type: String, lowercase: true, required: true },
|
||||
email: { type: String, lowercase: true, unique: true, required: true },
|
||||
emailVerified: { type: Boolean, default: false },
|
||||
password: String,
|
||||
role: { type: String, default: 'USER', enum: ['USER', 'ADMIN'] },
|
||||
providers: Array,
|
||||
avatar: String,
|
||||
created: { type: Date, default: Date.now },
|
||||
lastLogin: { type: Date, default: Date.now }
|
||||
}, { timestamps: true });
|
||||
|
||||
const User = mongoose.models.User || mongoose.model('User', userSchema);
|
||||
|
||||
// Check if demo user exists
|
||||
const existingUser = await User.findOne({ email: 'hattori@hanzo.ai' });
|
||||
|
||||
if (!existingUser) {
|
||||
const hashedPassword = await bcrypt.hash('demo1234', 10);
|
||||
|
||||
const demoUser = new User({
|
||||
name: 'Hattori Hanzo',
|
||||
username: 'hattori',
|
||||
email: 'hattori@hanzo.ai',
|
||||
emailVerified: true,
|
||||
password: hashedPassword,
|
||||
role: 'ADMIN',
|
||||
providers: ['local'],
|
||||
avatar: 'https://hanzo.ai/avatar/hattori.png'
|
||||
});
|
||||
|
||||
await demoUser.save();
|
||||
console.log('✅ Demo user created: hattori@hanzo.ai / demo1234');
|
||||
} else {
|
||||
console.log('ℹ️ Demo user already exists');
|
||||
}
|
||||
|
||||
mongoose.disconnect();
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
EOF
|
||||
|
||||
# Run the script
|
||||
node /tmp/create_demo_user.js || true
|
||||
rm -f /tmp/create_demo_user.js
|
||||
}
|
||||
|
||||
# Start the initialization in background
|
||||
(
|
||||
wait_for_mongodb
|
||||
create_demo_user
|
||||
) &
|
||||
|
||||
# Start the main application
|
||||
echo "🚀 Starting Hanzo Chat application..."
|
||||
exec npm run backend
|
||||
@@ -0,0 +1,88 @@
|
||||
# Hanzo Router Configuration
|
||||
# Unified LLM gateway for all AI providers in the Hanzo ecosystem
|
||||
|
||||
model_list:
|
||||
# Primary Hanzo AI models (via Anthropic)
|
||||
- model_name: hanzo-zen-1
|
||||
litellm_params:
|
||||
model: anthropic/claude-3-5-sonnet-20241022
|
||||
api_key: os.environ/ANTHROPIC_API_KEY
|
||||
model_info:
|
||||
description: "Hanzo Zen-1: Fast, efficient AI for most tasks"
|
||||
|
||||
- model_name: hanzo-zen-1-pro
|
||||
litellm_params:
|
||||
model: anthropic/claude-3-opus-20240229
|
||||
api_key: os.environ/ANTHROPIC_API_KEY
|
||||
model_info:
|
||||
description: "Hanzo Zen-1 Pro: Advanced reasoning for complex tasks"
|
||||
|
||||
# Additional models via different providers
|
||||
- model_name: gpt-4
|
||||
litellm_params:
|
||||
model: openai/gpt-4
|
||||
api_key: os.environ/OPENAI_API_KEY
|
||||
|
||||
- model_name: gpt-3.5-turbo
|
||||
litellm_params:
|
||||
model: openai/gpt-3.5-turbo
|
||||
api_key: os.environ/OPENAI_API_KEY
|
||||
|
||||
# Together AI models
|
||||
- model_name: mixtral-8x7b
|
||||
litellm_params:
|
||||
model: together_ai/mixtral-8x7b-32768
|
||||
api_key: os.environ/TOGETHER_API_KEY
|
||||
|
||||
# Wildcard routing for flexibility
|
||||
- model_name: "openai/*"
|
||||
litellm_params:
|
||||
model: "openai/*"
|
||||
api_key: os.environ/OPENAI_API_KEY
|
||||
|
||||
- model_name: "anthropic/*"
|
||||
litellm_params:
|
||||
model: "anthropic/*"
|
||||
api_key: os.environ/ANTHROPIC_API_KEY
|
||||
|
||||
- model_name: "together_ai/*"
|
||||
litellm_params:
|
||||
model: "together_ai/*"
|
||||
api_key: os.environ/TOGETHER_API_KEY
|
||||
|
||||
litellm_settings:
|
||||
drop_params: true
|
||||
num_retries: 3
|
||||
request_timeout: 300
|
||||
telemetry: false
|
||||
|
||||
router_settings:
|
||||
routing_strategy: simple-shuffle
|
||||
enable_pre_call_checks: true
|
||||
redis_host: os.environ/REDIS_HOST
|
||||
redis_password: os.environ/REDIS_PASSWORD
|
||||
redis_port: os.environ/REDIS_PORT
|
||||
|
||||
general_settings:
|
||||
master_key: os.environ/LITELLM_MASTER_KEY
|
||||
store_model_in_db: true
|
||||
database_url: os.environ/DATABASE_URL
|
||||
database_connection_pool_limit: 10
|
||||
|
||||
# UI Configuration
|
||||
ui_access_mode: "admin"
|
||||
|
||||
# Branding
|
||||
custom_branding:
|
||||
app_name: "Hanzo AI Chat"
|
||||
logo_url: "/assets/hanzo-logo.svg"
|
||||
primary_color: "#000000"
|
||||
|
||||
# MCP Integration
|
||||
mcp_enabled: true
|
||||
mcp_servers:
|
||||
- name: "hanzo-mcp"
|
||||
command: ["python", "-m", "hanzo_mcp_server"]
|
||||
|
||||
# Enable health checks
|
||||
health_check_interval: 30
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
# Initialize demo user for Hanzo Chat
|
||||
# Run this after docker compose up
|
||||
|
||||
echo "🚀 Initializing Hanzo Chat demo user..."
|
||||
echo "📧 Email: hattori@hanzo.ai"
|
||||
echo "🔑 Password: demo1234"
|
||||
echo ""
|
||||
|
||||
# Wait for services to be ready
|
||||
echo "⏳ Waiting for services to be ready..."
|
||||
sleep 5
|
||||
|
||||
# Run the seed script inside a temporary container
|
||||
docker run --rm \
|
||||
--network chat_hanzo-network \
|
||||
-e MONGO_URI="mongodb://hanzo:hanzo123@hanzo-mongodb:27017/HanzoChat?authSource=admin" \
|
||||
-v "$PWD/scripts:/scripts" \
|
||||
-w /scripts \
|
||||
node:18-alpine sh -c "
|
||||
npm install mongoose bcryptjs
|
||||
node seed_demo_user.js
|
||||
"
|
||||
|
||||
echo ""
|
||||
echo "✅ Demo user initialization complete!"
|
||||
echo "🌐 Access Hanzo Chat at: http://localhost:3081"
|
||||
echo "📧 Login with: hattori@hanzo.ai / demo1234"
|
||||
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Seed script to create demo user for Hanzo Chat
|
||||
* Email: hattori@hanzo.ai
|
||||
* Password: demo1234
|
||||
*/
|
||||
|
||||
const mongoose = require('mongoose');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
// MongoDB connection URL from environment or default
|
||||
const MONGO_URI = process.env.MONGO_URI || 'mongodb://hanzo:hanzo123@localhost:27017/HanzoChat?authSource=admin';
|
||||
|
||||
// User schema (matching LibreChat's schema)
|
||||
const userSchema = new mongoose.Schema({
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
username: {
|
||||
type: String,
|
||||
lowercase: true,
|
||||
required: [true, "can't be blank"],
|
||||
match: [/^[a-zA-Z0-9_]+$/, 'is invalid'],
|
||||
index: true,
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
lowercase: true,
|
||||
unique: true,
|
||||
required: [true, "can't be blank"],
|
||||
match: [/\S+@\S+\.\S+/, 'is invalid'],
|
||||
index: true,
|
||||
},
|
||||
emailVerified: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
password: {
|
||||
type: String,
|
||||
trim: true,
|
||||
minlength: 8,
|
||||
maxlength: 128,
|
||||
},
|
||||
avatar: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
role: {
|
||||
type: String,
|
||||
default: 'USER',
|
||||
enum: ['USER', 'ADMIN'],
|
||||
},
|
||||
provider: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
providers: {
|
||||
type: Array,
|
||||
required: false,
|
||||
},
|
||||
refreshToken: {
|
||||
type: [String],
|
||||
default: [],
|
||||
},
|
||||
created: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
lastLogin: {
|
||||
type: Date,
|
||||
default: Date.now,
|
||||
},
|
||||
plugins: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
}, { timestamps: true });
|
||||
|
||||
const User = mongoose.model('User', userSchema);
|
||||
|
||||
async function seedDemoUser() {
|
||||
try {
|
||||
console.log('🔌 Connecting to MongoDB...');
|
||||
await mongoose.connect(MONGO_URI);
|
||||
console.log('✅ Connected to MongoDB');
|
||||
|
||||
// Check if demo user already exists
|
||||
const existingUser = await User.findOne({ email: 'hattori@hanzo.ai' });
|
||||
|
||||
if (existingUser) {
|
||||
console.log('⚠️ Demo user already exists');
|
||||
return;
|
||||
}
|
||||
|
||||
// Hash the password
|
||||
const hashedPassword = await bcrypt.hash('demo1234', 10);
|
||||
|
||||
// Create demo user
|
||||
const demoUser = new User({
|
||||
name: 'Hattori Hanzo',
|
||||
username: 'hattori',
|
||||
email: 'hattori@hanzo.ai',
|
||||
emailVerified: true,
|
||||
password: hashedPassword,
|
||||
role: 'ADMIN', // First user gets admin role
|
||||
avatar: 'https://hanzo.ai/avatar/hattori.png',
|
||||
providers: ['local'],
|
||||
});
|
||||
|
||||
await demoUser.save();
|
||||
console.log('✅ Demo user created successfully!');
|
||||
console.log('📧 Email: hattori@hanzo.ai');
|
||||
console.log('🔑 Password: demo1234');
|
||||
console.log('👤 Role: ADMIN');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error seeding demo user:', error);
|
||||
} finally {
|
||||
await mongoose.disconnect();
|
||||
console.log('🔌 Disconnected from MongoDB');
|
||||
}
|
||||
}
|
||||
|
||||
// Run the seed function
|
||||
seedDemoUser();
|
||||
Reference in New Issue
Block a user