Skip to content

Repository Separation Implementation Guide

Date: 2025-11-18 Status: Implementation Plan Author: Claude Code Complexity: Medium - High complexity migration with significant architectural benefits

Executive Summary

This guide provides a detailed implementation plan for separating the current monolithic s5-slidefactory repository into:

  1. slidefactory-core - Core platform as installable Python package
  2. s5-slidefactory - S5 client deployment (Azure Container Apps)
  3. eddy-slidefactory - Eddy client deployment (Docker/Coolify)

Benefits: - Single source of truth for core functionality - Client-specific issue tracking and PRs - Independent deployment cycles - Version pinning for stability - Easy to add new clients

Distribution: GitHub Packages (private) Versioning: Semantic versioning (v1.0.0, v1.1.0, etc.) License: Private for now, core may become MIT later


Architecture Overview

Current State

s5-slidefactory/ (monolithic)
├── app/                      # Core application
├── cli/                      # CLI tool
├── static/                   # Mixed: core + S5 branding
├── .github/workflows/        # S5 Azure deployment
├── docker-compose.yml        # S5 specific
└── ...

Target State

slidefactory-core/            # Core package (GitHub Packages)
├── pyproject.toml            # Package config
├── src/
│   └── slidefactory/
│       ├── app/              # Core FastAPI application
│       ├── cli/              # CLI commands
│       ├── alembic/          # Database migrations
│       └── __init__.py
├── static/                   # Generic assets only
├── templates/                # Generic templates
├── packages/
│   └── n8n-nodes-slidefactory/
├── tests/                    # Core tests
├── requirements.txt          # Core dependencies
├── Dockerfile.base           # Base image
├── .github/workflows/
│   ├── test.yml              # Test on PR
│   ├── publish.yml           # Publish to GitHub Packages
│   └── release.yml           # Create releases
└── README.md                 # Developer documentation

s5-slidefactory/              # S5 client repo
├── pyproject.toml            # Depends on: slidefactory-core
├── s5_branding/
│   ├── static/               # SportFive logos, colors
│   └── templates/            # S5-specific overrides
├── .env.s5                   # S5 configuration
├── .github/workflows/
│   ├── preview.yml           # Azure preview deploy
│   └── production.yml        # Azure production deploy
├── docker-compose.s5.yml     # S5 local development
├── scripts/
│   ├── start-web-azure.sh
│   └── deploy-azure.sh
├── README.md                 # S5 user documentation
└── docs/                     # S5-specific docs

eddy-slidefactory/            # Eddy client repo
├── pyproject.toml            # Depends on: slidefactory-core
├── eddy_branding/
│   ├── static/               # Eddy logos, colors
│   └── templates/            # Eddy-specific overrides
├── .env.eddy                 # Eddy configuration
├── docker-compose.yml        # Coolify deployment
├── scripts/
│   └── start-web-docker.sh
├── README.md                 # Eddy user documentation
└── docs/                     # Eddy-specific docs

Phase 1: Create Core Package Repository

1.1 Create New Repository

# Create new repo on GitHub
# Repository name: slidefactory-core
# Visibility: Private
# Initialize: No (we'll push existing code)

1.2 Repository Structure

New pyproject.toml for core:

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "slidefactory-core"
version = "1.0.0"
description = "AI-driven presentation automation platform - Core engine"
readme = "README.md"
requires-python = ">=3.11"
license = {text = "Proprietary"}
authors = [
    {name = "Christian Gast", email = "your-email@example.com"}
]
keywords = ["presentations", "automation", "ai", "n8n", "fastapi"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.11",
    "Framework :: FastAPI",
]

