Skip to content

S5 Client Cleanup Implementation Plan (Revised)

Date: 2025-11-23 Status: Implementation Plan (Revised) Author: Claude Code Complexity: Medium-high complexity migration with architectural benefits Risk Level: Medium

Executive Summary

This document provides a detailed implementation plan for converting the S5 Slidefactory repository from a monolithic codebase to a thin client that depends on the slidefactory-core package. This completes the repository separation strategy outlined in the November 2025 migration guides.

Important: S5 is Azure-only deployment. Docker setup has moved to eddy-slidefactory (Hetzner). S5 local development uses start.sh and start-worker.sh connected to Azure preview environment.

Current State: - S5 repository contains duplicate core code (app/, cli/, alembic/, tests/) - Core package exists at ../slidefactory-core with version 1.0.8 - S5 uses monolith-style imports (app.*) - No clear separation between core functionality and S5-specific branding/deployment - Contains Docker Compose setup (should be in eddy-slidefactory)

Target State: - S5 repository contains only branding, configuration, and Azure deployment files - S5 depends on slidefactory-core==1.0.8 via pyproject.toml - Core functionality provided by installed package - Clear separation of concerns: core logic vs. Azure client deployment - No Docker Compose (moved to eddy-slidefactory)

Benefits: - Single source of truth for core functionality - Easier maintenance and updates - Clear deployment boundaries - Consistent with repository separation architecture - Reduced code duplication


Assessment Summary

Current Repository State

✅ Verified: - Core package (slidefactory-core) exists at ../slidefactory-core with version 1.0.8 - Core has all application code under src/slidefactory/ with proper package structure - Core uses proper imports (slidefactory.app.*) - S5 branding files identified in static/img/branding/ and scattered locations

