Files
tibi-svelte-starter/.agents/skills/deployment/SKILL.md
T
apairon 4020ad62c5 feat: enhance medialib image handling and add asset URL resolution
- Implemented `resolveApiAssetUrl` function to normalize asset URLs based on API base.
- Updated `MedialibImage` component to utilize new asset URL resolution and added support for alt text and class properties.
- Enhanced image loading behavior with improved width measurement and focal point handling.
- Added placeholder image handling and improved accessibility with alt text.
- Introduced new test script for auditing broken links in skill documentation.
- Expanded seeded test content to include medialib entries and updated related tests for pagebuilder previews.
- Improved global setup and teardown logging for clarity on seeded content management.
2026-05-17 00:52:41 +00:00

193 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: deployment
description: Production deployment setup for tibi-projects Basispanel subdomain, .env, CI-Pipeline, Makefile. Use when deploying a new project to production or setting up a staging environment.
---
# Deployment
## Überblick
Ein tibi-Projekt wird per Gitea Actions CI gebaut und via rsync auf den Produktionsserver (dock4) deployed. Davor muss die Subdomain im Basispanel angelegt und der Kunde korrekt konfiguriert sein.
## 1. Basispanel Subdomain anlegen
### Kunde prüfen
```bash
# Domain des Kunden suchen
mcp_call(server="basispanel", tool="bp_list_domains", args={"search": "<kunde>"})
# → liefert Customer-ID, Domain-ID, Company, Username
```
### Subdomain anlegen
```bash
# 1. Config holen (verfügbare Webserver + Storages sehen)
mcp_call(server="basispanel", tool="bp_get_config")
# 2. Subdomain erstellen (ohne Webserver)
mcp_call(server="basispanel", tool="bp_create_subdomain", args={
"domainId": <domain-id>,
"name": "<subdomain>", # oder leer für bare domain
})
# 3. Löschen + neu mit Webserver (wenn Update nicht klappt)
mcp_call(server="basispanel", tool="bp_delete_subdomain", args={"id": <subdomain-id>})
mcp_call(server="basispanel", tool="bp_create_subdomain", args={
"domainId": <domain-id>,
"name": "<subdomain>",
"webserverKey": "dock4_lamp2",
"webserverStorage": "dock4_webroots2",
"webserverSettings": {
"redirectType": "docroot",
"docroot": "/<subdomain>.<domain>/frontend",
"gitbaseRepository": "<org>/<repo>",
"deployRoot": "./..",
"defaultAlias": "wwwAlias",
"defaultSubdomain": "defaultSubdomain",
"wwwRedirect": "wwwRedirect",
"php": "phpDisabled", # tibi-SPA kein PHP
"https": "noHttps", # erstmal aus, später aktivieren
"certbot": "noCertbot",
},
})
```
Wichtige Keys (aus `bp_get_config`):
| Server | Key | Storage |
|--------|-----|---------|
| dock4 | `dock4_lamp2` | `dock4_webroots2` |
| dock1 | `dock1_...` | `dock1_webroots...` |
### Status prüfen
```bash
mcp_call(server="basispanel", tool="bp_get_subdomain_status", args={"id": <subdomain-id>})
```
Achtung: Health-Check zeigt DNS-Warnungen (externe Nameserver) das ist normal solange der Kunde sein DNS selbst verwaltet.
## 2. `.env` konfigurieren
```env
# Basis
PROJECT_NAME=<project>
TIBI_PREFIX=tibi
TIBI_NAMESPACE=<project>
# RSYNC für Deploy
RSYNC_HOST=ftp1.webmakers.de
RSYNC_PORT=22223
PRODUCTION_RSYNC_UID=100<customer-id>00 # z.B. 10051300
PRODUCTION_RSYNC_GID=33
# Production Server
PRODUCTION_SERVER=dock4.basehosts.de
PRODUCTION_TIBI_PREFIX=tibi
PRODUCTION_PATH=/webroots2/customers/<customer-id>/htdocs
# Staging
STAGING_PATH=/staging/<org>/<project>/dev
# URLs
LIVE_URL=http://<subdomain>.<domain>.dock4.basispanel.de # Preview-URL
STAGING_URL=https://dev-<project>.staging.testversion.online
CODING_URL=https://<project>.code.testversion.online
```
## 3. CI-Pipeline (`.gitea/workflows/deploy.yml`)
```yaml
name: deploy to production
on: "push"
jobs:
deploy:
steps:
- checkout + git fetch --tags
- node 22 + yarn install
- yarn validate
- ./scripts/ci-modify-config.sh # injiziert LIVE_URL, release, preview
- yarn build # frontend
- yarn build:server # SSR
- sourcemaps → sentry
- if dev-branch: ./scripts/ci-staging.sh
- if master-branch: ./scripts/ci-deploy.sh
```
**Wichtig:** Das aktuelle Workflow-File führt `yarn validate`, `yarn build` und `yarn build:server` im CI aus. Wenn `validate` dort scheitert, behebe den eigentlichen Typ- oder Pfadfehler statt den Schritt stillschweigend zu entfernen.
## 4. Deploy-Skripte
### `scripts/ci-deploy.sh` (Production)
- Liest `.env` und `api/config.yml.env`
- rsynct `frontend/`, `api/`, `media/` via SSH zu `RSYNC_HOST`
- deshalb muessen Collection-Dateiuploads auf den Repo-Root `media/` zeigen, typischerweise via `uploadPath: ../media/<collection>` in `api/collections/*.yml`
- `api/media` ist in diesem Setup nicht der persistente Deploy-Zielpfad fuer Uploads
- Nutzt `RSYNC_USER` + `RSYNC_PASS` (aus Gitea Secrets)
- Auf master: excludiert `src/` und `*.map`
- Reloadt den projektlokalen Proxy-Endpunkt via `LIVE_URL/api/_/admin/reload` mit `Authorization: Bearer ${ADMIN_TOKEN}`
- Cleared SSR cache via `LIVE_URL/api/ssr?clear=1`
### `scripts/ci-staging.sh` (Dev/Staging)
- rsynct `api/`, `frontend/dist`, und `frontend/assets` nach `/data/${{ github.repository }}/${{ github.ref_name }}`
- Startet `docker-compose-staging.yml`
- Reloadt den projektlokalen Proxy-Endpunkt via `STAGING_URL/api/_/admin/reload` mit `Authorization: Bearer ${ADMIN_TOKEN}`
### `scripts/ci-modify-config.sh`
- Injiziert `LIVE_URL` als `originURL` in `api/hooks/config-client.js`
- Injiziert `LIVE_URL` als `PREVIEW_URL` in `api/config.yml.env`
- Setzt `release` + `buildTime` für Sentry
- Kopiert `frontend/spa.html``api/templates/spa.html` (SSR-Template)
- Ersetzt `__TIMESTAMP__` in spa.html (Cache-Busting)
## 5. Makefile
Wichtige Targets:
```makefile
# Media von Production syncen
media-sync-master-to-local:
rsync -v -e "ssh ... -l $(PRODUCTION_RSYNC_UID),$(PRODUCTION_RSYNC_GID),$(PRODUCTION_PATH)/media" \
-az $(RSYNC_HOST):/ media/
# MongoDB von Production syncen (via Chisel-Tunnel)
mongo-sync-master-to-local:
chisel client --auth coder:$$PASSWORD http://$(PRODUCTION_SERVER):10987 27017:mongo:27017 &
mongodump ... | mongorestore ...
```
## 6. DNS
Der Kunde verwaltet sein DNS selbst (externe Nameserver). Für die Subdomain muss ein A-Record gesetzt werden:
```
<subdomain>.<domain> IN A 45.129.180.102 (IP von dock4)
```
Die Preview-URL `http://<subdomain>.<domain>.dock4.basispanel.de` funktioniert ohne DNS (wird von Basispanel intern aufgelöst).
## 7. HTTPS nachträglich aktivieren
Sobald das Projekt live geht:
1. Im Basispanel Subdomain updaten:
- `https`: `"https"` (statt `"noHttps"`)
- `certbot`: `"certbot"` (automatisches Letsencrypt)
- `httpsRedirect`: `"httpsRedirect"` (HTTP→HTTPS)
2. `.env`: `LIVE_URL` auf `https://www.<domain>` ändern
3. `api/hooks/config-client.js`: `originURL` entsprechend setzen (wird von CI überschrieben)
## 8. Typische Fehler
| Problem | Ursache | Fix |
| ------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------ |
| `invalid webserverKey: dock4` | Falscher Key | Mit `bp_get_config` prüfen → `dock4_lamp2` |
| `subdomain exists` | Doppelt angelegt | Mit `bp_delete_subdomain` löschen, neu anlegen |
| `yarn validate` scheitert in CI | Typen/Submodule/Pfade nicht sauber eingecheckt | Checkout-, Submodule- und Include-Pfade korrigieren; `validate` im Workflow belassen |
| Rsync "Permission denied" | Falscher RSYNC_USER | In Gitea Secrets prüfen |
| 404 auf Subdomain | DNS nicht gesetzt | A-Record beim Kunden-DNS-Provider eintragen |