feat(merchant): extract merchant portal as first-class frontend with auth, Tailwind fixes, and Gitea CI
Some checks failed
Some checks failed
- Extract login/dashboard from billing module into core (matching admin pattern) - Add merchant auth API with path-isolated cookies (path=/merchants) - Add merchant base layout with sidebar/header partials and Alpine.js init - Add frontend detection and login redirect for MERCHANT type - Wire merchant token in shared api-client.js (get/clear) - Migrate billing templates to merchant base with dark mode support - Fix Tailwind: rename shop→storefront in sources and config - DRY Makefile tailwind targets with TAILWIND_FRONTENDS loop - Rebuild all Tailwind outputs (production minified) - Add Gitea Actions CI workflow (ruff, pytest, architecture, docs) - Add Gitea deployment documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
302
docs/deployment/gitea.md
Normal file
302
docs/deployment/gitea.md
Normal file
@@ -0,0 +1,302 @@
|
||||
# Gitea CI/CD Deployment Guide
|
||||
|
||||
This document describes how to **self-host Gitea** on an external server and migrate CI/CD from GitLab to **Gitea Actions** (GitHub Actions-compatible).
|
||||
|
||||
---
|
||||
|
||||
## Why Gitea?
|
||||
|
||||
- Lightweight, self-hosted Git forge (single binary or Docker image)
|
||||
- Built-in CI/CD via **Gitea Actions** (GitHub Actions-compatible YAML)
|
||||
- Built-in migration tool imports repos, issues, and PRs from GitLab
|
||||
- Low resource usage compared to GitLab
|
||||
|
||||
---
|
||||
|
||||
## 1. Server Prerequisites
|
||||
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt update && sudo apt install -y docker.io docker-compose-plugin
|
||||
sudo systemctl enable --now docker
|
||||
sudo usermod -aG docker $USER # log out/in after this
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Gitea Server Setup (Docker Compose)
|
||||
|
||||
Create a directory on your server:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/gitea && cd ~/gitea
|
||||
```
|
||||
|
||||
Create `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: always
|
||||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
- GITEA__database__DB_TYPE=postgres
|
||||
- GITEA__database__HOST=gitea-db:5432
|
||||
- GITEA__database__NAME=gitea
|
||||
- GITEA__database__USER=gitea
|
||||
- GITEA__database__PASSWD=<CHANGE_ME>
|
||||
- GITEA__server__ROOT_URL=https://git.yourdomain.com/
|
||||
- GITEA__server__SSH_DOMAIN=git.yourdomain.com
|
||||
- GITEA__server__DOMAIN=git.yourdomain.com
|
||||
- GITEA__actions__ENABLED=true
|
||||
volumes:
|
||||
- gitea-data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "3000:3000" # Web UI
|
||||
- "2222:22" # SSH (Git over SSH)
|
||||
depends_on:
|
||||
gitea-db:
|
||||
condition: service_healthy
|
||||
|
||||
gitea-db:
|
||||
image: postgres:15
|
||||
container_name: gitea-db
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_DB: gitea
|
||||
POSTGRES_USER: gitea
|
||||
POSTGRES_PASSWORD: <CHANGE_ME>
|
||||
volumes:
|
||||
- gitea-db-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U gitea"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# Gitea Actions runner — executes CI workflows
|
||||
gitea-runner:
|
||||
image: gitea/act_runner:latest
|
||||
container_name: gitea-runner
|
||||
restart: always
|
||||
environment:
|
||||
GITEA_INSTANCE_URL: http://gitea:3000
|
||||
GITEA_RUNNER_REGISTRATION_TOKEN: <RUNNER_TOKEN>
|
||||
GITEA_RUNNER_NAME: default-runner
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- gitea-runner-data:/data
|
||||
depends_on:
|
||||
- gitea
|
||||
|
||||
volumes:
|
||||
gitea-data:
|
||||
gitea-db-data:
|
||||
gitea-runner-data:
|
||||
```
|
||||
|
||||
!!! warning "Replace placeholders"
|
||||
Replace `<CHANGE_ME>` with a strong database password and `<RUNNER_TOKEN>` with the token from step 4.
|
||||
|
||||
Start Gitea and the database first:
|
||||
|
||||
```bash
|
||||
docker compose up -d gitea gitea-db
|
||||
```
|
||||
|
||||
Visit `http://your-server-ip:3000` and complete the initial setup wizard.
|
||||
|
||||
---
|
||||
|
||||
## 3. Reverse Proxy with HTTPS (Nginx + Let's Encrypt)
|
||||
|
||||
```bash
|
||||
sudo apt install -y nginx certbot python3-certbot-nginx
|
||||
```
|
||||
|
||||
Create `/etc/nginx/sites-available/gitea`:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
server_name git.yourdomain.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
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;
|
||||
client_max_body_size 100M;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Enable and get a certificate:
|
||||
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/
|
||||
sudo certbot --nginx -d git.yourdomain.com
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Enable Actions & Register the Runner
|
||||
|
||||
1. Go to **Site Administration > Runners** in the Gitea web UI.
|
||||
2. Click **Create new Runner** and copy the registration token.
|
||||
3. Paste the token into `docker-compose.yml` as `GITEA_RUNNER_REGISTRATION_TOKEN`.
|
||||
4. Start the runner:
|
||||
|
||||
```bash
|
||||
docker compose up -d gitea-runner
|
||||
```
|
||||
|
||||
Verify the runner appears as **Online** in the admin panel.
|
||||
|
||||
---
|
||||
|
||||
## 5. Migrate Your Repository
|
||||
|
||||
### Option A: Git push (code only)
|
||||
|
||||
```bash
|
||||
# On your local machine
|
||||
cd /path/to/letzshop-product-import
|
||||
git remote add gitea ssh://git@git.yourdomain.com:2222/your-username/letzshop-product-import.git
|
||||
git push gitea --all
|
||||
git push gitea --tags
|
||||
```
|
||||
|
||||
### Option B: Gitea built-in migration (code + issues + PRs)
|
||||
|
||||
1. In Gitea, click **+** > **New Migration**.
|
||||
2. Select **GitLab** as the source.
|
||||
3. Enter your GitLab URL and a Personal Access Token.
|
||||
4. Gitea will import the repository, issues, labels, milestones, and merge requests.
|
||||
|
||||
---
|
||||
|
||||
## 6. CI/CD — GitLab vs Gitea Actions
|
||||
|
||||
The workflow file lives in `.gitea/workflows/ci.yml` (already created in this repository).
|
||||
|
||||
| GitLab CI (`.gitlab-ci.yml`) | Gitea Actions (`.gitea/workflows/ci.yml`) |
|
||||
|------------------------------|-------------------------------------------|
|
||||
| `stages:` + `stage:` per job | Jobs run in parallel; use `needs:` for ordering |
|
||||
| `services:` (top-level on job) | `services:` nested under each job with `options:` |
|
||||
| `allow_failure: true` | `continue-on-error: true` |
|
||||
| `rules: - if:` | `on:` triggers + `if:` conditionals per job |
|
||||
| `artifacts: paths:` | `actions/upload-artifact@v4` |
|
||||
| `cache: paths:` | `actions/cache@v4` |
|
||||
| `coverage: '/regex/'` | Use coverage action or parse in step |
|
||||
| CI/CD Variables (UI) | Repository **Settings > Secrets** |
|
||||
|
||||
---
|
||||
|
||||
## 7. CI/CD Secrets
|
||||
|
||||
Configure these in your Gitea repository under **Settings > Actions > Secrets**:
|
||||
|
||||
| Secret | Description | Used by |
|
||||
|--------|-------------|---------|
|
||||
| `SSH_PRIVATE_KEY` | Private key for deployment server | Deploy job (if added) |
|
||||
| `SERVER_HOST` | Production server IP/hostname | Deploy job |
|
||||
| `SERVER_USER` | SSH user on production server | Deploy job |
|
||||
| `SERVER_PATH` | App directory on server | Deploy job |
|
||||
|
||||
---
|
||||
|
||||
## 8. Pipeline Overview
|
||||
|
||||
The CI pipeline (`.gitea/workflows/ci.yml`) runs:
|
||||
|
||||
```
|
||||
push/PR to master
|
||||
├── ruff (lint)
|
||||
├── pytest (tests + PostgreSQL service)
|
||||
├── architecture (architecture validation)
|
||||
├── dependency-scanning (pip-audit, non-blocking)
|
||||
├── audit (custom audit, non-blocking)
|
||||
└── docs (mkdocs build, master-only, after lint+test pass)
|
||||
```
|
||||
|
||||
All jobs run in parallel except `docs`, which waits for `ruff`, `pytest`, and `architecture` to pass.
|
||||
|
||||
---
|
||||
|
||||
## 9. Adding a Deploy Job (Optional)
|
||||
|
||||
To add automated deployment via SSH (similar to the GitLab deploy stage), add this job to `.gitea/workflows/ci.yml`:
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
needs: [ruff, pytest, architecture]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Deploy via SSH
|
||||
uses: appleboy/ssh-action@v1
|
||||
with:
|
||||
host: ${{ secrets.SERVER_HOST }}
|
||||
username: ${{ secrets.SERVER_USER }}
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
script: |
|
||||
cd ${{ secrets.SERVER_PATH }}
|
||||
git pull origin master
|
||||
source .venv/bin/activate
|
||||
uv sync --frozen
|
||||
python -m alembic upgrade head
|
||||
sudo systemctl restart wizamart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Firewall Configuration
|
||||
|
||||
```bash
|
||||
sudo ufw allow OpenSSH
|
||||
sudo ufw allow 'Nginx Full'
|
||||
sudo ufw enable
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Maintenance
|
||||
|
||||
```bash
|
||||
# View Gitea logs
|
||||
docker compose -f ~/gitea/docker-compose.yml logs -f gitea
|
||||
|
||||
# View runner logs
|
||||
docker compose -f ~/gitea/docker-compose.yml logs -f gitea-runner
|
||||
|
||||
# Update Gitea
|
||||
cd ~/gitea
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
|
||||
# Backup Gitea data
|
||||
docker run --rm -v gitea-data:/data -v $(pwd):/backup alpine \
|
||||
tar czf /backup/gitea-backup-$(date +%Y%m%d).tar.gz /data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Removing GitLab (After Migration)
|
||||
|
||||
Once you have verified everything works on Gitea:
|
||||
|
||||
1. Update your local git remote:
|
||||
```bash
|
||||
git remote set-url origin ssh://git@git.yourdomain.com:2222/your-username/letzshop-product-import.git
|
||||
```
|
||||
2. The `.gitlab-ci.yml` file can be removed from the repository.
|
||||
3. Archive or delete the GitLab project.
|
||||
Reference in New Issue
Block a user