mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:41:09 +02:00
chore: remove remaining Hetzner references across codebase
Deleted: - DOCKER_REGISTRY_SETUP.md, QUICK_START_CICD.md (legacy CI/CD docs) - docs/ULOAD-DEPLOYMENT.md (Hetzner VPS deployment guide) - scripts/get-ssh-key.sh, scripts/remove-coolify-references.sh (legacy scripts) Updated Hetzner → MinIO references in: - shared-storage (package.json, README, client.ts, types.ts) - App CLAUDE.md files (mukke, storage, planta, picture) - .claude/GUIDELINES.md, sveltekit-web.md guideline - TROUBLESHOOTING.md, SETUP_TEMPLATES.md (replaced IPs with placeholders) - GIT_WORKFLOW.md, COMMANDS.md - services/matrix-project-doc-bot/CLAUDE.md Remaining Hetzner mentions are in historical devlogs/audits and docs that list Hetzner as a hosting alternative (not as active infrastructure). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cc5ba3bb90
commit
7c1e2aca49
20 changed files with 53 additions and 1163 deletions
|
|
@ -49,7 +49,7 @@ This directory contains comprehensive guidelines for working in the Mana Univers
|
|||
| **Mobile** | Expo SDK 52-54 | React Native, NativeWind |
|
||||
| **Database** | PostgreSQL | Via Drizzle ORM |
|
||||
| **Auth** | Mana Core Auth | Better Auth, EdDSA JWT |
|
||||
| **Storage** | S3-compatible | MinIO (dev), Hetzner (prod) |
|
||||
| **Storage** | S3-compatible | MinIO |
|
||||
|
||||
## Project Structure
|
||||
|
||||
|
|
|
|||
|
|
@ -784,16 +784,16 @@ services:
|
|||
PUBLIC_BACKEND_URL: http://myapp-backend:3000
|
||||
PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||
# Client-side URLs (browser access via public IP)
|
||||
PUBLIC_BACKEND_URL_CLIENT: http://46.224.108.214:3000
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: http://46.224.108.214:3001
|
||||
PUBLIC_BACKEND_URL_CLIENT: https://myapp.mana.how:3000
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://myapp.mana.how:3001
|
||||
```
|
||||
|
||||
### Why Two URLs?
|
||||
|
||||
| Variable | Purpose | Example |
|
||||
| ---------------------------------- | --------------------------------- | ---------------------------- |
|
||||
| `PUBLIC_MANA_CORE_AUTH_URL` | Server-to-server (SSR, API calls) | `http://mana-core-auth:3001` |
|
||||
| `PUBLIC_MANA_CORE_AUTH_URL_CLIENT` | Browser to server | `http://46.224.108.214:3001` |
|
||||
| Variable | Purpose | Example |
|
||||
| ---------------------------------- | --------------------------------- | ----------------------------- |
|
||||
| `PUBLIC_MANA_CORE_AUTH_URL` | Server-to-server (SSR, API calls) | `http://mana-core-auth:3001` |
|
||||
| `PUBLIC_MANA_CORE_AUTH_URL_CLIENT` | Browser to server | `https://myapp.mana.how:3001` |
|
||||
|
||||
Docker containers can reach each other by service name (`mana-core-auth`), but browsers need the public IP/domain.
|
||||
|
||||
|
|
|
|||
12
COMMANDS.md
12
COMMANDS.md
|
|
@ -255,11 +255,11 @@ pnpm drizzle-kit studio # Drizzle Studio
|
|||
|
||||
Zentraler Such-Microservice mit SearXNG für Web-Suche und Content-Extraktion.
|
||||
|
||||
| Service | Port | Befehl |
|
||||
| -------- | ---- | ------------------------- |
|
||||
| API | 3021 | `pnpm dev:search` |
|
||||
| SearXNG | 8080 | (Docker) |
|
||||
| Redis | 6380 | (Docker) |
|
||||
| Service | Port | Befehl |
|
||||
| ------- | ---- | ----------------- |
|
||||
| API | 3021 | `pnpm dev:search` |
|
||||
| SearXNG | 8080 | (Docker) |
|
||||
| Redis | 6380 | (Docker) |
|
||||
|
||||
```bash
|
||||
# SearXNG + Redis in Docker starten
|
||||
|
|
@ -489,4 +489,4 @@ pnpm --filter @manacore/shared-ui build
|
|||
shared-ui - Gemeinsame UI-Komponenten für alle Web-Apps
|
||||
shared-auth - Client-seitige Auth-Integration für Web/Mobile
|
||||
shared-nestjs-auth - NestJS Guards/Decorators für JWT-Validierung
|
||||
shared-storage - S3-kompatible Storage-Abstraktion (MinIO/Hetzner)
|
||||
shared-storage - S3-kompatible Storage-Abstraktion (MinIO)
|
||||
|
|
|
|||
|
|
@ -1,315 +0,0 @@
|
|||
# GitHub Container Registry Setup Guide
|
||||
|
||||
## Why GitHub Container Registry (ghcr.io)?
|
||||
|
||||
For a 2-person team, GitHub Container Registry is the **easiest and most cost-effective** option:
|
||||
|
||||
✅ **No additional signup** - Uses your existing GitHub account
|
||||
✅ **Automatic authentication** - Uses `GITHUB_TOKEN` (no manual token creation)
|
||||
✅ **Team access built-in** - Your colleague already has access via the GitHub repo
|
||||
✅ **No manual repo creation** - Repositories created automatically when you push
|
||||
✅ **Unlimited private images** - Free tier is generous
|
||||
✅ **No rate limits** - Unlike Docker Hub free tier (100 pulls/6 hours)
|
||||
|
||||
---
|
||||
|
||||
## ✅ Setup Complete!
|
||||
|
||||
The Hive Mind has already configured your workflows to use GitHub Container Registry. **No additional setup required!**
|
||||
|
||||
### What Was Changed
|
||||
|
||||
1. **`.github/workflows/ci-main.yml`**:
|
||||
- Login action now uses `ghcr.io` registry
|
||||
- Authentication uses `GITHUB_TOKEN` (automatically available)
|
||||
- Image names changed to `ghcr.io/wuesteon/service-name` format
|
||||
|
||||
### How It Works
|
||||
|
||||
When GitHub Actions runs:
|
||||
|
||||
1. Automatically logs in to ghcr.io using `GITHUB_TOKEN`
|
||||
2. Builds Docker images
|
||||
3. Pushes to: `ghcr.io/wuesteon/mana-core-auth`, `ghcr.io/wuesteon/chat-backend`, etc.
|
||||
4. Images are automatically private (tied to your repo)
|
||||
|
||||
---
|
||||
|
||||
## Accessing Images
|
||||
|
||||
### For You and Your Colleague
|
||||
|
||||
**Both of you can pull images** because you both have access to the GitHub repository:
|
||||
|
||||
```bash
|
||||
# Login to ghcr.io (one-time setup per machine)
|
||||
echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin
|
||||
|
||||
# Pull an image
|
||||
docker pull ghcr.io/wuesteon/mana-core-auth:latest
|
||||
```
|
||||
|
||||
### For Deployment Servers (Staging/Production)
|
||||
|
||||
Create a **Personal Access Token (PAT)** with `read:packages` permission:
|
||||
|
||||
1. **GitHub** → **Settings** → **Developer settings** → **Personal access tokens** → **Tokens (classic)**
|
||||
2. Click **Generate new token (classic)**
|
||||
3. Name: `ghcr-pull-token`
|
||||
4. Select scopes: `read:packages`
|
||||
5. Click **Generate token**
|
||||
6. **Copy the token** (you won't see it again!)
|
||||
|
||||
Then add to your deployment server:
|
||||
|
||||
```bash
|
||||
# Login on your Hetzner server
|
||||
echo YOUR_PAT_TOKEN | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin
|
||||
|
||||
# Now docker compose pull will work
|
||||
cd ~/manacore-staging
|
||||
docker compose pull
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GitHub Secrets Required
|
||||
|
||||
### ✅ Already Configured (No Action Needed)
|
||||
|
||||
- `GITHUB_TOKEN` - Automatically available in GitHub Actions
|
||||
|
||||
### 🔧 Optional: For Private Repo Pull from Deployment Servers
|
||||
|
||||
If you want to pull images on your Hetzner servers, add these secrets:
|
||||
|
||||
**GitHub** → **Your Repo** → **Settings** → **Secrets and variables** → **Actions** → **New repository secret**
|
||||
|
||||
| Secret Name | Value | Purpose |
|
||||
| --------------- | --------------------------------- | ----------------------------- |
|
||||
| `GHCR_USERNAME` | `wuesteon` (your GitHub username) | For pulling images on servers |
|
||||
| `GHCR_TOKEN` | Your PAT from above | For pulling images on servers |
|
||||
|
||||
Then update `docker-compose.staging.yml` and `docker-compose.production.yml` to include login:
|
||||
|
||||
```yaml
|
||||
# Add this before docker compose pull in deployment workflows
|
||||
echo ${{ secrets.GHCR_TOKEN }} | docker login ghcr.io -u ${{ secrets.GHCR_USERNAME }} --password-stdin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Image Naming Convention
|
||||
|
||||
Your images will be named:
|
||||
|
||||
```
|
||||
ghcr.io/wuesteon/mana-core-auth:latest
|
||||
ghcr.io/wuesteon/mana-core-auth:main
|
||||
ghcr.io/wuesteon/mana-core-auth:main-a1b2c3d
|
||||
|
||||
ghcr.io/wuesteon/chat-backend:latest
|
||||
ghcr.io/wuesteon/chat-backend:main
|
||||
ghcr.io/wuesteon/chat-backend:main-a1b2c3d
|
||||
|
||||
ghcr.io/wuesteon/maerchenzauber-backend:latest
|
||||
# ... etc for all services
|
||||
```
|
||||
|
||||
**Tags**:
|
||||
|
||||
- `latest` - Most recent build from main branch
|
||||
- `main` - Same as latest (branch-based tag)
|
||||
- `main-a1b2c3d` - Specific commit SHA (for rollbacks)
|
||||
|
||||
---
|
||||
|
||||
## Viewing Your Images
|
||||
|
||||
1. Go to your GitHub profile: `https://github.com/wuesteon`
|
||||
2. Click **Packages** tab
|
||||
3. You'll see all your Docker images listed
|
||||
4. Click on an image to see:
|
||||
- All versions/tags
|
||||
- Pull commands
|
||||
- Size and storage usage
|
||||
- Package settings (visibility, access)
|
||||
|
||||
---
|
||||
|
||||
## Making Images Public (Optional)
|
||||
|
||||
If you want to make images public (so anyone can pull without authentication):
|
||||
|
||||
1. Go to the package page: `https://github.com/users/wuesteon/packages/container/SERVICE_NAME`
|
||||
2. Click **Package settings**
|
||||
3. Scroll to **Danger Zone**
|
||||
4. Click **Change visibility** → **Public**
|
||||
5. Type the package name to confirm
|
||||
|
||||
**Recommendation**: Keep images **private** for production services.
|
||||
|
||||
---
|
||||
|
||||
## Team Access Management
|
||||
|
||||
Your colleague automatically has access because they have access to the repository.
|
||||
|
||||
### To give access to someone else:
|
||||
|
||||
1. Go to package page
|
||||
2. Click **Package settings**
|
||||
3. Under **Manage access**, click **Add people or teams**
|
||||
4. Enter their GitHub username
|
||||
5. Choose role: **Read** (pull only) or **Write** (push + pull)
|
||||
|
||||
---
|
||||
|
||||
## Updating docker-compose Files
|
||||
|
||||
Update image references in `docker-compose.staging.yml` and `docker-compose.production.yml`:
|
||||
|
||||
**Before** (if using Docker Hub):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
mana-core-auth:
|
||||
image: wuesteon/mana-core-auth:latest
|
||||
```
|
||||
|
||||
**After** (using GitHub Container Registry):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
mana-core-auth:
|
||||
image: ghcr.io/wuesteon/mana-core-auth:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Storage Limits
|
||||
|
||||
**GitHub Container Registry Free Tier**:
|
||||
|
||||
- **Storage**: 500 MB (across all packages)
|
||||
- **Data transfer**: 1 GB/month
|
||||
|
||||
**How long until you hit limits?**:
|
||||
|
||||
- Average Docker image size: 150 MB
|
||||
- You can store ~3 images before hitting 500 MB
|
||||
- **Recommendation**: Enable auto-delete for old images
|
||||
|
||||
### Auto-Delete Old Images
|
||||
|
||||
Create `.github/workflows/cleanup-ghcr.yml`:
|
||||
|
||||
```yaml
|
||||
name: Cleanup Old Container Images
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # Weekly on Sunday
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
cleanup:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Delete old images
|
||||
uses: actions/delete-package-versions@v5
|
||||
with:
|
||||
package-name: 'mana-core-auth'
|
||||
package-type: 'container'
|
||||
min-versions-to-keep: 3
|
||||
delete-only-untagged-versions: 'true'
|
||||
```
|
||||
|
||||
This keeps only the 3 most recent versions and deletes untagged images.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: "Permission denied while trying to connect to the Docker daemon"
|
||||
|
||||
**Solution**: Add your user to docker group on deployment server:
|
||||
|
||||
```bash
|
||||
sudo usermod -aG docker $USER
|
||||
newgrp docker
|
||||
```
|
||||
|
||||
### Issue: "unauthorized: unauthenticated"
|
||||
|
||||
**Solution**: Login again with your PAT:
|
||||
|
||||
```bash
|
||||
echo YOUR_PAT_TOKEN | docker login ghcr.io -u wuesteon --password-stdin
|
||||
```
|
||||
|
||||
### Issue: "denied: permission_denied"
|
||||
|
||||
**Solution**: Check your PAT has `read:packages` scope. Create a new one if needed.
|
||||
|
||||
### Issue: Images not appearing in GitHub Packages
|
||||
|
||||
**Solution**:
|
||||
|
||||
1. Check GitHub Actions workflow completed successfully
|
||||
2. Check the workflow pushed images (look for "Pushed to ghcr.io" in logs)
|
||||
3. Images may take 1-2 minutes to appear in Packages tab
|
||||
|
||||
---
|
||||
|
||||
## Comparison: Docker Hub vs ghcr.io
|
||||
|
||||
| Feature | Docker Hub (Free) | GitHub Container Registry |
|
||||
| -------------------- | ------------------------------ | ------------------------- |
|
||||
| **Cost** | Free (limited) | Free (generous) |
|
||||
| **Pull rate limits** | 100 pulls/6 hours | Unlimited |
|
||||
| **Storage** | 1 repo (free tier) | 500 MB (all packages) |
|
||||
| **Private repos** | 1 private repo | Unlimited private |
|
||||
| **Team access** | Manual invitation | Automatic via GitHub |
|
||||
| **Authentication** | Username + Token | GitHub account |
|
||||
| **Setup complexity** | Medium (create repos manually) | Low (automatic) |
|
||||
| **Integration** | Good | Excellent (native GitHub) |
|
||||
|
||||
**Winner for 2-person team**: GitHub Container Registry ✅
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. ✅ **Nothing!** - Setup is complete
|
||||
2. 🚀 **Test it**: Push a commit and watch GitHub Actions build + push images
|
||||
3. 👀 **View images**: Check your GitHub profile → Packages tab
|
||||
4. 🔧 **Optional**: Set up PAT for deployment servers (if deploying now)
|
||||
5. 🧹 **Optional**: Create cleanup workflow to auto-delete old images
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**What you get with ghcr.io**:
|
||||
|
||||
- ✅ Zero setup (already configured by Hive Mind)
|
||||
- ✅ Automatic authentication in GitHub Actions
|
||||
- ✅ Your colleague has instant access
|
||||
- ✅ No rate limits
|
||||
- ✅ Free private images
|
||||
- ✅ Native GitHub integration
|
||||
|
||||
**What you need to do**:
|
||||
|
||||
- ✅ Nothing! (for CI/CD pipeline)
|
||||
- 🔧 Create PAT for deployment servers (5 minutes)
|
||||
- 🧹 Optional: Set up auto-cleanup (5 minutes)
|
||||
|
||||
**Estimated time to be fully operational**: 5 minutes (just create PAT for servers)
|
||||
|
||||
---
|
||||
|
||||
**Created by**: Hive Mind Collective Intelligence
|
||||
**Date**: 2025-11-27
|
||||
**Status**: ✅ Production-Ready
|
||||
|
|
@ -1,251 +0,0 @@
|
|||
# Quick Start - CI/CD Pipeline
|
||||
|
||||
Get the CI/CD pipeline running in 30 minutes or less.
|
||||
|
||||
## Prerequisites Checklist
|
||||
|
||||
- [ ] GitHub repository access with admin permissions
|
||||
- [ ] Docker Hub account (or alternative registry)
|
||||
- [ ] Server with Ubuntu 20.04+ (for staging/production)
|
||||
- [ ] SSH access to server
|
||||
|
||||
## Step 1: Configure GitHub Secrets (10 minutes)
|
||||
|
||||
### Essential Secrets (Minimum Required)
|
||||
|
||||
```bash
|
||||
# Docker Registry (3 secrets)
|
||||
DOCKER_USERNAME=your-username
|
||||
DOCKER_PASSWORD=your-token
|
||||
DOCKER_REGISTRY=your-username
|
||||
|
||||
# Staging Server (2 secrets)
|
||||
STAGING_HOST=staging.example.com
|
||||
STAGING_USER=deploy
|
||||
|
||||
# SSH Key (generate and add)
|
||||
ssh-keygen -t ed25519 -C "github-actions" -f ~/.ssh/github-staging
|
||||
# Copy private key to:
|
||||
STAGING_SSH_KEY=<contents of ~/.ssh/github-staging>
|
||||
```
|
||||
|
||||
**Add in GitHub**: Repository > Settings > Secrets and variables > Actions > New repository secret
|
||||
|
||||
## Step 2: Prepare Server (10 minutes)
|
||||
|
||||
### On Your Server
|
||||
|
||||
```bash
|
||||
# 1. Create deploy user
|
||||
sudo adduser deploy
|
||||
sudo usermod -aG docker deploy
|
||||
|
||||
# 2. Install Docker
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
sudo apt install docker-compose-plugin
|
||||
|
||||
# 3. Add SSH key
|
||||
sudo su - deploy
|
||||
mkdir -p ~/.ssh
|
||||
echo "ssh-ed25519 YOUR_PUBLIC_KEY github-actions" >> ~/.ssh/authorized_keys
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
|
||||
# 4. Create directories
|
||||
mkdir -p ~/manacore-staging/{logs,backups}
|
||||
|
||||
# 5. Test SSH from your machine
|
||||
ssh deploy@staging.example.com
|
||||
```
|
||||
|
||||
## Step 3: Test the Pipeline (10 minutes)
|
||||
|
||||
### Test PR Workflow
|
||||
|
||||
```bash
|
||||
# 1. Create test branch
|
||||
git checkout -b test/ci-pipeline
|
||||
|
||||
# 2. Make a change
|
||||
echo "# CI/CD Test" >> README.md
|
||||
git add README.md
|
||||
git commit -m "test: verify CI pipeline"
|
||||
|
||||
# 3. Push and create PR
|
||||
git push origin test/ci-pipeline
|
||||
```
|
||||
|
||||
**Expected**: PR checks run in GitHub Actions tab
|
||||
|
||||
### Test Staging Deployment
|
||||
|
||||
```bash
|
||||
# 1. Merge the PR
|
||||
# GitHub UI > Merge pull request
|
||||
|
||||
# 2. Check GitHub Actions
|
||||
# Watch "CI - Main Branch" workflow
|
||||
# Watch "CD - Staging Deployment" workflow
|
||||
|
||||
# 3. Verify deployment
|
||||
./scripts/deploy/health-check.sh staging
|
||||
```
|
||||
|
||||
## Step 4: First Production Deploy (Optional)
|
||||
|
||||
```bash
|
||||
# 1. Add production secrets (same as staging but with PRODUCTION_ prefix)
|
||||
# 2. Go to Actions > CD - Production Deployment
|
||||
# 3. Run workflow:
|
||||
# - Service: all
|
||||
# - Environment: production
|
||||
# - Confirm: deploy
|
||||
# 4. Approve when prompted
|
||||
# 5. Monitor deployment
|
||||
```
|
||||
|
||||
## Minimal Secrets Configuration
|
||||
|
||||
If you want to test quickly, here's the absolute minimum:
|
||||
|
||||
### For PR Testing Only (No Deployment)
|
||||
|
||||
```
|
||||
# Just these 3 secrets to test PR workflow:
|
||||
DOCKER_USERNAME=your-username
|
||||
DOCKER_PASSWORD=your-token
|
||||
DOCKER_REGISTRY=your-username
|
||||
```
|
||||
|
||||
### For Staging Deployment
|
||||
|
||||
```
|
||||
# Add these 5 more secrets:
|
||||
STAGING_HOST=your-server-ip
|
||||
STAGING_USER=deploy
|
||||
STAGING_SSH_KEY=<private-key>
|
||||
STAGING_SUPABASE_URL=https://xxx.supabase.co
|
||||
STAGING_SUPABASE_ANON_KEY=<key>
|
||||
```
|
||||
|
||||
## Common Commands
|
||||
|
||||
### Build and Deploy
|
||||
|
||||
```bash
|
||||
# Build all images
|
||||
./scripts/deploy/build-and-push.sh all latest
|
||||
|
||||
# Deploy to staging
|
||||
./scripts/deploy/deploy-hetzner.sh staging all
|
||||
|
||||
# Check health
|
||||
./scripts/deploy/health-check.sh staging
|
||||
|
||||
# Rollback if needed
|
||||
./scripts/deploy/rollback.sh staging all
|
||||
```
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
# Start local services
|
||||
pnpm run docker:up
|
||||
|
||||
# View logs
|
||||
pnpm run docker:logs
|
||||
|
||||
# Stop services
|
||||
pnpm run docker:down
|
||||
```
|
||||
|
||||
### Debugging
|
||||
|
||||
```bash
|
||||
# Check GitHub Actions logs
|
||||
# GitHub > Actions > Select workflow > View logs
|
||||
|
||||
# Check server
|
||||
ssh deploy@staging.example.com
|
||||
cd ~/manacore-staging
|
||||
docker compose ps
|
||||
docker compose logs -f
|
||||
|
||||
# Test SSH connection
|
||||
ssh -i ~/.ssh/github-staging deploy@staging.example.com 'echo "Success"'
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Permission denied (publickey)"
|
||||
|
||||
```bash
|
||||
# Check SSH key was added to server
|
||||
ssh deploy@staging.example.com 'cat ~/.ssh/authorized_keys'
|
||||
|
||||
# Verify GitHub secret has correct private key
|
||||
# Settings > Secrets > STAGING_SSH_KEY
|
||||
```
|
||||
|
||||
### "Docker command not found"
|
||||
|
||||
```bash
|
||||
# Install Docker on server
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
sudo usermod -aG docker deploy
|
||||
# Logout and login again
|
||||
```
|
||||
|
||||
### "Health checks failing"
|
||||
|
||||
```bash
|
||||
# Check service logs
|
||||
ssh deploy@staging.example.com
|
||||
cd ~/manacore-staging
|
||||
docker compose logs --tail=100 service-name
|
||||
|
||||
# Check if service is running
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
Once basic pipeline works:
|
||||
|
||||
1. [ ] Add remaining secrets (database, Redis, Azure, etc.)
|
||||
2. [ ] Configure production environment
|
||||
3. [ ] Set up monitoring (UptimeRobot, etc.)
|
||||
4. [ ] Read full documentation in `docs/`
|
||||
5. [ ] Train team on deployment process
|
||||
|
||||
## Full Documentation
|
||||
|
||||
- **Quick Reference**: `CI_CD_README.md`
|
||||
- **Setup Guide**: `docs/CI_CD_SETUP.md`
|
||||
- **Deployment Guide**: `docs/DEPLOYMENT.md`
|
||||
- **Docker Guide**: `docs/DOCKER_GUIDE.md`
|
||||
- **Implementation Summary**: `CI_CD_IMPLEMENTATION_SUMMARY.md`
|
||||
|
||||
## Support
|
||||
|
||||
Stuck? Check:
|
||||
|
||||
1. GitHub Actions logs (most errors shown here)
|
||||
2. Server logs: `ssh deploy@server 'cd ~/manacore-staging && docker compose logs'`
|
||||
3. Documentation in `docs/` folder
|
||||
4. Script output (all scripts have detailed error messages)
|
||||
|
||||
## Success Indicators
|
||||
|
||||
You'll know it's working when:
|
||||
|
||||
- ✅ PR checks pass on every pull request
|
||||
- ✅ Docker images appear in your registry
|
||||
- ✅ Services run on staging server
|
||||
- ✅ Health checks return 200 OK
|
||||
- ✅ `docker compose ps` shows all services as "Up"
|
||||
|
||||
---
|
||||
|
||||
**Estimated Time**: 30 minutes for basic setup
|
||||
**Difficulty**: Beginner-friendly with step-by-step instructions
|
||||
**Production Ready**: Yes, after completing all secrets
|
||||
|
|
@ -466,7 +466,7 @@ mv .github/workflows/test.yml.bak .github/workflows/test.yml
|
|||
|
||||
```bash
|
||||
# Connect to staging server
|
||||
ssh -i ~/.ssh/hetzner_deploy_key deploy@46.224.108.214
|
||||
ssh -i ~/.ssh/deploy_key deploy@your-server-ip
|
||||
|
||||
# Check container status
|
||||
cd ~/manacore-staging
|
||||
|
|
@ -519,9 +519,9 @@ healthcheck:
|
|||
|
||||
```bash
|
||||
# Test from outside the server
|
||||
curl http://46.224.108.214:3001/api/v1/health
|
||||
curl http://46.224.108.214:3002/api/v1/health
|
||||
curl http://46.224.108.214:3000/health
|
||||
curl http://your-server-ip:3001/api/v1/health
|
||||
curl http://your-server-ip:3002/api/v1/health
|
||||
curl http://your-server-ip:3000/health
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -632,8 +632,8 @@ chat-web:
|
|||
PUBLIC_BACKEND_URL: http://chat-backend:3002
|
||||
PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||
# Client-side URLs (browser access via public IP)
|
||||
PUBLIC_BACKEND_URL_CLIENT: http://46.224.108.214:3002
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: http://46.224.108.214:3001
|
||||
PUBLIC_BACKEND_URL_CLIENT: http://your-server-ip:3002
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: http://your-server-ip:3001
|
||||
```
|
||||
|
||||
2. **Inject into HTML via hooks.server.ts:**
|
||||
|
|
@ -677,7 +677,7 @@ Open browser DevTools (F12) → Console:
|
|||
|
||||
```javascript
|
||||
window.__PUBLIC_MANA_CORE_AUTH_URL__;
|
||||
// Should show: "http://46.224.108.214:3001"
|
||||
// Should show: "http://your-server-ip:3001"
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -686,7 +686,7 @@ window.__PUBLIC_MANA_CORE_AUTH_URL__;
|
|||
|
||||
**Symptoms:**
|
||||
|
||||
- Browser console shows: `Access to fetch at 'http://46.224.108.214:3001/...' from origin 'http://46.224.108.214:3000' has been blocked by CORS policy`
|
||||
- Browser console shows: `Access to fetch at 'http://your-server-ip:3001/...' from origin 'http://your-server-ip:3000' has been blocked by CORS policy`
|
||||
- API calls work via curl but fail from browser
|
||||
- Preflight OPTIONS requests fail
|
||||
|
||||
|
|
@ -694,8 +694,8 @@ window.__PUBLIC_MANA_CORE_AUTH_URL__;
|
|||
|
||||
Browser security blocks requests between different origins (port counts as different origin):
|
||||
|
||||
- chat-web: `http://46.224.108.214:3000`
|
||||
- mana-core-auth: `http://46.224.108.214:3001`
|
||||
- chat-web: `http://your-server-ip:3000`
|
||||
- mana-core-auth: `http://your-server-ip:3001`
|
||||
|
||||
Even though they're on the same IP, different ports = different origins = CORS blocked.
|
||||
|
||||
|
|
@ -708,7 +708,7 @@ mana-core-auth:
|
|||
environment:
|
||||
# ... other env vars ...
|
||||
# CORS - Allow chat-web and other staging origins
|
||||
CORS_ORIGINS: http://46.224.108.214:3000,http://46.224.108.214:3002,http://localhost:3000
|
||||
CORS_ORIGINS: http://your-server-ip:3000,http://your-server-ip:3002,http://localhost:3000
|
||||
```
|
||||
|
||||
**CORS Configuration in mana-core-auth:**
|
||||
|
|
@ -736,13 +736,13 @@ app.enableCors({
|
|||
|
||||
```bash
|
||||
# Test CORS preflight
|
||||
curl -X OPTIONS http://46.224.108.214:3001/api/v1/auth/register \
|
||||
-H "Origin: http://46.224.108.214:3000" \
|
||||
curl -X OPTIONS http://your-server-ip:3001/api/v1/auth/register \
|
||||
-H "Origin: http://your-server-ip:3000" \
|
||||
-H "Access-Control-Request-Method: POST" \
|
||||
-v
|
||||
|
||||
# Should see in response headers:
|
||||
# Access-Control-Allow-Origin: http://46.224.108.214:3000
|
||||
# Access-Control-Allow-Origin: http://your-server-ip:3000
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -771,7 +771,7 @@ The CD workflow was calling `pnpm run db:migrate` but that script doesn't exist
|
|||
1. **Manual fix (immediate):**
|
||||
|
||||
```bash
|
||||
ssh -i ~/.ssh/hetzner_deploy_key deploy@46.224.108.214
|
||||
ssh -i ~/.ssh/deploy_key deploy@your-server-ip
|
||||
cd ~/manacore-staging
|
||||
|
||||
# Push schema to database (--force skips interactive confirmation)
|
||||
|
|
@ -822,7 +822,7 @@ docker compose exec -T postgres psql -U postgres -d manacore_auth -c '\dt auth.*
|
|||
1. **SSH to server:**
|
||||
|
||||
```bash
|
||||
ssh -i ~/.ssh/hetzner_deploy_key deploy@46.224.108.214
|
||||
ssh -i ~/.ssh/deploy_key deploy@your-server-ip
|
||||
cd ~/manacore-staging
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ Playback uses HTML5 Audio (browser-native codec support). Upload accepts any `au
|
|||
| Metadata | music-metadata (server-side) |
|
||||
| Backend | NestJS 10, Drizzle ORM |
|
||||
| Database | PostgreSQL |
|
||||
| Storage | MinIO (dev) / Hetzner S3 (prod) |
|
||||
| Storage | MinIO (S3-compatible) |
|
||||
| Auth | mana-core-auth |
|
||||
|
||||
## Environment Variables
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ DATABASE_URL=postgresql://picture:password@localhost:5432/picture
|
|||
MANA_CORE_AUTH_URL=http://localhost:3001
|
||||
|
||||
# Storage Configuration
|
||||
# Options: 'local' (default) or 's3' (for Hetzner Object Storage)
|
||||
# Options: 'local' (default) or 's3' (for MinIO/S3-compatible storage)
|
||||
STORAGE_MODE=local
|
||||
|
||||
# Local Storage (for development)
|
||||
LOCAL_STORAGE_PATH=./uploads
|
||||
|
||||
# S3/Hetzner Object Storage (for production)
|
||||
# S3/MinIO Object Storage (for production)
|
||||
# S3_ENDPOINT=fsn1.your-objectstorage.com
|
||||
# S3_REGION=eu-central-1
|
||||
# S3_ACCESS_KEY=your-access-key
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ pnpm preview # Preview production build
|
|||
- **Web**: SvelteKit 2.x, Svelte 5 (runes mode), Tailwind CSS
|
||||
- **Backend**: NestJS 10, Drizzle ORM, PostgreSQL
|
||||
- **AI**: Google Gemini Vision for plant analysis
|
||||
- **Storage**: MinIO (local) / Hetzner S3 (prod)
|
||||
- **Storage**: MinIO (S3-compatible)
|
||||
- **Auth**: Mana Core Auth (JWT)
|
||||
- **Types**: TypeScript 5.x
|
||||
|
||||
|
|
@ -163,5 +163,5 @@ PUBLIC_MANA_CORE_AUTH_URL=http://localhost:3001
|
|||
1. **Authentication**: Uses Mana Core Auth (JWT in Authorization header)
|
||||
2. **Database**: PostgreSQL with Drizzle ORM
|
||||
3. **Port**: Backend runs on port 3022 by default
|
||||
4. **Storage**: Photos stored in MinIO (local) / Hetzner S3 (prod)
|
||||
4. **Storage**: Photos stored in MinIO (S3-compatible)
|
||||
5. **AI**: Google Gemini Vision for plant identification
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ pnpm build # Build for production
|
|||
- **Web**: SvelteKit 2.x, Svelte 5 (runes mode), Tailwind CSS
|
||||
- **Landing**: Astro 5.x, Tailwind CSS
|
||||
- **Backend**: NestJS 11, Drizzle ORM, PostgreSQL
|
||||
- **Storage**: S3-compatible (MinIO local, Hetzner production)
|
||||
- **Storage**: S3-compatible (MinIO)
|
||||
- **Types**: TypeScript 5.x
|
||||
|
||||
## Architecture
|
||||
|
|
|
|||
|
|
@ -238,10 +238,10 @@ git diff HEAD -- docker-compose.staging.yml # See what changed
|
|||
|
||||
```yaml
|
||||
# WRONG - HTTP IP address
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: http://46.224.108.214:3001
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: http://192.168.1.100:3001
|
||||
|
||||
# CORRECT - HTTPS staging domain
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.staging.manacore.ai
|
||||
# CORRECT - HTTPS domain
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how
|
||||
```
|
||||
|
||||
**CI Check:** The `staging-config-check.yml` workflow validates this on every PR that touches `docker-compose.staging.yml`.
|
||||
|
|
|
|||
|
|
@ -159,8 +159,8 @@ myproject-web:
|
|||
PUBLIC_BACKEND_URL: http://myproject-backend:30XX
|
||||
PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||
# Client-side URLs (browser access via public IP)
|
||||
PUBLIC_BACKEND_URL_CLIENT: http://46.224.108.214:30XX
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: http://46.224.108.214:3001
|
||||
PUBLIC_BACKEND_URL_CLIENT: http://your-server-ip:30XX
|
||||
PUBLIC_MANA_CORE_AUTH_URL_CLIENT: http://your-server-ip:3001
|
||||
depends_on:
|
||||
myproject-backend:
|
||||
condition: service_healthy
|
||||
|
|
@ -255,7 +255,7 @@ myproject-backend:
|
|||
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/myproject
|
||||
MANA_CORE_AUTH_URL: http://mana-core-auth:3001
|
||||
# CORS - Include app's web AND manacore-web dashboard
|
||||
CORS_ORIGINS: http://46.224.108.214:51XX,http://46.224.108.214:5173,http://localhost:51XX,http://localhost:5173
|
||||
CORS_ORIGINS: http://your-server-ip:51XX,http://your-server-ip:5173,http://localhost:51XX,http://localhost:5173
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
|
@ -287,7 +287,7 @@ myproject-backend:
|
|||
### Create Database on Staging
|
||||
|
||||
```bash
|
||||
ssh -i ~/.ssh/hetzner_deploy_key deploy@46.224.108.214
|
||||
ssh -i ~/.ssh/deploy_key deploy@your-server-ip
|
||||
|
||||
# Create database
|
||||
docker exec manacore-postgres-staging psql -U postgres -c 'CREATE DATABASE myproject;'
|
||||
|
|
@ -314,14 +314,14 @@ docker exec manacore-postgres-staging psql -U postgres -c '\l' | grep myproject
|
|||
docker ps --format '{{.Names}}: {{.Image}}' | grep myproject
|
||||
|
||||
# Check health endpoint
|
||||
curl http://46.224.108.214:30XX/api/v1/health
|
||||
curl http://your-server-ip:30XX/api/v1/health
|
||||
|
||||
# Check logs for errors
|
||||
docker logs myproject-backend-staging --tail 50
|
||||
|
||||
# Test CORS (from manacore-web origin)
|
||||
curl -I -X OPTIONS http://46.224.108.214:30XX/api/v1/endpoint \
|
||||
-H "Origin: http://46.224.108.214:5173" \
|
||||
curl -I -X OPTIONS http://your-server-ip:30XX/api/v1/endpoint \
|
||||
-H "Origin: http://your-server-ip:5173" \
|
||||
-H "Access-Control-Request-Method: GET"
|
||||
```
|
||||
|
||||
|
|
@ -395,7 +395,7 @@ manacore-web:
|
|||
# ... existing env vars ...
|
||||
# Add new backend URL
|
||||
PUBLIC_MYSERVICE_API_URL: http://myservice-backend:30XX
|
||||
PUBLIC_MYSERVICE_API_URL_CLIENT: http://46.224.108.214:30XX
|
||||
PUBLIC_MYSERVICE_API_URL_CLIENT: http://your-server-ip:30XX
|
||||
```
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,451 +0,0 @@
|
|||
# uload Deployment Guide
|
||||
|
||||
Schritt-für-Schritt Anleitung zum Deployment von uload mit Coolify auf Hetzner VPS.
|
||||
|
||||
## Architektur
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Hetzner VPS │
|
||||
│ ┌───────────────────────────────────────────────────────────┐ │
|
||||
│ │ Coolify │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │
|
||||
│ │ │ uload │ │ PostgreSQL │ │ Redis │ │ │
|
||||
│ │ │ (Node) │ │ (16) │ │ (7) │ │ │
|
||||
│ │ │ :3000 │ │ :5432 │ │ :6379 │ │ │
|
||||
│ │ └─────────────┘ └─────────────┘ └─────────────────┘ │ │
|
||||
│ │ │ │ │ │ │
|
||||
│ │ └────────────────┴──────────────────┘ │ │
|
||||
│ │ Traefik (SSL/Proxy) │ │
|
||||
│ │ :80 / :443 │ │
|
||||
│ └───────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
https://ulo.ad
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- [ ] Hetzner VPS (mindestens CX21: 2 vCPU, 4GB RAM, 40GB SSD)
|
||||
- [ ] Domain mit DNS-Zugang (z.B. ulo.ad)
|
||||
- [ ] GitHub Account mit Zugriff auf das Repository
|
||||
- [ ] Accounts für externe Services:
|
||||
- Resend (Email)
|
||||
- Stripe (Payments)
|
||||
- Cloudflare R2 (Storage)
|
||||
|
||||
---
|
||||
|
||||
## Schritt 1: Hetzner VPS einrichten
|
||||
|
||||
### 1.1 Server erstellen
|
||||
|
||||
1. Gehe zu [Hetzner Cloud Console](https://console.hetzner.cloud)
|
||||
2. Erstelle neues Projekt oder wähle bestehendes
|
||||
3. Klicke **Add Server**
|
||||
4. Wähle:
|
||||
- **Location:** Falkenstein oder Nürnberg (DE)
|
||||
- **Image:** Ubuntu 22.04
|
||||
- **Type:** CX21 (2 vCPU, 4GB RAM) oder größer
|
||||
- **SSH Key:** Füge deinen öffentlichen SSH-Key hinzu
|
||||
5. Klicke **Create & Buy Now**
|
||||
6. Notiere die **IP-Adresse**
|
||||
|
||||
### 1.2 Mit Server verbinden
|
||||
|
||||
```bash
|
||||
ssh root@DEINE-SERVER-IP
|
||||
```
|
||||
|
||||
### 1.3 System updaten
|
||||
|
||||
```bash
|
||||
apt update && apt upgrade -y
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schritt 2: Coolify installieren
|
||||
|
||||
### 2.1 Installation
|
||||
|
||||
```bash
|
||||
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
|
||||
```
|
||||
|
||||
Die Installation dauert ca. 2-5 Minuten.
|
||||
|
||||
### 2.2 Coolify öffnen
|
||||
|
||||
1. Öffne im Browser: `http://DEINE-SERVER-IP:8000`
|
||||
2. Erstelle Admin-Account (E-Mail + Passwort)
|
||||
3. Wähle **Self-hosted** als Instance Type
|
||||
4. Der Server "localhost" wird automatisch hinzugefügt
|
||||
|
||||
---
|
||||
|
||||
## Schritt 3: PostgreSQL Datenbank erstellen
|
||||
|
||||
### 3.1 In Coolify
|
||||
|
||||
1. Klicke **+ New Resource**
|
||||
2. Wähle **Database**
|
||||
3. Wähle **PostgreSQL**
|
||||
4. Konfiguriere:
|
||||
- **Name:** `uload-postgres`
|
||||
- **Version:** `16-alpine`
|
||||
- **Database Name:** `uload`
|
||||
- **Database User:** `uload`
|
||||
- **Password:** (automatisch generiert oder eigenes)
|
||||
5. Klicke **Start**
|
||||
|
||||
### 3.2 Connection String notieren
|
||||
|
||||
Nach dem Start findest du unter **Connect** die Internal URL:
|
||||
|
||||
```
|
||||
postgresql://uload:PASSWORT@uload-postgres:5432/uload
|
||||
```
|
||||
|
||||
**Wichtig:** Kopiere diese URL - du brauchst sie später!
|
||||
|
||||
---
|
||||
|
||||
## Schritt 4: Redis erstellen (optional, aber empfohlen)
|
||||
|
||||
### 4.1 In Coolify
|
||||
|
||||
1. Klicke **+ New Resource**
|
||||
2. Wähle **Database**
|
||||
3. Wähle **Redis**
|
||||
4. Konfiguriere:
|
||||
- **Name:** `uload-redis`
|
||||
- **Version:** `7-alpine`
|
||||
5. Klicke **Start**
|
||||
|
||||
### 4.2 Connection String notieren
|
||||
|
||||
```
|
||||
redis://uload-redis:6379
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schritt 5: GitHub Repository verbinden
|
||||
|
||||
### 5.1 GitHub App erstellen
|
||||
|
||||
1. In Coolify: Gehe zu **Sources** (linke Sidebar)
|
||||
2. Klicke **+ Add**
|
||||
3. Wähle **GitHub App**
|
||||
4. Klicke **Register GitHub App**
|
||||
5. Du wirst zu GitHub weitergeleitet
|
||||
6. Gib der App einen Namen (z.B. "coolify-uload")
|
||||
7. Klicke **Create GitHub App**
|
||||
8. Installiere die App für dein Repository
|
||||
|
||||
### 5.2 Repository-Zugriff gewähren
|
||||
|
||||
1. Wähle **Only select repositories**
|
||||
2. Wähle `manacore-monorepo`
|
||||
3. Klicke **Install**
|
||||
|
||||
---
|
||||
|
||||
## Schritt 6: uload Application erstellen
|
||||
|
||||
### 6.1 Neue Application
|
||||
|
||||
1. Klicke **+ New Resource**
|
||||
2. Wähle **Application**
|
||||
3. Wähle deine **GitHub App** als Source
|
||||
4. Wähle das Repository `manacore-monorepo`
|
||||
5. Wähle Branch: `main`
|
||||
|
||||
### 6.2 Build-Konfiguration (WICHTIG!)
|
||||
|
||||
Da uload Teil eines Monorepos ist, muss die Build-Konfiguration genau so sein:
|
||||
|
||||
| Einstellung | Wert |
|
||||
| ----------------------- | -------------------------- |
|
||||
| **Base Directory** | `/` (leer lassen oder `/`) |
|
||||
| **Build Pack** | Dockerfile |
|
||||
| **Dockerfile Location** | `uload/Dockerfile` |
|
||||
| **Port Exposes** | `3000` |
|
||||
|
||||
**Warum `/` als Base Directory?**
|
||||
Das Dockerfile benötigt Zugriff auf:
|
||||
|
||||
- `uload/apps/web/` (die App)
|
||||
- `packages/shared-*` (gemeinsame Packages)
|
||||
- `pnpm-workspace.yaml` und `pnpm-lock.yaml` (Workspace-Config)
|
||||
|
||||
---
|
||||
|
||||
## Schritt 7: Environment Variables setzen
|
||||
|
||||
### 7.1 In Coolify
|
||||
|
||||
Gehe zu deiner Application → **Environment Variables** → **Add Variable**
|
||||
|
||||
### 7.2 Erforderliche Variablen
|
||||
|
||||
```env
|
||||
# === APP ===
|
||||
NODE_ENV=production
|
||||
PORT=3000
|
||||
HOST=0.0.0.0
|
||||
ORIGIN=https://ulo.ad
|
||||
|
||||
# === DATABASE ===
|
||||
# Von Schritt 3.2 - PostgreSQL Internal URL
|
||||
DATABASE_URL=postgresql://uload:DEIN-PASSWORT@uload-postgres:5432/uload
|
||||
|
||||
# === REDIS (optional) ===
|
||||
# Von Schritt 4.2
|
||||
REDIS_URL=redis://uload-redis:6379
|
||||
|
||||
# === AUTH ===
|
||||
# Generiere mit: openssl rand -base64 32
|
||||
AUTH_SECRET=GENERIERE-EINEN-SICHEREN-STRING-HIER
|
||||
|
||||
# === EMAIL (Resend) ===
|
||||
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# === PAYMENTS (Stripe) ===
|
||||
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# === STORAGE (Cloudflare R2) ===
|
||||
R2_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
R2_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
R2_BUCKET_NAME=uload-uploads
|
||||
R2_ENDPOINT=https://xxxxxxxxxx.r2.cloudflarestorage.com
|
||||
```
|
||||
|
||||
### 7.3 AUTH_SECRET generieren
|
||||
|
||||
Auf deinem lokalen Rechner:
|
||||
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
Kopiere das Ergebnis als `AUTH_SECRET`.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 8: Domain konfigurieren
|
||||
|
||||
### 8.1 DNS-Einträge setzen
|
||||
|
||||
Bei deinem DNS-Provider (z.B. Cloudflare, Namecheap):
|
||||
|
||||
| Type | Name | Value | TTL |
|
||||
| ---- | ---- | --------------- | ---- |
|
||||
| A | @ | DEINE-SERVER-IP | 3600 |
|
||||
| A | www | DEINE-SERVER-IP | 3600 |
|
||||
|
||||
### 8.2 Domain in Coolify hinzufügen
|
||||
|
||||
1. Gehe zu deiner Application → **Settings**
|
||||
2. Unter **Domains** klicke **+ Add**
|
||||
3. Gib ein: `ulo.ad`
|
||||
4. Aktiviere: **Generate SSL Certificate** (Let's Encrypt)
|
||||
5. Optional: Füge auch `www.ulo.ad` hinzu mit Redirect
|
||||
|
||||
### 8.3 Warten
|
||||
|
||||
DNS-Änderungen können 5-30 Minuten dauern. SSL-Zertifikate werden automatisch erstellt.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 9: Deployment starten
|
||||
|
||||
### 9.1 Erster Deploy
|
||||
|
||||
1. Gehe zu deiner Application
|
||||
2. Klicke **Deploy**
|
||||
3. Warte auf den Build (ca. 3-5 Minuten)
|
||||
|
||||
### 9.2 Build-Logs überwachen
|
||||
|
||||
Klicke auf das laufende Deployment um die Logs zu sehen.
|
||||
|
||||
**Erfolgreicher Build zeigt:**
|
||||
|
||||
```
|
||||
✔ done
|
||||
Listening on http://0.0.0.0:3000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schritt 10: Datenbank-Migration
|
||||
|
||||
### 10.1 Nach erstem Deployment
|
||||
|
||||
Die Datenbank-Tabellen müssen erstellt werden:
|
||||
|
||||
1. In Coolify: Gehe zu deiner Application → **Terminal**
|
||||
2. Oder via SSH:
|
||||
|
||||
```bash
|
||||
# Container-Name finden
|
||||
docker ps | grep uload
|
||||
|
||||
# In Container gehen
|
||||
docker exec -it CONTAINER-NAME sh
|
||||
|
||||
# Migration ausführen
|
||||
npx drizzle-kit push
|
||||
```
|
||||
|
||||
### 10.2 Alternative: Pre-Deploy Command
|
||||
|
||||
In Coolify → Application → **Settings** → **Pre-Deploy Command**:
|
||||
|
||||
```bash
|
||||
cd /app && npx drizzle-kit push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Schritt 11: Verifizieren
|
||||
|
||||
### 11.1 Health Check
|
||||
|
||||
```bash
|
||||
curl https://ulo.ad/api/health
|
||||
```
|
||||
|
||||
Erwartete Antwort:
|
||||
|
||||
```json
|
||||
{ "status": "ok", "timestamp": "2025-11-25T12:00:00.000Z", "uptime": 123.45 }
|
||||
```
|
||||
|
||||
### 11.2 Website öffnen
|
||||
|
||||
Öffne `https://ulo.ad` im Browser.
|
||||
|
||||
---
|
||||
|
||||
## Automatische Deployments
|
||||
|
||||
### Webhook (Standard)
|
||||
|
||||
Coolify erstellt automatisch einen GitHub Webhook. Bei jedem Push auf `main` wird automatisch deployed.
|
||||
|
||||
### Manuelles Deployment
|
||||
|
||||
In Coolify: Application → **Redeploy**
|
||||
|
||||
---
|
||||
|
||||
## Wartung & Monitoring
|
||||
|
||||
### Logs anzeigen
|
||||
|
||||
**In Coolify:**
|
||||
Application → **Logs**
|
||||
|
||||
**Via SSH:**
|
||||
|
||||
```bash
|
||||
docker logs -f $(docker ps -qf "name=uload")
|
||||
```
|
||||
|
||||
### Container neustarten
|
||||
|
||||
In Coolify: Application → **Restart**
|
||||
|
||||
### Datenbank Backup
|
||||
|
||||
```bash
|
||||
# Manuelles Backup
|
||||
docker exec uload-postgres pg_dump -U uload uload > backup_$(date +%Y%m%d).sql
|
||||
|
||||
# Backup wiederherstellen
|
||||
cat backup_20251125.sql | docker exec -i uload-postgres psql -U uload uload
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build schlägt fehl
|
||||
|
||||
| Problem | Lösung |
|
||||
| -------------------------- | ---------------------------------------- |
|
||||
| "Cannot find package" | Prüfe Base Directory (muss `/` sein) |
|
||||
| "pnpm-lock.yaml not found" | Prüfe dass pnpm-lock.yaml im Repo ist |
|
||||
| Timeout beim Build | Erhöhe Build-Timeout in Coolify Settings |
|
||||
|
||||
### Container startet nicht
|
||||
|
||||
| Problem | Lösung |
|
||||
| ---------------------------- | ----------------------------------------- |
|
||||
| "Missing API key" | Prüfe RESEND_API_KEY Environment Variable |
|
||||
| "Cannot connect to database" | Prüfe DATABASE_URL (Internal URL!) |
|
||||
| Port already in use | Prüfe ob alter Container noch läuft |
|
||||
|
||||
### SSL-Zertifikat Fehler
|
||||
|
||||
1. Prüfe DNS-Einträge (A-Record auf Server-IP)
|
||||
2. Warte 5-10 Minuten
|
||||
3. In Coolify: Domain löschen und neu hinzufügen
|
||||
4. Prüfe ob Port 80 erreichbar ist (Firewall)
|
||||
|
||||
### Datenbank-Verbindung fehlgeschlagen
|
||||
|
||||
1. Prüfe ob PostgreSQL-Container läuft
|
||||
2. Verwende **Internal URL** (nicht External!)
|
||||
3. Teste Verbindung:
|
||||
```bash
|
||||
docker exec -it uload-postgres psql -U uload -d uload -c "SELECT 1"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checkliste Production-Ready
|
||||
|
||||
- [ ] Hetzner VPS erstellt und SSH funktioniert
|
||||
- [ ] Coolify installiert und Admin-Account erstellt
|
||||
- [ ] PostgreSQL läuft und CONNECTION_STRING notiert
|
||||
- [ ] Redis läuft (optional)
|
||||
- [ ] GitHub Repository verbunden
|
||||
- [ ] Application mit korrektem Dockerfile-Pfad erstellt
|
||||
- [ ] Alle Environment Variables gesetzt
|
||||
- [ ] AUTH_SECRET generiert (min. 32 Zeichen)
|
||||
- [ ] DNS A-Records konfiguriert
|
||||
- [ ] Domain in Coolify hinzugefügt
|
||||
- [ ] SSL-Zertifikat aktiv
|
||||
- [ ] Erster Deploy erfolgreich
|
||||
- [ ] Datenbank-Migration ausgeführt
|
||||
- [ ] Health-Check funktioniert (`/api/health`)
|
||||
- [ ] Website erreichbar
|
||||
|
||||
---
|
||||
|
||||
## Dateien im Repository
|
||||
|
||||
| Datei | Beschreibung |
|
||||
| ---------------------------------- | ------------------------ |
|
||||
| `uload/Dockerfile` | Multi-Stage Docker Build |
|
||||
| `uload/docker-compose.yml` | Lokale Entwicklung |
|
||||
| `uload/docker-compose.coolify.yml` | Coolify Deployment |
|
||||
| `uload/docker-compose.prod.yml` | Standalone Production |
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
Bei Problemen:
|
||||
|
||||
1. Coolify Logs prüfen
|
||||
2. Container Logs prüfen (`docker logs`)
|
||||
3. GitHub Issues: https://github.com/anthropics/claude-code/issues
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# @manacore/shared-storage
|
||||
|
||||
S3-compatible object storage client for the Manacore monorepo. Uses MinIO for local development and Hetzner Object Storage in production.
|
||||
S3-compatible object storage client for the Manacore monorepo. Uses MinIO for S3-compatible storage.
|
||||
|
||||
## Setup
|
||||
|
||||
|
|
@ -208,7 +208,7 @@ This creates the following Prometheus metrics:
|
|||
|
||||
```env
|
||||
# Required
|
||||
S3_ENDPOINT=http://localhost:9000 # MinIO local / Hetzner production
|
||||
S3_ENDPOINT=http://localhost:9000 # MinIO
|
||||
S3_REGION=us-east-1
|
||||
S3_ACCESS_KEY=minioadmin
|
||||
S3_SECRET_KEY=minioadmin
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "@manacore/shared-storage",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"description": "S3-compatible object storage client for Manacore monorepo (MinIO local, Hetzner production)",
|
||||
"description": "S3-compatible object storage client for Manacore monorepo (MinIO)",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
|
|
|
|||
|
|
@ -46,9 +46,7 @@ function constrainStream(stream: ReadableStream, maxBytes: number): ReadableStre
|
|||
bytesRead += value.byteLength;
|
||||
if (bytesRead > maxBytes) {
|
||||
controller.error(
|
||||
new Error(
|
||||
`Stream size ${bytesRead} bytes exceeds maximum allowed ${maxBytes} bytes`
|
||||
)
|
||||
new Error(`Stream size ${bytesRead} bytes exceeds maximum allowed ${maxBytes} bytes`)
|
||||
);
|
||||
reader.cancel();
|
||||
return;
|
||||
|
|
@ -62,7 +60,7 @@ function constrainStream(stream: ReadableStream, maxBytes: number): ReadableStre
|
|||
}
|
||||
|
||||
/**
|
||||
* S3-compatible storage client for MinIO (local) and Hetzner Object Storage (production)
|
||||
* S3-compatible storage client for MinIO
|
||||
*/
|
||||
export class StorageClient {
|
||||
private client: S3Client;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
export interface StorageConfig {
|
||||
/** S3 endpoint URL (e.g., http://localhost:9000 for MinIO) */
|
||||
endpoint: string;
|
||||
/** S3 region (e.g., 'us-east-1' or 'fsn1' for Hetzner) */
|
||||
/** S3 region (e.g., 'us-east-1') */
|
||||
region: string;
|
||||
/** Access key ID */
|
||||
accessKeyId: string;
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Get SSH Private Key Content for GitHub Secret
|
||||
|
||||
echo "================================================"
|
||||
echo " SSH PRIVATE KEY FOR STAGING_SSH_KEY"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo "Copy the ENTIRE output below (including BEGIN and END lines):"
|
||||
echo ""
|
||||
echo "================================================"
|
||||
|
||||
cat ~/.ssh/hetzner_deploy_key
|
||||
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo "This is the value for: STAGING_SSH_KEY"
|
||||
echo ""
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Script to remove Coolify references and replace with Docker Compose equivalents
|
||||
# Usage: ./scripts/remove-coolify-references.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "Starting Coolify reference removal..."
|
||||
|
||||
# Function to replace text in files
|
||||
replace_in_file() {
|
||||
local file=$1
|
||||
local search=$2
|
||||
local replace=$3
|
||||
|
||||
if [ -f "$file" ]; then
|
||||
sed -i.bak "s|$search|$replace|g" "$file" && rm "${file}.bak"
|
||||
echo " ✓ Updated: $file"
|
||||
fi
|
||||
}
|
||||
|
||||
# Common replacements across all files
|
||||
echo "Applying common replacements..."
|
||||
|
||||
# Platform references
|
||||
find . -type f \( -name "*.md" -o -name "*.yml" -o -name "*.yaml" \) \
|
||||
-not -path "*/node_modules/*" \
|
||||
-not -path "*/.git/*" \
|
||||
-not -path "*/archive/*" \
|
||||
-exec sed -i.bak 's/Coolify + Hetzner/Docker Compose + Hetzner VPS/g' {} \; \
|
||||
-exec sed -i.bak 's/Coolify (open-source PaaS)/Docker Compose orchestration/g' {} \; \
|
||||
-exec sed -i.bak 's/Coolify server/Hetzner VPS/g' {} \; \
|
||||
-exec sed -i.bak 's/Coolify Platform/Docker Compose/g' {} \; \
|
||||
-exec sed -i.bak 's/Coolify managed/Docker Compose managed/g' {} \; \
|
||||
-exec sed -i.bak 's/Install Coolify/Set up Docker Compose/g' {} \; \
|
||||
-exec sed -i.bak 's/Coolify UI/Docker Compose configuration/g' {} \; \
|
||||
-exec sed -i.bak 's/Coolify deployment/Docker Compose deployment/g' {} \; \
|
||||
-exec sed -i.bak 's/Platform: Coolify/Platform: Docker Compose/g' {} \; \
|
||||
-exec sed -i.bak 's/Platform\*\*: Coolify/Platform**: Docker Compose/g' {} \;
|
||||
|
||||
# Clean up backup files
|
||||
find . -name "*.bak" -type f -delete
|
||||
|
||||
echo "✓ Common replacements complete"
|
||||
|
||||
# Specific file updates
|
||||
echo "Updating specific files..."
|
||||
|
||||
# Update TODO.md to remove Coolify installation steps
|
||||
if [ -f "cicd/TODO.md" ]; then
|
||||
echo " - Updating cicd/TODO.md..."
|
||||
# Remove the "Install Coolify" section header and related tasks
|
||||
sed -i.bak '/### 1.3 Install Coolify/,/\*\*\*\*/d' cicd/TODO.md
|
||||
sed -i.bak 's/Provision production server/Set up production server/g' cicd/TODO.md
|
||||
sed -i.bak 's/Install Coolify on production server/Set up Docker Compose on production server/g' cicd/TODO.md
|
||||
rm cicd/TODO.md.bak
|
||||
fi
|
||||
|
||||
# Update PLAN.md
|
||||
if [ -f "cicd/PLAN.md" ]; then
|
||||
echo " - Updating cicd/PLAN.md..."
|
||||
sed -i.bak 's/Coolify with auto-scaling/Docker Compose with manual scaling/g' cicd/PLAN.md
|
||||
sed -i.bak '/Coolify Documentation/d' cicd/PLAN.md
|
||||
sed -i.bak '/GitHub Repository.*coolify/d' cicd/PLAN.md
|
||||
rm cicd/PLAN.md.bak
|
||||
fi
|
||||
|
||||
# Clean up remaining backup files
|
||||
find . -name "*.bak" -type f -delete
|
||||
|
||||
echo "✅ Coolify reference removal complete!"
|
||||
echo ""
|
||||
echo "Files modified. Please review changes with: git diff"
|
||||
|
|
@ -9,7 +9,7 @@ Matrix Project Doc Bot collects photos, voice notes, and text for projects and g
|
|||
- **Framework**: NestJS 10
|
||||
- **Matrix**: matrix-bot-sdk
|
||||
- **Database**: Drizzle ORM + PostgreSQL
|
||||
- **Storage**: S3 (MinIO locally, Hetzner in production)
|
||||
- **Storage**: S3 (MinIO)
|
||||
- **AI**: OpenAI (Whisper for transcription, GPT-4o-mini for generation)
|
||||
|
||||
## Commands
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue