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>
This commit is contained in:
@@ -0,0 +1,328 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user