❌ Issues: - S5 repo still has duplicate code in app/, cli/, alembic/, static/, templates/ - S5 repo has old setup.py for CLI (should use core's package) - S5 repo has migration docs that belong in core or archive - S5 uses old monolith imports (app.*) - S5 repo has Docker Compose setup (belongs in eddy-slidefactory)

Key Differences

Aspect Core Package S5 Current S5 Target
Import Style slidefactory.app.* app.* Use core package
Package Structure src/slidefactory/ app/ at root No app code
Version 1.0.8 N/A Depends on core
CLI slidefactory command Local setup.py Use core's CLI
Distribution Python package Monolith Thin client
Local Dev N/A Docker Compose Azure preview connection
Deployment N/A Azure Container Apps Azure Container Apps

S5 Deployment Model

Azure-Only Architecture

S5 uses Azure Container Apps for both preview and production:

Preview Environment: - Push to preview branch → GitHub Actions → Azure Container Apps (preview) - Local development connects to preview environment (database, Redis, storage)

Production Environment: - Push to main branch → GitHub Actions → Azure Container Apps (production) - Only repository owner merges previewmain

Local Development: - No local Docker Compose - start.sh runs web server against Azure preview database - start-worker.sh runs Celery worker against Azure preview Redis/database - Configuration via .env pointing to Azure resources

Docker: - Docker Compose setup moved to eddy-slidefactory (Hetzner deployment) - S5 only uses Dockerfile for Azure Container Apps image build


Repository Structure Changes

Files to KEEP in S5 Repo

Configuration: - .env, .env.azure.* - S5 Azure environment configuration - .env.s5 - S5 environment template for Azure - .gitignore, .gitattributes - Git configuration - .github/workflows/ - Azure deployment workflows (updated)

S5-Specific Assets: - s5_branding/ - S5 branding files (created) - docs/ - S5-specific documentation (Azure deployment, S5 resources)

Deployment: - Dockerfile - Azure Container Apps deployment (updated to use core) - scripts/ - Azure deployment scripts (updated) - start-web-azure.sh - Azure Container Apps web startup - start-worker-azure.sh - Azure Container Apps worker startup - start.sh - Local web development (connects to Azure preview) - start-worker.sh - Local worker development (connects to Azure preview)

S5-Specific Azure Resources (Optional): - azure/ - Infrastructure as code, Gotenberg setup, LibreChat setup

Project Files: - README.md - S5-specific documentation (rewritten) - pyproject.toml - S5 client package definition - .claude/ - Claude Code project instructions - Git history and configuration

Files to REMOVE from S5 Repo

Core Application Code: - app/ - Entire FastAPI application (now in core) - cli/ - CLI tool (now in core package) - alembic/ - Database migrations (now in core) - alembic.ini - Migration configuration (now in core)

Core Assets: - static/ - Except S5 branding (moved to s5_branding/static/) - templates/ - Except S5 overrides (moved to s5_branding/templates/)

Core Testing: - tests/ - Core tests (now in core repo) - pytest.ini - Testing configuration (now in core) - .coverage, htmlcov/ - Coverage artifacts

Core Infrastructure: - init.sql, init_test.sql - Database initialization (now in core) - packages/ - N8N nodes package (now in core) - bootstrap-database.sh - Database setup script (now in core)

Docker Setup (Moved to Eddy): - docker-compose.yml - Moved to eddy-slidefactory - .env.local - Local Docker config (not used by S5)

Old Package Files: - setup.py - Old CLI setup (replaced by pyproject.toml) - s5_slidefactory_cli.egg-info/ - Old package metadata - requirements.txt, requirements-dev.txt - Replaced by pyproject.toml

Build Artifacts: - site/ - MkDocs build output (docs now in core) - mkdocs.yml - Documentation config (now in core) - test_workflow_engines.py - Core test file

Migration Documentation: - docs/reports/technical/2025-11-18_repository_separation_*.md - Archive these - docs/reports/technical/2025-11-20_core_*.md - Archive these - docs/reports/technical/2025-11-20_eddy_*.md - Archive these


New S5 Repository Structure

s5-slidefactory/
├── pyproject.toml                    # S5 package with core dependency
├── README.md                         # S5 Azure deployment documentation
├── .env.s5                          # S5 Azure environment template
├── .env, .env.azure.*               # S5 Azure configurations
├── s5_branding/                     # S5-specific branding
│   ├── __init__.py
│   ├── static/
│   │   ├── css/
│   │   │   └── s5-custom.css
│   │   └── img/
│   │       ├── sportfive_logo.png
│   │       ├── sportfive_large.png
│   │       ├── sportfive_small.png
│   │       ├── bannerlogo.png
│   │       ├── sf_logo_*.png
│   │       └── favicon.ico
│   └── templates/                   # S5-specific overrides (if needed)
├── .github/
│   └── workflows/
│       ├── preview.yml              # Azure preview deployment
│       └── production.yml           # Azure production deployment
├── scripts/
│   ├── start-web-azure.sh           # Azure Container Apps web startup
│   └── start-worker-azure.sh        # Azure Container Apps worker startup
├── azure/                           # Optional: S5-specific Azure resources
│   ├── gotenberg/                   # Gotenberg PDF service setup
│   └── librechat/                   # LibreChat AI chatbot setup
├── Dockerfile                       # Azure Container Apps image
├── start.sh                         # Local web dev (Azure preview)
├── start-worker.sh                  # Local worker dev (Azure preview)
├── docs/
│   ├── azure_deployment.md          # Azure deployment guide
│   ├── s5_resources.md              # S5-specific Azure resources
│   ├── archive/
│   │   └── migration/               # Archived migration docs
│   └── reports/technical/           # S5-specific technical reports
├── .claude/
│   └── CLAUDE.md                    # Updated project instructions
└── .gitignore

Implementation Plan - CLI Commands

PHASE 1: BACKUP & PREPARATION

# 1. Create backup of current state
git checkout -b backup-before-s5-cleanup-$(date +%Y%m%d)
git push origin backup-before-s5-cleanup-$(date +%Y%m%d)

# 2. Verify core package is available
ls -la ../slidefactory-core/src/slidefactory/
cat ../slidefactory-core/pyproject.toml | grep version

# 3. Create working branch for cleanup
git checkout preview
git pull origin preview
git checkout -b feature/s5-client-cleanup

PHASE 2: CREATE S5 BRANDING STRUCTURE

# 4. Create S5 branding directory structure
mkdir -p s5_branding/static/img
mkdir -p s5_branding/static/css
mkdir -p s5_branding/templates

# 5. Move S5-specific images to branding folder
mv static/img/branding/* s5_branding/static/img/
mv static/img/sf_logo_*.png s5_branding/static/img/
mv static/img/sportfive* s5_branding/static/img/

# 6. Create S5 custom CSS (if needed)
touch s5_branding/static/css/s5-custom.css

# 7. Create __init__.py for S5 branding package
cat > s5_branding/__init__.py << 'EOF'
"""S5 SportFive branding package for Slidefactory."""
__version__ = "1.0.0"
EOF

PHASE 3: CREATE S5 CLIENT CONFIGURATION

# 8. Create S5-specific pyproject.toml
cat > pyproject.toml << 'EOF'
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "s5-slidefactory"
version = "1.0.0"
description = "S5 SportFive Slidefactory - Azure Deployment Client"
requires-python = ">=3.11"
# Note: slidefactory-core installed separately from local path
# See installation instructions below
dependencies = []

[project.optional-dependencies]
azure = [
    "azure-storage-blob>=12.19.0",
    "azure-identity>=1.15.0",
    "msal>=1.26.0",
]

[tool.setuptools]
packages = ["s5_branding"]
EOF

# 9. Install slidefactory-core
# Option A: From local sibling repository (recommended for development)
pip install -e ../slidefactory-core

# Option B: Using GitHub CLI (easiest for non-dev setup)
# gh auth login  # Login once
# gh release download v1.0.8 --repo cgast/slidefactory-core --pattern "*.whl"
# pip install slidefactory_core-1.0.8-py3-none-any.whl
# rm slidefactory_core-1.0.8-py3-none-any.whl

# Option C: Using curl with GitHub PAT
# export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
# curl -L \
#   -H "Authorization: token ${GITHUB_TOKEN}" \
#   -H "Accept: application/octet-stream" \
#   https://api.github.com/repos/cgast/slidefactory-core/releases/download/v1.0.8/slidefactory_core-1.0.8-py3-none-any.whl \
#   -o slidefactory_core.whl && \
#   pip install slidefactory_core.whl && \
#   rm slidefactory_core.whl

# 10. Create S5-specific .env.s5 template (Azure configuration)
cat > .env.s5 << 'EOF'
# S5 SportFive Branding
CLIENT_NAME="SportFive Slidefactory"
CLIENT_LOGO="/s5_branding/static/img/sportfive_logo.png"
CLIENT_LOGO_LARGE="/s5_branding/static/img/sportfive_large.png"
CLIENT_PRIMARY_COLOR="#ee0000"

# S5 Deployment
DEPLOYMENT_PLATFORM="azure"
SERVER_URL="https://slidefactory.sportfive.com"

# Storage (Azure Blob Storage)
STORAGE_PROVIDER="azure"
AZURE_STORAGE_ACCOUNT_NAME="${AZURE_STORAGE_ACCOUNT_NAME}"
AZURE_STORAGE_ACCOUNT_KEY="${AZURE_STORAGE_ACCOUNT_KEY}"

# Auth (Azure AD)
AZURE_TENANT_ID="${AZURE_TENANT_ID}"
AZURE_CLIENT_ID="${AZURE_CLIENT_ID}"
AZURE_CLIENT_SECRET="${AZURE_CLIENT_SECRET}"
AZURE_REDIRECT_URI="${AZURE_REDIRECT_URI}"

# Database (Azure PostgreSQL)
DATABASE_URL="${DATABASE_URL}"

# Redis (Azure Cache for Redis)
REDIS_HOST="${REDIS_HOST}"
REDIS_PORT="${REDIS_PORT}"
REDIS_PASSWORD="${REDIS_PASSWORD}"
REDIS_SSL=true

# AI (Azure OpenAI / OpenAI)
OPENAI_API_KEY="${OPENAI_API_KEY}"
AZURE_OPENAI_API_KEY="${AZURE_OPENAI_API_KEY}"
AZURE_OPENAI_ENDPOINT="${AZURE_OPENAI_ENDPOINT}"

# S5-Specific Services (Optional)
GOTENBERG_URL="${GOTENBERG_URL}"  # S5 Gotenberg instance on Azure
LIBRECHAT_URL="${LIBRECHAT_URL}"  # S5 LibreChat instance on Azure
EOF

# 11. Update Dockerfile for Azure Container Apps
cat > Dockerfile << 'EOF'
FROM python:3.11-slim

WORKDIR /code

# Install system dependencies
RUN apt-get update && apt-get install -y \
    gcc \
    curl \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

# Install slidefactory-core from GitHub release
# Note: Use GitHub PAT for private repo access
ARG GITHUB_TOKEN
ARG CORE_VERSION=1.0.8
RUN curl -L \
    -H "Authorization: token ${GITHUB_TOKEN}" \
    -H "Accept: application/octet-stream" \
    https://api.github.com/repos/cgast/slidefactory-core/releases/download/v${CORE_VERSION}/slidefactory_core-${CORE_VERSION}-py3-none-any.whl \
    -o /tmp/slidefactory_core.whl && \
    pip install --no-cache-dir /tmp/slidefactory_core.whl && \
    rm /tmp/slidefactory_core.whl

# Copy S5 package files
COPY pyproject.toml /code/
COPY s5_branding/ /code/s5_branding/

# Install S5 package with Azure dependencies
RUN pip install --no-cache-dir -e ".[azure]"

# Copy S5 Azure deployment scripts
COPY scripts/ /code/scripts/
RUN chmod +x /code/scripts/*.sh

# Expose S5 branding as static files
RUN ln -s /code/s5_branding/static /code/static/s5_branding

# Expose port
EXPOSE 8000

# Use S5 Azure startup script
CMD ["/code/scripts/start-web-azure.sh"]
EOF

PHASE 4: UPDATE SCRIPTS FOR CORE PACKAGE

# 11. Update start-web-azure.sh (Azure Container Apps)
cat > scripts/start-web-azure.sh << 'EOF'
#!/bin/bash
set -e

echo "Starting S5 Slidefactory Web (Azure Container Apps deployment)..."

# Run migrations (from core package)
echo "Running database migrations..."
alembic upgrade head

# Initialize system if needed (from core package CLI)
echo "Initializing system..."
slidefactory init check || slidefactory init all

# Start uvicorn (core package's FastAPI app)
echo "Starting web server..."
exec uvicorn slidefactory.app.main:app --host 0.0.0.0 --port 8000
EOF
chmod +x scripts/start-web-azure.sh

# 12. Update start-worker-azure.sh (Azure Container Apps)
cat > scripts/start-worker-azure.sh << 'EOF'
#!/bin/bash
set -e

echo "Starting S5 Slidefactory Worker (Azure Container Apps deployment)..."

# Start Celery worker (from core package)
exec celery -A slidefactory.app.celery_app worker --loglevel=info --concurrency=2
EOF
chmod +x scripts/start-worker-azure.sh

# 13. Create start.sh for local development (connects to Azure preview)
cat > start.sh << 'EOF'
#!/bin/bash
# S5 Slidefactory local development web startup
# Connects to Azure preview environment (database, Redis, storage)

set -e

echo "Starting S5 Slidefactory web (local development)..."
echo "Connecting to Azure preview environment..."

# Note: Requires .env configured with Azure preview credentials
# - Database: Azure PostgreSQL preview instance
# - Redis: Azure Cache for Redis preview instance
# - Storage: Azure Blob Storage preview container

# Start uvicorn with reload (core package)
exec uvicorn slidefactory.app.main:app --host 0.0.0.0 --port 8080 --reload
EOF
chmod +x start.sh

# 14. Create start-worker.sh for local worker development
cat > start-worker.sh << 'EOF'
#!/bin/bash
# S5 Slidefactory local development worker startup
# Connects to Azure preview environment (Redis, database)

set -e

echo "Starting S5 Slidefactory worker (local development)..."
echo "Connecting to Azure preview environment..."

# Note: Requires .env configured with Azure preview credentials
# - Redis: Azure Cache for Redis preview instance (Celery broker)
# - Database: Azure PostgreSQL preview instance

# Start Celery worker with autoreload (core package)
exec celery -A slidefactory.app.celery_app worker --loglevel=info --concurrency=2 --autoreload
EOF
chmod +x start-worker.sh

PHASE 5: UPDATE DOCUMENTATION

# 15. Create S5-specific README
cat > README.md << 'EOF'
# S5 SportFive Slidefactory

SportFive-branded deployment of Slidefactory on Azure Container Apps.

## Overview

This repository contains the SportFive-specific configuration, branding, and Azure deployment setup for Slidefactory.

**Core Engine:** [slidefactory-core](https://github.com/cgast/slidefactory-core) v1.0.8

**Deployment:** Azure Container Apps (preview and production environments)

## Architecture

S5 is an **Azure-only deployment client**:
- Uses `slidefactory-core` package for all core functionality
- Contains only S5 branding, configuration, and Azure deployment files
- No local Docker setup (Docker moved to `eddy-slidefactory` for Hetzner)

## Local Development

S5 local development connects to **Azure preview environment** (no local services):

```bash
# Install slidefactory-core
# Option A: From local sibling repository (if you have the source)
pip install -e ../slidefactory-core

# Option B: Using GitHub CLI (easiest, recommended)
gh auth login  # Login once
gh release download v1.0.8 --repo cgast/slidefactory-core --pattern "*.whl"
pip install slidefactory_core-1.0.8-py3-none-any.whl
rm slidefactory_core-1.0.8-py3-none-any.whl

# Option C: Using curl with GitHub PAT
# export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
# curl -L \
#   -H "Authorization: token ${GITHUB_TOKEN}" \
#   -H "Accept: application/octet-stream" \
#   https://api.github.com/repos/cgast/slidefactory-core/releases/download/v1.0.8/slidefactory_core-1.0.8-py3-none-any.whl \
#   -o slidefactory_core.whl && \
#   pip install slidefactory_core.whl && \
#   rm slidefactory_core.whl

# Install S5 client with Azure dependencies
pip install -e ".[azure]"

# Configure environment for Azure preview
cp .env.azure.preview .env
# Edit .env with your Azure preview credentials:
#   - DATABASE_URL: Azure PostgreSQL preview
#   - REDIS_HOST/PORT/PASSWORD: Azure Cache for Redis preview
#   - AZURE_STORAGE_*: Azure Blob Storage preview
#   - AZURE_TENANT_ID/CLIENT_ID/etc.: Azure AD credentials

# Start web server (connects to Azure preview)
./start.sh

# In separate terminal, start worker
./start-worker.sh

Access: http://localhost:8080

Azure Deployment

Automatic deployment via GitHub Actions:

Preview Environment: - Push to preview branch → GitHub Actions → Azure Container Apps (preview) - Preview URL: https://slidefactory-preview.sportfive.com

Production Environment: - Push to main branch → GitHub Actions → Azure Container Apps (production) - Production URL: https://slidefactory.sportfive.com - Only repository owner merges preview → main

S5 Branding

S5 branding assets in s5_branding/static/: - Logo: SportFive red logo - Colors: Red (#ee0000) primary - Custom CSS: s5_branding/static/css/s5-custom.css

Branding is automatically included in Azure Container Apps deployment via Dockerfile.

S5-Specific Azure Resources

Beyond core Slidefactory infrastructure, S5 deployment includes:

Additional Services: - Gotenberg: PDF rendering service for presentation generation - LibreChat (optional): AI chatbot interface - Azure OpenAI: S5-specific AI endpoints

Configuration: See azure/ directory for infrastructure setup and deployment scripts.

Configuration

See .env.s5 for S5 Azure configuration template.

Azure Resources: - Container Apps: Web and Worker services - Storage: Azure Blob Storage - Database: Azure Database for PostgreSQL with pgvector - Redis: Azure Cache for Redis - Optional: Gotenberg, LibreChat

CLI Commands

All CLI commands are provided by the core package:

+++bash

System initialization

slidefactory init all

User management

slidefactory user list slidefactory user create-local user@example.com --name "John Doe"

API keys

slidefactory api-key create "My Key" --user-id 1

Presentations

slidefactory presentation generate --template-id 123 +++

Support

License

Proprietary - SportFive internal use only EOF

16. Archive migration docs

mkdir -p docs/archive/migration mv docs/reports/technical/2025-11-18_repository_separation_.md docs/archive/migration/ 2>/dev/null || true mv docs/reports/technical/2025-11-20_core_.md docs/archive/migration/ 2>/dev/null || true mv docs/reports/technical/2025-11-20_eddy_*.md docs/archive/migration/ 2>/dev/null || true

### PHASE 6: REMOVE CORE CODE AND DOCKER SETUP

```bash
# 17. Remove core application code
rm -rf app/
rm -rf cli/
rm -rf alembic/
rm -f alembic.ini

# 18. Remove core static/templates
rm -rf static/css/
rm -rf static/js/
rm -rf static/vendor/
rm -rf static/img/  # S5 images already moved to s5_branding/
rm -rf templates/

# 19. Remove core test infrastructure
rm -rf tests/
rm -f pytest.ini

# 20. Remove core database files
rm -f init.sql
rm -f init_test.sql

# 21. Remove old package setup
rm -f setup.py
rm -rf s5_slidefactory_cli.egg-info/

# 22. Remove core requirements files
rm -f requirements.txt
rm -f requirements-dev.txt

# 23. Remove core package directory (N8N nodes)
rm -rf packages/

# 24. Remove core-specific files
rm -f test_workflow_engines.py
rm -f bootstrap-database.sh

# 25. Clean up old build artifacts
rm -rf htmlcov/
rm -f .coverage
rm -rf site/  # MkDocs build output (docs now in core)
rm -f mkdocs.yml

# 26. Remove Docker Compose setup (moved to eddy-slidefactory)
rm -f docker-compose.yml
rm -f .env.local

PHASE 7: UPDATE GITHUB ACTIONS

# 27. Update preview.yml workflow for Azure deployment
cat > .github/workflows/preview.yml << 'EOF'
name: Deploy S5 to Azure Preview

on:
  push:
    branches: [preview]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to Azure
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Login to Azure Container Registry
        run: |
          az acr login --name s5slidefactory

      - name: Build and push Docker image
        env:
          GITHUB_TOKEN: ${{ secrets.GH_PAT_SLIDEFACTORY_CORE }}
        run: |
          docker build \
            --build-arg GITHUB_TOKEN=$GITHUB_TOKEN \
            --build-arg CORE_VERSION=1.0.8 \
            -t s5slidefactory.azurecr.io/slidefactory:preview-${{ github.sha }} .
          docker push s5slidefactory.azurecr.io/slidefactory:preview-${{ github.sha }}

      - name: Deploy to Azure Container Apps
        run: |
          az containerapp update \
            --name slidefactory-web-preview \
            --resource-group rg-slidefactory-preview \
            --image s5slidefactory.azurecr.io/slidefactory:preview-${{ github.sha }}
EOF

# 28. Update production.yml workflow for Azure deployment
cat > .github/workflows/production.yml << 'EOF'
name: Deploy S5 to Azure Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to Azure
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS_PROD }}

      - name: Login to Azure Container Registry
        run: |
          az acr login --name s5slidefactory

      - name: Build and push Docker image
        env:
          GITHUB_TOKEN: ${{ secrets.GH_PAT_SLIDEFACTORY_CORE }}
        run: |
          docker build \
            --build-arg GITHUB_TOKEN=$GITHUB_TOKEN \
            --build-arg CORE_VERSION=1.0.8 \
            -t s5slidefactory.azurecr.io/slidefactory:prod-${{ github.sha }} .
          docker push s5slidefactory.azurecr.io/slidefactory:prod-${{ github.sha }}

      - name: Deploy to Azure Container Apps
        run: |
          az containerapp update \
            --name slidefactory-web-prod \
            --resource-group rg-slidefactory-prod \
            --image s5slidefactory.azurecr.io/slidefactory:prod-${{ github.sha }}
EOF

PHASE 8: COMMIT CHANGES

# 29. Review changes
git status
git diff --stat

# 30. Stage S5-specific files
git add s5_branding/
git add pyproject.toml
git add .env.s5
git add Dockerfile
git add scripts/
git add start.sh
git add start-worker.sh
git add README.md
git add .github/workflows/
git add docs/

# 31. Stage removals
git add -u  # Stage all deletions

# 32. Review staged changes
git status

# 33. Commit changes
git commit -m "refactor: Convert S5 to Azure-only thin client using slidefactory-core

- Remove core application code (app/, cli/, alembic/, tests/)
- Remove Docker Compose setup (moved to eddy-slidefactory)
- Create s5_branding/ with SportFive assets
- Create pyproject.toml with slidefactory-core==1.0.8 dependency
- Update Dockerfile for Azure Container Apps deployment
- Update scripts for Azure Container Apps (start-web-azure.sh, start-worker-azure.sh)
- Create local dev scripts (start.sh, start-worker.sh) for Azure preview connection
- Archive migration documentation
- Update README for S5 Azure-only deployment

S5 is now an Azure-only deployment client. Docker setup moved to eddy-slidefactory.
Local development connects to Azure preview environment.

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

Co-Authored-By: Claude <noreply@anthropic.com>"

PHASE 9: VERIFICATION

# 34. Install slidefactory-core
# Option A: From local sibling repository (if you have the source)
pip install -e ../slidefactory-core

# Option B: From GitHub release using curl (if you don't have the source)
# export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
# curl -L \
#   -H "Authorization: token ${GITHUB_TOKEN}" \
#   -H "Accept: application/octet-stream" \
#   https://api.github.com/repos/cgast/slidefactory-core/releases/download/v1.0.8/slidefactory_core-1.0.8-py3-none-any.whl \
#   -o slidefactory_core-1.0.8-py3-none-any.whl
# pip install slidefactory_core-1.0.8-py3-none-any.whl
# rm slidefactory_core-1.0.8-py3-none-any.whl

# Option C: From GitHub release using gh CLI (easiest if you have gh installed)
# gh auth login  # Login once, then:
# gh release download v1.0.8 --repo cgast/slidefactory-core --pattern "*.whl"
# pip install slidefactory_core-1.0.8-py3-none-any.whl
# rm slidefactory_core-1.0.8-py3-none-any.whl

# 35. Install S5 package in development mode
pip install -e ".[azure]"

# 36. Verify core package is installed
pip list | grep slidefactory
# Should show:
#   slidefactory-core  1.0.8
#   s5-slidefactory    1.0.0

# 37. Verify CLI is available
which slidefactory
slidefactory --help

# 38. Test imports work
python -c "from slidefactory.app.main import app; print('✅ Core package imports successfully')"

# 39. Build Docker image for Azure locally (requires GITHUB_TOKEN)
# Note: For private repo access, you need to provide GitHub PAT
docker build \
  --build-arg GITHUB_TOKEN=$GITHUB_TOKEN \
  --build-arg CORE_VERSION=1.0.8 \
  -t s5-slidefactory:test .

# 40. Test Docker container
docker run --rm s5-slidefactory:test slidefactory --version

# 41. Test local development startup (requires Azure preview .env)
# ./start.sh
# (Ctrl+C to stop)

PHASE 10: PUSH TO REMOTE

# 42. Push feature branch
git push origin feature/s5-client-cleanup

# 43. Create PR to preview branch (NOT main)
# Do this via GitHub UI or gh CLI:
gh pr create --base preview --title "Convert S5 to Azure-only thin client using slidefactory-core" \
  --body "Completes repository separation by removing core code and using slidefactory-core package.

Changes:
- Remove core application code
- Remove Docker Compose (moved to eddy-slidefactory)
- Create s5_branding/ package
- Update for Azure-only deployment
- Local dev connects to Azure preview environment

Note: Requires GITHUB_TOKEN secret configured in GitHub Actions for private slidefactory-core access."

# After PR review and merge to preview:
# 44. Test preview deployment
# Monitor Azure Container Apps preview environment

# 45. If preview works, merge preview → main (repo owner only)
# This triggers production deployment

OPTIONAL: CLEANUP

# 46. After successful deployment, archive old branches
git branch -D backup-before-s5-cleanup-YYYYMMDD  # Delete local backup
# Keep remote backup for safety

Risk Assessment & Mitigation

Complexity Assessment

Complexity: Medium-high Risk Level: Medium

Reasons for Medium-High Complexity: 1. Major architectural change (monolith → package dependency) 2. Affects deployment pipeline and CI/CD 3. Changes import paths and startup scripts throughout 4. Requires coordination with Azure deployment configuration 5. Multiple file movements and deletions 6. Testing requires Azure preview environment access 7. Removes Docker Compose (moved to different repo)

Reasons for Medium Risk: 1. Core package is already tested and stable (v1.0.8) 2. Clear rollback strategy available (backup branch) 3. Preview environment allows testing before production 4. Non-destructive changes (backups created) 5. Similar pattern already working in core repo 6. Docker removal is clean separation (moved to eddy-slidefactory)

Risk Mitigation Strategies

1. Backup Strategy - Create backup branch before any changes - Push backup to remote immediately - Keep backup for at least 30 days after successful deployment

2. Staged Rollout - Test locally with Azure preview connection - Deploy to Azure preview environment - Monitor for 24-48 hours before production - Only merge to main after preview validation

3. Testing Strategy - Verify package installation locally - Test CLI commands work - Test Docker build completes - Test local development with Azure preview - Verify Azure Container Apps deployment succeeds

4. Rollback Plan

# If something breaks:
git checkout preview
git reset --hard origin/preview  # Restore to last working state

# Or restore from backup branch:
git checkout backup-before-s5-cleanup-YYYYMMDD
git checkout -b preview-restored
git push origin preview-restored --force

Pre-deployment Checklist

Before executing this plan, verify:

  • Core package v1.0.8 is stable and tested in core repo
  • Core package is accessible (installed locally via ../slidefactory-core)
  • S5 branding assets are identified and backed up
  • Azure secrets and credentials are documented
  • Azure preview environment is accessible for local dev
  • Preview environment is available for testing deployment
  • Backup branch has been created and pushed to remote
  • Team has been notified of upcoming changes
  • Rollback procedure has been reviewed
  • .env configured with Azure preview credentials for local testing
  • GitHub PAT created with 'repo' scope for slidefactory-core access
  • GitHub secret GH_PAT_SLIDEFACTORY_CORE configured in repo settings

Post-deployment Validation

After deployment, verify:

  • Azure preview deployment starts successfully
  • Web application is accessible at preview URL
  • CLI commands work in Azure environment
  • Database migrations run correctly
  • Static files (S5 branding) are served correctly
  • User authentication works (Azure AD)
  • Presentation generation works
  • Worker processes start and process tasks
  • Logs show no import errors or package issues
  • Local development works with Azure preview connection

Benefits Realized

For Core Maintainer

  1. Single Source of Truth: One codebase for all core functionality
  2. Version Control: Clients upgrade on their schedule
  3. Clear Ownership: Core changes go to core repo only
  4. Easier Testing: Test core once, all clients benefit
  5. Documentation: Core docs separate from client docs
  6. Reduced Duplication: No need to maintain multiple copies of core code

For S5 Deployment

  1. Isolated Issues: S5-specific issues tracked separately
  2. Custom Branding: Complete control over S5 look and feel
  3. Independent Deployments: Deploy on S5's schedule
  4. Stable Versions: Pin to tested core versions, upgrade when ready
  5. Clear Support: Know where to report issues (core vs. S5)
  6. Simplified Repository: Only deployment and branding code
  7. Azure-Only Focus: No Docker maintenance, focused on Azure

Technical Benefits

  1. Separation of Concerns: Core logic vs. Azure deployment configuration
  2. Testability: Core tests don't need Azure setup
  3. Reusability: Easy to create new clients (Eddy uses Docker, S5 uses Azure)
  4. Scalability: Core improvements benefit all clients automatically
  5. Security: Client-specific secrets stay in client repos
  6. Maintainability: Changes are localized and easier to reason about
  7. Clear Deployment Models: S5 (Azure), Eddy (Docker/Hetzner), etc.

Version Management Strategy

Core Package Updates

When core package releases a new version:

  1. Core team creates new release in core repo:

    cd ../slidefactory-core
    # Update version in pyproject.toml and __init__.py
    git tag v1.1.0
    git push --tags
    

  2. S5 team decides when to upgrade:

    cd s5-slidefactory
    
    # Update Dockerfile CORE_VERSION
    # Edit Dockerfile, change: ARG CORE_VERSION=1.0.8 → ARG CORE_VERSION=1.1.0
    
    # Update local development
    cd ../slidefactory-core
    git pull
    git checkout v1.1.0
    cd ../s5-slidefactory
    pip install -e ../slidefactory-core --force-reinstall
    
    # Test locally against Azure preview
    ./start.sh
    
    # Commit and deploy to preview
    git commit -am "chore: upgrade slidefactory-core to v1.1.0"
    git push origin preview
    
    # Monitor preview deployment, then merge to main when stable
    

Version Pinning Policy

  • S5 pins exact versions in Dockerfile via CORE_VERSION build arg (e.g., 1.0.8)
  • Version is set in Dockerfile: ARG CORE_VERSION=1.0.8
  • GitHub Actions can override: --build-arg CORE_VERSION=1.1.0
  • Prevents unexpected breakage from core updates
  • S5 controls upgrade timing
  • Allows testing before production deployment

Breaking Changes

Core package follows semantic versioning: - MAJOR (x.0.0): Breaking changes - S5 must review and test - MINOR (1.x.0): New features - S5 can upgrade with low risk - PATCH (1.0.x): Bug fixes - S5 should upgrade ASAP


Deployment Model Comparison

S5 (Azure-only)

Local Development: - start.sh + start-worker.sh - Connects to Azure preview environment - No local database/Redis/storage

Deployment: - GitHub Actions → Azure Container Apps - Preview and production environments

Dockerfile: - Used only for Azure Container Apps image build - Not used for local development

Eddy (Docker/Hetzner)

Local Development: - docker-compose up - Local services (postgres, redis, minio) - Self-contained development

Deployment: - Docker Compose on Hetzner - Single production environment

Dockerfile: - Used for both local development and production - Docker Compose manages services


Future Considerations

Adding More Clients

This pattern makes it easy to add new clients with different deployment models:

S5 Pattern (Azure):

mkdir s5-slidefactory
cd s5-slidefactory
# Create pyproject.toml with core dependency + Azure dependencies
# Create branding package
# Create Azure deployment workflows
# Local dev connects to Azure preview

Eddy Pattern (Docker/Hetzner):

mkdir eddy-slidefactory
cd eddy-slidefactory
# Create pyproject.toml with core dependency
# Create branding package
# Create docker-compose.yml
# Local dev uses Docker Compose

Core Package Distribution

Current: Local installation from ../slidefactory-core

Future options: 1. GitHub Packages: Private package registry 2. PyPI: Public package (if open-sourced) 3. Self-hosted PyPI: Internal package server

Documentation Strategy

  • Core docs: In core repo, published via MkDocs
  • S5 docs: In S5 repo, Azure deployment-specific
  • Eddy docs: In Eddy repo, Docker deployment-specific

Troubleshooting Guide

Issue: Package not found during installation

# Solution: Install core from local path
pip install -e ../slidefactory-core

# Or if using package registry:
pip install slidefactory-core==1.0.8 --index-url <registry-url>

Issue: Import errors after cleanup

# Check if core package is installed
pip list | grep slidefactory

# Reinstall if needed
pip install -e ".[azure]" --force-reinstall

Issue: Static files (branding) not found

# Verify symlink in Dockerfile
docker run --rm s5-slidefactory:test ls -la /code/static/s5_branding

# Check branding package structure
ls -la s5_branding/static/

Issue: CLI commands not working

# Check which slidefactory is being used
which slidefactory

# Should point to core package's CLI, not local script
# /path/to/.venv/bin/slidefactory (correct)
# ./slidefactory (incorrect - old script)

Issue: Local development cannot connect to Azure

# Verify .env has Azure preview credentials
cat .env | grep DATABASE_URL
cat .env | grep REDIS_HOST
cat .env | grep AZURE_STORAGE

# Test database connection
psql "${DATABASE_URL}"

# Test Redis connection
redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} -a ${REDIS_PASSWORD} ping

Issue: Azure Container Apps deployment fails

# Check GitHub Actions logs
# Verify secrets are configured in GitHub repo settings:
#   - AZURE_CREDENTIALS (for preview)
#   - AZURE_CREDENTIALS_PROD (for production)
#   - GH_PAT_SLIDEFACTORY_CORE (GitHub PAT for accessing private slidefactory-core repo)

# Test Docker build locally with GitHub token
docker build \
  --build-arg GITHUB_TOKEN=$GITHUB_TOKEN \
  --build-arg CORE_VERSION=1.0.8 \
  -t s5-slidefactory:test .
docker run --rm s5-slidefactory:test slidefactory --version

Issue: Docker build fails to download slidefactory-core wheel

# Ensure GITHUB_TOKEN is provided and has repo access
# The token needs 'repo' scope for private repository access

# Create GitHub Personal Access Token:
# 1. Go to GitHub Settings > Developer settings > Personal access tokens > Tokens (classic)
# 2. Generate new token with 'repo' scope
# 3. Add as secret GH_PAT_SLIDEFACTORY_CORE in GitHub repo settings

# Verify the wheel exists in GitHub releases:
# https://github.com/cgast/slidefactory-core/releases/tag/v1.0.8
# File should be: slidefactory_core-1.0.8-py3-none-any.whl

# For local builds, export token:
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
docker build \
  --build-arg GITHUB_TOKEN=$GITHUB_TOKEN \
  --build-arg CORE_VERSION=1.0.8 \
  -t s5-slidefactory:test .

# Test with different version:
docker build \
  --build-arg GITHUB_TOKEN=$GITHUB_TOKEN \
  --build-arg CORE_VERSION=1.0.9 \
  -t s5-slidefactory:test .

Helper Script: Install Core from GitHub

For easier installation without the sibling repository, create this helper script:

# Create scripts/install-core-from-github.sh
cat > scripts/install-core-from-github.sh << 'EOF'
#!/bin/bash
# Install slidefactory-core from GitHub release
set -e

CORE_VERSION=${1:-1.0.8}

echo "Installing slidefactory-core v${CORE_VERSION} from GitHub releases..."

# Try gh CLI first (easiest, handles auth automatically)
if command -v gh &> /dev/null; then
    echo "Using GitHub CLI (gh)..."
    gh release download v${CORE_VERSION} \
        --repo cgast/slidefactory-core \
        --pattern "*.whl" \
        --dir /tmp

    pip install /tmp/slidefactory_core-${CORE_VERSION}-py3-none-any.whl
    rm /tmp/slidefactory_core-${CORE_VERSION}-py3-none-any.whl

# Fall back to curl with GITHUB_TOKEN
elif [ -n "$GITHUB_TOKEN" ]; then
    echo "Using curl with GITHUB_TOKEN..."
    curl -L \
        -H "Authorization: token ${GITHUB_TOKEN}" \
        -H "Accept: application/octet-stream" \
        https://api.github.com/repos/cgast/slidefactory-core/releases/download/v${CORE_VERSION}/slidefactory_core-${CORE_VERSION}-py3-none-any.whl \
        -o /tmp/slidefactory_core.whl

    pip install /tmp/slidefactory_core.whl
    rm /tmp/slidefactory_core.whl

else
    echo "Error: Neither 'gh' CLI nor GITHUB_TOKEN found"
    echo ""
    echo "Option 1: Install GitHub CLI and authenticate:"
    echo "  brew install gh  # or apt-get install gh"
    echo "  gh auth login"
    echo "  ./scripts/install-core-from-github.sh"
    echo ""
    echo "Option 2: Use GitHub Personal Access Token:"
    echo "  export GITHUB_TOKEN=ghp_xxxxx"
    echo "  ./scripts/install-core-from-github.sh"
    exit 1
fi

echo "✅ slidefactory-core v${CORE_VERSION} installed successfully"
slidefactory --version
EOF

chmod +x scripts/install-core-from-github.sh

Usage:

# Option 1: With GitHub CLI (recommended)
gh auth login  # One-time setup
./scripts/install-core-from-github.sh           # Install v1.0.8
./scripts/install-core-from-github.sh 1.0.9     # Install specific version

# Option 2: With GitHub PAT
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
./scripts/install-core-from-github.sh           # Install v1.0.8
./scripts/install-core-from-github.sh 1.0.9     # Install specific version


Success Criteria

This migration is considered successful when:

  1. ✅ S5 repo contains only branding, config, and Azure deployment files
  2. ✅ Core package (v1.0.8) is installed and importable
  3. slidefactory CLI command works and uses core package
  4. ✅ Local development works with ./start.sh (connects to Azure preview)
  5. ✅ Local worker works with ./start-worker.sh (connects to Azure preview)
  6. ✅ Docker build completes successfully (for Azure Container Apps)
  7. ✅ Docker container starts and serves application
  8. ✅ Azure preview deployment succeeds
  9. ✅ S5 branding appears correctly in deployed application
  10. ✅ All core functionality (presentations, users, API keys) works
  11. ✅ No import errors or package-related errors in logs
  12. ✅ Docker Compose removed (confirmed moved to eddy-slidefactory)

Appendix A: File Inventory

Files Removed (Core Code)

  • app/ (18 subdirectories, ~200 files)
  • cli/ (5 files)
  • alembic/ (4 directories, ~30 files)
  • static/ (4 subdirectories, ~50 files)
  • templates/ (14 subdirectories, ~40 files)
  • tests/ (11 subdirectories, ~80 files)
  • docker-compose.yml (moved to eddy-slidefactory)
  • .env.local (Docker config, not used by S5)
  • Supporting files: ~20 files

Total removal: ~440 files

Files Created (S5 Client)

  • s5_branding/ (3 subdirectories)
  • pyproject.toml
  • .env.s5
  • start-worker.sh
  • Updated: Dockerfile, README.md
  • Updated scripts: 2 files (start-web-azure.sh, start-worker-azure.sh)
  • Updated: start.sh (Azure preview connection)
  • New documentation: This report

Total additions: ~15 files + branding assets

Net Change

  • Before: ~500 files (monolith + Docker)
  • After: ~60 files (thin Azure client)
  • Reduction: ~88% fewer files in S5 repo

These documents have been archived to docs/archive/migration/ as they pertain to the migration process rather than ongoing S5 operations.


Appendix C: S5 vs Eddy Comparison

Aspect S5 (This Repo) Eddy
Deployment Azure Container Apps Docker on Hetzner
Local Dev Connect to Azure preview Docker Compose
Services All on Azure All in Docker
Dockerfile Azure Container Apps only Local + production
docker-compose.yml ❌ Removed ✅ Main setup
start.sh Connect to Azure ❌ Not needed
Configuration .env.azure.* .env.local

Document Status: Ready for Implementation Next Steps: Review revised plan, obtain approval, execute Phase 1 (backup) Questions/Issues: Contact maintainer or create issue in S5 repository


Revision History: - 2025-11-22: Initial plan created - 2025-11-23: Revised to align with S5 Azure-only deployment model - Removed Docker Compose setup (moved to eddy-slidefactory) - Updated local development to connect to Azure preview - Added start-worker.sh for local worker development - Clarified S5 vs Eddy deployment models - Updated all scripts and documentation - Updated package installation: slidefactory-core is private, not on PyPI - Local development: pip install -e ../slidefactory-core - Docker/Azure: Download wheel from GitHub releases (v1.0.8) - Uses curl with GitHub PAT to download private release asset - Added GitHub secret requirement: GH_PAT_SLIDEFACTORY_CORE - Added build arg: CORE_VERSION (default: 1.0.8)