dependencies = [
    "fastapi>=0.104.0",
    "uvicorn[standard]>=0.24.0",
    "sqlalchemy>=2.0.0",
    "psycopg2-binary>=2.9.9",
    "alembic>=1.12.0",
    "celery>=5.3.4",
    "redis>=5.0.1",
    "jinja2>=3.1.2",
    "jinja2-fragments>=1.2.0",
    "python-pptx>=0.6.23",
    "pillow>=10.1.0",
    "requests>=2.31.0",
    "python-dotenv>=1.0.0",
    "pydantic>=2.5.0",
    "pydantic-settings>=2.1.0",
    "httpx>=0.25.2",
    "python-multipart>=0.0.6",
    "python-jose[cryptography]>=3.3.0",
    "passlib[bcrypt]>=1.7.4",
    "fastapi-sessions>=0.3.2",
    "sse-starlette>=1.8.2",
    "apscheduler>=3.10.4",
    "mistralai>=0.0.7",
    "openai>=1.3.0",
    "anthropic>=0.7.0",
    "pgvector>=0.2.3",
    "beautifulsoup4>=4.12.2",
    "lxml>=4.9.3",
    "markdown>=3.5.1",
    "pypdf>=3.17.1",
    "openpyxl>=3.1.2",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.4.3",
    "pytest-asyncio>=0.21.1",
    "pytest-cov>=4.1.0",
    "pytest-xdist>=3.5.0",
    "black>=23.12.0",
    "flake8>=6.1.0",
    "mypy>=1.7.1",
]
azure = [
    "azure-storage-blob>=12.19.0",
    "azure-identity>=1.15.0",
    "msal>=1.26.0",
]
minio = [
    "minio>=7.2.0",
]

[project.scripts]
slidefactory = "slidefactory.cli.main:main"

[project.urls]
Homepage = "https://github.com/yourusername/slidefactory-core"
Documentation = "https://github.com/yourusername/slidefactory-core/tree/main/docs"
Repository = "https://github.com/yourusername/slidefactory-core"
Issues = "https://github.com/yourusername/slidefactory-core/issues"

[tool.setuptools]
packages = ["slidefactory"]
package-dir = {"" = "src"}

[tool.setuptools.package-data]
slidefactory = [
    "templates/**/*.j2",
    "templates/**/*.html",
    "static/**/*",
    "alembic.ini",
    "alembic/**/*",
]

[tool.black]
line-length = 120
target-version = ['py311']

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
markers = [
    "unit: Unit tests",
    "integration: Integration tests",
    "e2e: End-to-end tests",
]

1.3 Directory Migration

Move core code to src/slidefactory/ structure:

# Current structure → New structure
app/                   src/slidefactory/app/
cli/                   src/slidefactory/cli/
alembic/               src/slidefactory/alembic/
alembic.ini            src/slidefactory/alembic.ini
requirements.txt       Keep at root (for backwards compat)

Create src/slidefactory/__init__.py:

"""
Slidefactory Core - AI-driven presentation automation platform.

This package provides the core engine for AI-powered presentation generation,
workflow integration, and document processing.
"""

__version__ = "1.0.0"
__author__ = "Christian Gast"

# Export key components
from slidefactory.app.config import settings, Config
from slidefactory.app.main import app

__all__ = [
    "__version__",
    "settings",
    "Config",
    "app",
]

1.4 Static Assets - Remove Client Branding

Keep in core:

static/
├── css/              # Keep (core styles)
├── js/               # Keep (core JS)
├── vendor/           # Keep (libraries)
└── img/
    ├── favicon.ico   # Keep (generic)
    ├── logo.png      # Keep (generic Slidefactory logo)
    └── logo_large.png # Keep (generic)

Remove from core (move to client repos):

static/img/
├── branding/         # → s5-slidefactory/s5_branding/static/
├── sportfive*        # → s5-slidefactory/s5_branding/static/
├── sf_logo_*         # → s5-slidefactory/s5_branding/static/
└── login_hero.png    # → s5-slidefactory/s5_branding/static/ (if S5-specific)

1.5 Configuration Changes

Update src/slidefactory/app/config.py:

Make sure all client-specific defaults are environment-driven:

class Config:
    # Branding (must be set by clients)
    CLIENT_NAME: str = os.getenv("CLIENT_NAME", "Slidefactory")
    CLIENT_LOGO: str = os.getenv("CLIENT_LOGO", "/static/img/logo.png")
    CLIENT_LOGO_LARGE: str = os.getenv("CLIENT_LOGO_LARGE", "/static/img/logo_large.png")
    CLIENT_PRIMARY_COLOR: str = os.getenv("CLIENT_PRIMARY_COLOR", "#007bff")

    # No hardcoded deployment-specific values
    # Clients must provide these via environment variables

1.6 GitHub Actions for Core

.github/workflows/test.yml:

name: Test Core

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main, develop]

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      postgres:
        image: ankane/pgvector:latest
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: slidefactory_test
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

      redis:
        image: redis:7-alpine
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 6379:6379

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          pip install -e ".[dev]"

      - name: Run tests
        env:
          DATABASE_URL: postgresql://postgres:postgres@localhost:5432/slidefactory_test
          REDIS_HOST: localhost
          REDIS_PORT: 6379
        run: |
          pytest tests/ -v --cov=slidefactory --cov-report=xml

      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage.xml

