Files
tatlock-ui/docs/DEPLOYMENT.md
T
jpmschweitzerandClaude Opus 4.5 0c3239f4b0 docs: add Phase 0 documentation
- docs/ARCHITECTURE.md - Clean Architecture patterns and conventions
- docs/API_INTEGRATION.md - Core API and Tatlock API endpoints
- docs/DEPLOYMENT.md - Docker, NPM, Portainer setup
- docs/DATAGRID.md - DataGrid component specification
- docs/THEMING.md - Material 3 theming guide

Also update seed color to teal for consistency.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 16:26:44 +01:00

329 lines
6.4 KiB
Markdown

# Deployment Guide
This document covers deploying Tatlock UI to the Tower of Joy infrastructure.
## Overview
```
Internet → NPM (home.schweitz.net:443) → tatlock-ui container (port 8092) → Flutter web
```
## Web Build
### Local Build
```bash
# Generate version info
dart run tool/generate_version.dart
# Build for web release
flutter build web --release
```
Build output: `build/web/`
### Build Optimizations
For production builds, consider:
```bash
flutter build web --release \
--dart-define=FLUTTER_WEB_USE_SKIA=true \
--tree-shake-icons
```
## Docker
### Dockerfile
```dockerfile
# Build stage
FROM ghcr.io/cirruslabs/flutter:stable AS build
WORKDIR /app
# Copy dependency files
COPY pubspec.* ./
RUN flutter pub get
# Copy source and build
COPY . .
RUN dart run tool/generate_version.dart
RUN flutter build web --release
# Production stage
FROM nginx:alpine
# Copy built web app
COPY --from=build /app/build/web /usr/share/nginx/html
# Copy nginx config (optional)
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```
### nginx.conf (Optional)
For SPA routing support:
```nginx
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# SPA routing - serve index.html for all routes
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Don't cache index.html
location = /index.html {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}
}
```
### Build Image Locally
```bash
docker build -t tatlock-ui:latest .
# Test locally
docker run -p 8092:80 tatlock-ui:latest
```
## Portainer Stack
### docker-compose.yml
```yaml
version: '3.8'
services:
tatlock-ui:
image: git.schweitz.net/jpmschweitzer/tatlock-ui:latest
container_name: tatlock-ui
restart: unless-stopped
ports:
- "8092:80"
networks:
- docker-dataplane
labels:
- "com.centurylinklabs.watchtower.enable=true"
networks:
docker-dataplane:
external: true
```
### Deploy to Portainer
1. Go to Portainer: https://portainer.schweitz.net
2. Navigate to Stacks → Add Stack
3. Name: `tatlock-ui`
4. Paste docker-compose.yml content
5. Deploy
## Nginx Proxy Manager
### Proxy Host Configuration
| Setting | Value |
|---------|-------|
| Domain | `home.schweitz.net` |
| Scheme | `http` |
| Forward Hostname | `tatlock-ui` (container name) |
| Forward Port | `80` |
### SSL
| Setting | Value |
|---------|-------|
| SSL Certificate | Let's Encrypt |
| Force SSL | Yes |
| HTTP/2 | Yes |
| HSTS | Yes |
### Advanced (Custom Nginx)
```nginx
# WebSocket support (if needed for future features)
location /ws {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
```
## CI/CD Pipeline
### Gitea Actions Workflow
Create `.gitea/workflows/build.yml`:
```yaml
name: Build and Deploy
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
test:
runs-on: ubuntu-latest
container:
image: ghcr.io/cirruslabs/flutter:stable
steps:
- uses: actions/checkout@v4
- name: Get dependencies
run: flutter pub get
- name: Generate version
run: dart run tool/generate_version.dart
- name: Analyze
run: flutter analyze
- name: Test
run: flutter test
build:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Gitea Registry
uses: docker/login-action@v3
with:
registry: git.schweitz.net
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: git.schweitz.net/jpmschweitzer/tatlock-ui:latest
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
steps:
- name: Trigger Watchtower
run: |
curl -X POST "http://watchtower:8080/v1/update" \
-H "Authorization: Bearer ${{ secrets.WATCHTOWER_TOKEN }}"
```
## Environment Configuration
### Runtime Configuration
For environment-specific settings, use compile-time defines:
```bash
flutter build web --release \
--dart-define=API_URL=https://api.schweitz.net \
--dart-define=AUTH_URL=https://auth.schweitz.net
```
Access in code:
```dart
class AppConfig {
static const apiUrl = String.fromEnvironment(
'API_URL',
defaultValue: 'https://api.schweitz.net',
);
static const authUrl = String.fromEnvironment(
'AUTH_URL',
defaultValue: 'https://auth.schweitz.net',
);
}
```
## Health Monitoring
### Container Health Check
Add to Dockerfile:
```dockerfile
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
```
### Uptime Monitoring
Add to your monitoring solution (Uptime Kuma, etc.):
- URL: `https://home.schweitz.net`
- Interval: 60s
- Expected status: 200
## Rollback
### Quick Rollback
If issues arise after deployment:
```bash
# In Portainer, update image tag to previous version
git.schweitz.net/jpmschweitzer/tatlock-ui:previous-tag
# Or via CLI
docker pull git.schweitz.net/jpmschweitzer/tatlock-ui:v0.1.0
docker stop tatlock-ui
docker rm tatlock-ui
docker run -d --name tatlock-ui -p 8092:80 git.schweitz.net/jpmschweitzer/tatlock-ui:v0.1.0
```
## Troubleshooting
### Container won't start
```bash
# Check logs
docker logs tatlock-ui
# Common issues:
# - Port 8092 already in use
# - Network not found (create docker-dataplane network)
```
### 502 Bad Gateway in NPM
1. Verify container is running: `docker ps | grep tatlock-ui`
2. Check container is on correct network
3. Verify port mapping in docker-compose
### Assets not loading
Check nginx is serving from correct path and CORS headers if loading from different domain.