.github/workflows/publish.yml:

name: Publish to GitHub Packages

on:
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to publish (e.g., 1.0.0)'
        required: true

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install build tools
        run: |
          pip install build twine

      - name: Update version
        if: github.event_name == 'workflow_dispatch'
        run: |
          VERSION="${{ github.event.inputs.version }}"
          sed -i "s/version = \".*\"/version = \"${VERSION}\"/" pyproject.toml
          sed -i "s/__version__ = \".*\"/__version__ = \"${VERSION}\"/" src/slidefactory/__init__.py

      - name: Build package
        run: |
          python -m build

      - name: Publish to GitHub Packages
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
          TWINE_REPOSITORY_URL: https://upload.pypi.org/legacy/
        run: |
          # For GitHub Packages, use:
          # TWINE_REPOSITORY_URL: https://upload.github.com/pypi/YOUR_ORG/
          twine upload dist/* --repository-url https://upload.github.com/pypi/${{ github.repository_owner }}/

1.7 Core README.md

README.md for core:

# Slidefactory Core

AI-driven presentation automation platform - Core engine.

## Overview

Slidefactory Core provides the foundational platform for AI-powered presentation generation, workflow orchestration, and document processing. This package is designed to be deployed by client-specific repositories.

## Features

- **Presentation Generation**: PowerPoint automation with Jinja2 templating
- **AI Provider Integration**: OpenAI, Azure OpenAI, Mistral, Anthropic, Ollama, OpenRouter
- **Workflow Orchestration**: N8N, Prefect, Windmill integration
- **Document Processing**: PDF/text ingestion, chunking, embedding, vector search
- **Multi-Cloud Storage**: MinIO, Azure Blob Storage
- **Database Migrations**: Alembic-based schema management
- **CLI Tool**: Complete management interface

## Installation

### From GitHub Packages

```bash
# Configure pip to use GitHub Packages
pip install slidefactory-core --index-url https://github.com/YOUR_ORG/packages/pypi/simple/

From Source (Development)

git clone https://github.com/YOUR_ORG/slidefactory-core.git
cd slidefactory-core
pip install -e ".[dev]"

Usage

As a Library

from slidefactory import settings, app

# Access configuration
print(settings.VERSION)

# Use FastAPI app
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8080)

CLI Tool

# Initialize database
slidefactory init all

# Manage users
slidefactory user create-local user@example.com --name "John Doe"

# Manage API keys
slidefactory api-key create "My Key" --user-id 1

# Generate presentations
slidefactory presentation generate --template-id 123 --data-file data.json

Configuration

All configuration is done via environment variables. See .env.example for all options.

Required Settings: - DATABASE_URL: PostgreSQL connection string - REDIS_HOST: Redis host - STORAGE_PROVIDER: "minio" or "azure" - AI_PROVIDER: Default AI provider - AI_MODEL: Default AI model

Branding (set by client deployments): - CLIENT_NAME: Display name - CLIENT_LOGO: Logo path - CLIENT_PRIMARY_COLOR: Brand color

Development

Running Tests

pytest tests/

Running Locally

# Start PostgreSQL, Redis, MinIO (via Docker)
docker-compose up -d postgres redis minio

# Run web server
uvicorn slidefactory.app.main:app --reload

# Run worker
celery -A slidefactory.app.celery_app worker --loglevel=info

Versioning

This package follows semantic versioning (MAJOR.MINOR.PATCH):

  • MAJOR: Breaking changes
  • MINOR: New features (backwards compatible)
  • PATCH: Bug fixes

License

Proprietary - Private use only. May become MIT licensed in the future.

Client Deployments

This core package is used by: - s5-slidefactory - Azure Container Apps - eddy-slidefactory - Docker/Coolify

Contributing

This is the core engine. Client-specific changes should go to respective client repositories.

For core changes: 1. Create feature branch from main 2. Make changes with tests 3. Create PR to main 4. After merge, create release tag 5. Publish to GitHub Packages

---

## Phase 2: Create S5 Client Repository

### 2.1 Repository Structure
s5-slidefactory/ ├── pyproject.toml # Depends on slidefactory-core ├── .env.s5 # S5 configuration ├── .env.s5.azure # Azure-specific overrides ├── s5_branding/ │ ├── init.py │ ├── static/ │ │ ├── css/ │ │ │ └── s5-custom.css │ │ └── img/ │ │ ├── sportfive_logo.png │ │ ├── sportfive_large.png │ │ ├── login_hero.png │ │ └── favicon.ico │ └── templates/ # S5-specific template overrides │ └── home.html.j2 # (if needed) ├── .github/ │ └── workflows/ │ ├── preview.yml # Azure preview deployment │ └── production.yml # Azure production deployment ├── docker-compose.s5.yml # Local development ├── scripts/ │ ├── start-web-azure.sh │ ├── start-worker-azure.sh │ └── deploy-azure.sh ├── Dockerfile # S5-specific (extends core base image) ├── README.md # S5 user documentation └── docs/ └── deployment.md # Azure deployment guide
### 2.2 S5 pyproject.toml

```toml
[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"
requires-python = ">=3.11"
dependencies = [
    "slidefactory-core==1.0.0",  # Pin to specific core version
]

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

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

2.3 S5 Environment Configuration

.env.s5:

# S5 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)
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 (from secrets)
DATABASE_URL="${DATABASE_URL}"

# Redis (from secrets)
REDIS_HOST="${REDIS_HOST}"
REDIS_PORT="${REDIS_PORT}"
REDIS_PASSWORD="${REDIS_PASSWORD}"
REDIS_SSL=true

# AI (from secrets)
OPENAI_API_KEY="${OPENAI_API_KEY}"
AZURE_OPENAI_API_KEY="${AZURE_OPENAI_API_KEY}"

2.4 S5 Dockerfile

# Extend core base image
FROM ghcr.io/YOUR_ORG/slidefactory-core:1.0.0

# Install S5 package with Azure dependencies
COPY pyproject.toml /code/
RUN pip install -e ".[azure]"

# Copy S5 branding
COPY s5_branding/ /code/s5_branding/

# Copy S5 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

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

2.5 S5 GitHub Actions

.github/workflows/preview.yml:

name: Deploy S5 to Preview

on:
  push:
    branches: [preview]

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

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push S5 image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}:preview-${{ github.sha }}

      - name: Deploy to Azure Container Apps
        # ... existing Azure deployment steps

2.6 S5 README.md

# S5 SportFive Slidefactory

SportFive-branded deployment of Slidefactory on Azure Container Apps.

## Overview

This repository contains the SportFive-specific configuration and branding for Slidefactory.

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

## Deployment

### Azure Container Apps (Production)

Automatic deployment via GitHub Actions:
- **Preview:** Push to `preview` branch → `slidefactory-preview.azurewebsites.net`
- **Production:** Push to `main` branch → `slidefactory.sportfive.com`

### Local Development

```bash
# Install dependencies
pip install -e ".[azure]"

# Configure environment
cp .env.s5 .env
# Edit .env with your secrets

# Start with Docker Compose
docker-compose -f docker-compose.s5.yml up

Branding

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

Configuration

See .env.s5 for S5-specific settings.

Azure Resources: - Resource Group: rg-slidefactory-prod-001 - Container Apps: slidefactory-web-prod, slidefactory-worker-prod - Storage: s5slidefactorystorage - Database: Azure Database for PostgreSQL

Support

For S5-specific issues, create an issue in this repository.

For core platform issues, see slidefactory-core issues.

---

## Phase 3: Create Eddy Client Repository

### 3.1 Repository Structure
eddy-slidefactory/ ├── pyproject.toml # Depends on slidefactory-core ├── .env.eddy # Eddy configuration ├── eddy_branding/ │ ├── init.py │ ├── static/ │ │ ├── css/ │ │ │ └── eddy-custom.css │ │ └── img/ │ │ ├── eddy_logo.png │ │ ├── eddy_large.png │ │ └── favicon.ico │ └── templates/ # Eddy-specific overrides ├── docker-compose.yml # Coolify deployment ├── scripts/ │ ├── start-web-docker.sh │ └── start-worker-docker.sh ├── Dockerfile # Eddy-specific ├── README.md # Eddy user documentation └── docs/ └── deployment.md # Coolify deployment guide
### 3.2 Eddy pyproject.toml

```toml
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "eddy-slidefactory"
version = "1.0.0"
description = "Eddy Slidefactory - Docker/Coolify Deployment"
requires-python = ">=3.11"
dependencies = [
    "slidefactory-core==1.0.0",  # Pin to specific core version
]

[project.optional-dependencies]
minio = [
    "minio>=7.2.0",
]

[tool.setuptools]
packages = ["eddy_branding"]

3.3 Eddy Environment Configuration

.env.eddy:

# Eddy Branding
CLIENT_NAME="Eddy Slidefactory"
CLIENT_LOGO="/eddy_branding/static/img/eddy_logo.png"
CLIENT_LOGO_LARGE="/eddy_branding/static/img/eddy_large.png"
CLIENT_PRIMARY_COLOR="#0066cc"

# Eddy Deployment
DEPLOYMENT_PLATFORM="docker"
SERVER_URL="https://eddy-slidefactory.example.com"

# Storage (MinIO)
STORAGE_PROVIDER="minio"
MINIO_CLIENT_URL="minio:9000"
MINIO_ACCESS_KEY="admin"
MINIO_SECRET_KEY="adminadminadmin"

# Database (Docker internal)
DATABASE_URL="postgresql+psycopg2://postgres:postgres@postgres:5432/slidefactory"

# Redis (Docker internal)
REDIS_HOST="redis"
REDIS_PORT="6379"
REDIS_PASSWORD=""
REDIS_SSL=false

# AI (from environment)
OPENAI_API_KEY="${OPENAI_API_KEY}"
AI_PROVIDER="openai"
AI_MODEL="gpt-4"

3.4 Eddy docker-compose.yml

version: '3.8'

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
    environment:
      - TZ=Europe/Berlin
    env_file:
      - .env.eddy
    volumes:
      - ./eddy_branding:/code/eddy_branding
      - ./downloads:/code/downloads
    depends_on:
      - postgres
      - redis
      - minio
    command: /code/scripts/start-web-docker.sh

  worker:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - TZ=Europe/Berlin
    env_file:
      - .env.eddy
    depends_on:
      - postgres
      - redis
      - minio
    command: /code/scripts/start-worker-docker.sh

  postgres:
    image: ankane/pgvector:latest
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: slidefactory
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  minio:
    image: minio/minio:latest
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: admin
      MINIO_ROOT_PASSWORD: adminadminadmin
    volumes:
      - minio_data:/data
    ports:
      - "9000:9000"
      - "9001:9001"

  n8n:
    image: n8nio/n8n:latest
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=admin
    volumes:
      - n8n_data:/home/node/.n8n
    ports:
      - "5678:5678"

volumes:
  postgres_data:
  minio_data:
  n8n_data:

3.5 Eddy Dockerfile

# Extend core base image
FROM ghcr.io/YOUR_ORG/slidefactory-core:1.0.0

# Install Eddy package with MinIO dependencies
COPY pyproject.toml /code/
RUN pip install -e ".[minio]"

# Copy Eddy branding
COPY eddy_branding/ /code/eddy_branding/

# Copy Eddy scripts
COPY scripts/ /code/scripts/
RUN chmod +x /code/scripts/*.sh

# Expose Eddy branding as static files
RUN ln -s /code/eddy_branding/static /code/static/eddy_branding

# Use Eddy startup script
CMD ["/code/scripts/start-web-docker.sh"]

3.6 Eddy README.md

# Eddy Slidefactory

Eddy-branded deployment of Slidefactory via Docker/Coolify.

## Overview

This repository contains the Eddy-specific configuration and branding for Slidefactory.

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

## Deployment

### Coolify (Production)

Deploy via Coolify dashboard:
1. Add new service → Docker Compose
2. Connect this repository
3. Set environment variables from `.env.eddy`
4. Deploy

### Local Development

```bash
# Install dependencies
pip install -e ".[minio]"

# Configure environment
cp .env.eddy .env
# Edit .env with your API keys

# Start all services
docker-compose up

Access: - Web: http://localhost:8000 - MinIO Console: http://localhost:9001 (admin/adminadminadmin) - N8N: http://localhost:5678 (admin/admin)

Branding

Eddy branding assets are in eddy_branding/static/: - Logo: Eddy blue logo - Colors: Blue (#0066cc) primary - Custom CSS: eddy_branding/static/css/eddy-custom.css

Configuration

See .env.eddy for Eddy-specific settings.

Docker Services: - Web: FastAPI application - Worker: Celery worker - PostgreSQL: Database with pgvector - Redis: Cache and queue - MinIO: S3-compatible storage - N8N: Workflow automation

Support

For Eddy-specific issues, create an issue in this repository.

For core platform issues, see slidefactory-core issues.

---

## Phase 4: Migration Process

### 4.1 Migration Checklist

**Week 1: Core Package Setup**
- [ ] Create `slidefactory-core` repository on GitHub
- [ ] Set up GitHub Packages authentication
- [ ] Restructure code to `src/slidefactory/` layout
- [ ] Create `pyproject.toml` with dependencies
- [ ] Remove client-specific branding from static assets
- [ ] Update import paths for new structure
- [ ] Set up GitHub Actions (test, publish, release)
- [ ] Run tests to ensure nothing broke
- [ ] Create initial release: v1.0.0
- [ ] Publish to GitHub Packages

**Week 2: S5 Client Setup**
- [ ] Create `s5-slidefactory` repository
- [ ] Set up `pyproject.toml` with core dependency
- [ ] Move S5 branding assets to `s5_branding/`
- [ ] Create S5 environment configuration (`.env.s5`)
- [ ] Update GitHub Actions workflows for Azure
- [ ] Create S5 Dockerfile
- [ ] Test S5 deployment locally
- [ ] Test S5 deployment to Azure preview
- [ ] Update S5 README and documentation
- [ ] Archive old `s5-slidefactory` (rename to `s5-slidefactory-legacy`)

**Week 3: Eddy Client Setup**
- [ ] Create `eddy-slidefactory` repository
- [ ] Set up `pyproject.toml` with core dependency
- [ ] Create Eddy branding assets in `eddy_branding/`
- [ ] Create Eddy environment configuration (`.env.eddy`)
- [ ] Create Eddy docker-compose.yml for Coolify
- [ ] Create Eddy Dockerfile
- [ ] Test Eddy deployment locally
- [ ] Prepare Coolify deployment guide
- [ ] Update Eddy README and documentation

**Week 4: Testing & Validation**
- [ ] Full integration test: S5 Azure deployment
- [ ] Full integration test: Eddy Docker deployment
- [ ] Test core version upgrade path (v1.0.0 → v1.0.1)
- [ ] Verify issue tracking works separately
- [ ] Document version upgrade process
- [ ] Create migration announcement for clients

### 4.2 Installing from GitHub Packages

**Configure pip authentication:**

Create `~/.pypirc`:
```ini
[distutils]
index-servers =
    github

[github]
repository = https://upload.github.com/pypi/YOUR_ORG/
username = YOUR_GITHUB_USERNAME
password = YOUR_GITHUB_PERSONAL_ACCESS_TOKEN

Or use environment variable:

export PIP_INDEX_URL=https://YOUR_GITHUB_TOKEN@github.com/pypi/YOUR_ORG/simple/

Install in client repos:

pip install slidefactory-core==1.0.0 --index-url https://${GITHUB_TOKEN}@github.com/pypi/YOUR_ORG/simple/

4.3 Version Update Workflow

When core has updates:

  1. Core Repo: Create new release

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

  2. Client Repo: Update dependency

    cd s5-slidefactory
    # Edit pyproject.toml
    dependencies = [
        "slidefactory-core==1.1.0",  # Update version
    ]
    pip install -e .
    # Test locally
    git commit -am "chore: upgrade slidefactory-core to v1.1.0"
    git push
    

4.4 Rollback Strategy

If core update breaks client:

# In client repo (e.g., s5-slidefactory)
# Edit pyproject.toml
dependencies = [
    "slidefactory-core==1.0.0",  # Roll back to previous version
]

pip install -e . --force-reinstall

# Test
# If working, commit
git commit -am "fix: rollback slidefactory-core to v1.0.0"
git push

If core release has issues:

# In core repo
git tag -d v1.1.0  # Delete local tag
git push --delete origin v1.1.0  # Delete remote tag

# Fix issues, create new release
git tag v1.1.1
git push --tags

Phase 5: Documentation & Communication

5.1 Developer Documentation

For Core Contributors: - How to add new features to core - How to test changes - How to create releases - Breaking change policy - Semantic versioning guidelines

For Client Deployers: - How to upgrade core version - How to override templates/styles - How to configure environment - How to deploy to target platform - Troubleshooting guide

5.2 Breaking Change Policy

Semantic Versioning Rules:

  • MAJOR (x.0.0): Breaking changes
  • Database schema changes requiring migrations
  • Removed APIs or configuration options
  • Changed behavior that breaks existing workflows
  • Action: Clients must review changelog and test before upgrading

  • MINOR (1.x.0): New features (backwards compatible)

  • New APIs, endpoints, features
  • New configuration options (with defaults)
  • Deprecation warnings (features will be removed in next major)
  • Action: Clients can upgrade with low risk

  • PATCH (1.0.x): Bug fixes

  • Security patches
  • Bug fixes that don't change behavior
  • Documentation updates
  • Action: Clients should upgrade as soon as possible

5.3 Changelog Format

CHANGELOG.md in core:

# Changelog

All notable changes to slidefactory-core will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Feature in progress

## [1.1.0] - 2025-12-01

### Added
- New API endpoint for batch presentation generation
- Support for custom fonts in presentations
- CLI command for bulk template upload

### Changed
- Improved AI provider selection logic
- Enhanced error messages for storage failures

### Deprecated
- `LEGACY_AUTH_MODE` configuration option (will be removed in v2.0.0)

### Fixed
- Fixed race condition in Celery task queue
- Fixed memory leak in image processing

## [1.0.0] - 2025-11-18

### Added
- Initial release
- Core FastAPI application
- AI provider integration (OpenAI, Azure, Mistral, Anthropic, Ollama)
- N8N workflow integration
- Document processing with vector search
- Multi-cloud storage (MinIO, Azure)
- CLI tool
- Database migrations with Alembic

Benefits Realized

For You (Core Maintainer)

  1. Single Source of Truth: One codebase to maintain
  2. Version Control: Clients choose when to upgrade
  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

For Clients (S5, Eddy)

  1. Isolated Issues: Each client has own issue tracker
  2. Custom Branding: Complete control over look and feel
  3. Independent Deployments: Deploy on their schedule
  4. Stable Versions: Pin to tested versions, upgrade when ready
  5. Clear Support: Know where to report issues (core vs. client)

Technical Benefits

  1. Separation of Concerns: Core logic vs. deployment config
  2. Testability: Core tests don't need Azure/Coolify setup
  3. Reusability: Add new clients easily
  4. Scalability: Core improvements benefit all clients
  5. Security: Client-specific secrets stay in client repos

Risks & Mitigations

Risk 1: Breaking Changes in Core

Mitigation: - Strict semantic versioning - Comprehensive changelog - Deprecation warnings before removal - Beta releases for major versions

Risk 2: Version Conflicts

Mitigation: - Pin exact versions in client repos - Test upgrades in preview environments first - Document upgrade path in release notes

Risk 3: Divergent Client Needs

Mitigation: - Keep core flexible with configuration - Use feature flags for optional functionality - Client-specific features stay in client repos

Risk 4: Deployment Complexity

Mitigation: - Clear documentation for each deployment type - Example configurations for common scenarios - Automated deployment via GitHub Actions

Risk 5: Authentication to GitHub Packages

Mitigation: - Use GitHub Actions secrets for CI/CD - Document PAT setup for local development - Consider self-hosted PyPI if issues arise


Next Steps

  1. Review this plan with stakeholders
  2. Set up GitHub Packages authentication
  3. Create core repository and initial structure
  4. Test publishing a v0.1.0-alpha release
  5. Create S5 client repo and test integration
  6. Validate deployment to Azure preview
  7. Create Eddy client repo once S5 is stable
  8. Document lessons learned during migration

Questions to Answer Before Starting

  1. GitHub Organization: Which GitHub org will host these repos?
  2. Repository Names: Confirm names: slidefactory-core, s5-slidefactory, eddy-slidefactory?
  3. Access Control: Who needs access to each repo?
  4. GitHub Packages: Public or private package registry?
  5. Initial Version: Start at v1.0.0 or v0.1.0?
  6. Migration Timeline: When to start? How long for each phase?
  7. Rollback Plan: How to handle if migration fails?
  8. Communication: How to inform users of S5 about the change?

Conclusion

This separation provides a clean, maintainable architecture that scales as you add more clients. The Python package approach is industry-standard, well-supported by tooling, and provides the control you need while giving clients the isolation they want.

Estimated Effort: - Core package setup: 2-3 days - S5 client migration: 1-2 days - Eddy client setup: 1-2 days - Testing & documentation: 2-3 days - Total: 1-2 weeks

Complexity Assessment: Medium-high complexity migration, but the long-term benefits significantly outweigh the initial effort. The architecture will pay dividends as you add more clients and maintain the core platform.