From 09ebdb1b2a60c1dc6399f2febe28fb9a1f25c17a Mon Sep 17 00:00:00 2001 From: gamer147 Date: Wed, 26 Nov 2025 16:08:40 -0500 Subject: [PATCH] [FA-11] Cleanup --- .gitea/workflows/build-gateway.yml | 7 - Documentation/CICD.md | 201 ++++++++++++++++++++--------- docker-compose.yml | 38 ++---- 3 files changed, 147 insertions(+), 99 deletions(-) diff --git a/.gitea/workflows/build-gateway.yml b/.gitea/workflows/build-gateway.yml index 0964c41..868f992 100644 --- a/.gitea/workflows/build-gateway.yml +++ b/.gitea/workflows/build-gateway.yml @@ -3,15 +3,8 @@ name: Build Gateway on: workflow_dispatch: push: - branches: - - master tags: - 'v*.*.*' - paths: - - 'FictionArchive.Service.*/**' - - 'FictionArchive.Common/**' - - 'FictionArchive.Service.Shared/**' - - 'FictionArchive.API/**' env: REGISTRY: ${{ gitea.server_url }} diff --git a/Documentation/CICD.md b/Documentation/CICD.md index a2f9c6e..d42b958 100644 --- a/Documentation/CICD.md +++ b/Documentation/CICD.md @@ -7,9 +7,9 @@ This document describes the CI/CD pipeline configuration for FictionArchive usin | Workflow | File | Trigger | Purpose | |----------|------|---------|---------| | CI | `build.yml` | Push/PR to master | Build and test all projects | -| Build Subgraphs | `build-subgraphs.yml` | Push to master (service changes) | Build GraphQL subgraph packages | -| Build Gateway | `build-gateway.yml` | Manual or triggered by subgraphs | Compose gateway and build Docker image | +| Build Gateway | `build-gateway.yml` | Tag `v*.*.*` or manual | Build subgraphs, compose gateway, push API image | | Release | `release.yml` | Tag `v*.*.*` | Build and push all Docker images | +| Claude PR Assistant | `claude_assistant.yml` | Issue/PR comments with @claude | AI-assisted code review and issue handling | ## Pipeline Architecture @@ -18,27 +18,32 @@ This document describes the CI/CD pipeline configuration for FictionArchive usin │ Push to master │ └─────────────────────────────┬───────────────────────────────────────┘ │ - ┌───────────────┴───────────────┐ - ▼ ▼ -┌─────────────────────────┐ ┌─────────────────────────┐ -│ build.yml │ │ build-subgraphs.yml │ -│ (CI checks - always) │ │ (if service changes) │ -└─────────────────────────┘ └────────────┬────────────┘ - │ - ▼ - ┌─────────────────────────┐ - │ build-gateway.yml │ - │ (compose & push API) │ - └─────────────────────────┘ + ▼ + ┌─────────────────────────┐ + │ build.yml │ + │ (CI checks) │ + └─────────────────────────┘ ┌─────────────────────────────────────────────────────────────────────┐ │ Push tag v*.*.* │ +└─────────────────────────────┬───────────────────────────────────────┘ + │ + ┌───────────────┴───────────────┐ + ▼ ▼ +┌─────────────────────────┐ ┌─────────────────────────┐ +│ release.yml │ │ build-gateway.yml │ +│ (build & push all │ │ (build subgraphs & │ +│ backend + frontend) │ │ push API gateway) │ +└─────────────────────────┘ └─────────────────────────┘ + +┌─────────────────────────────────────────────────────────────────────┐ +│ Issue/PR comment containing @claude │ └─────────────────────────────┬───────────────────────────────────────┘ │ ▼ ┌─────────────────────────┐ - │ release.yml │ - │ (build & push all) │ + │ claude_assistant.yml │ + │ (AI code assistance) │ └─────────────────────────┘ ``` @@ -51,14 +56,15 @@ Configure these in **Settings → Actions → Secrets**: | Secret | Description | Required By | |--------|-------------|-------------| | `REGISTRY_TOKEN` | Gitea access token with `write:package` scope | `release.yml`, `build-gateway.yml` | -| `GITEA_TOKEN` | Gitea access token for API calls | `build-subgraphs.yml` | +| `CLAUDE_CODE_OAUTH_TOKEN` | Claude Code OAuth token | `claude_assistant.yml` | +| `CLAUDE_GITEA_TOKEN` | Gitea token for Claude assistant | `claude_assistant.yml` | #### Creating Access Tokens 1. Go to **Settings → Applications → Access Tokens** 2. Create a new token with the following scopes: - `write:package` - Push container images - - `write:repository` - Trigger workflows via API + - `write:repository` - For Claude assistant to push commits 3. Copy the token and add it as a repository secret ### Repository Variables @@ -85,42 +91,62 @@ Configure these in **Settings → Actions → Variables**: **Requirements:** - .NET 8.0 SDK -- Python 3.12 - Node.js 20 -- HotChocolate Fusion CLI -### Build Subgraphs (`build-subgraphs.yml`) +**Steps (Backend):** +1. Checkout repository +2. Setup .NET 8.0 +3. Restore dependencies +4. Build solution (Release, with `SkipFusionBuild=true`) +5. Run tests -**Trigger:** Push to `master` with changes in: -- `FictionArchive.Service.*/**` -- `FictionArchive.Common/**` -- `FictionArchive.Service.Shared/**` - -**Jobs:** -1. `build-subgraphs` - Matrix job building each service's `.fsp` package -2. `trigger-gateway` - Triggers gateway rebuild via API - -**Subgraphs Built:** -- Novel Service -- Translation Service -- Scheduler Service -- User Service -- File Service - -**Artifacts:** Each subgraph produces a `.fsp` file retained for 30 days. +**Steps (Frontend):** +1. Checkout repository +2. Setup Node.js 20 +3. Install dependencies (`npm ci`) +4. Run linter (`npm run lint`) +5. Build application (`npm run build`) ### Build Gateway (`build-gateway.yml`) **Trigger:** - Manual dispatch (`workflow_dispatch`) -- Push to `master` with changes in `FictionArchive.API/**` -- Triggered by `build-subgraphs.yml` completion +- Push tag matching `v*.*.*` -**Process:** -1. Downloads all subgraph `.fsp` artifacts -2. Configures Docker-internal URLs for each subgraph -3. Composes gateway schema using Fusion CLI -4. Builds and pushes API Docker image +**Jobs:** + +#### 1. `build-subgraphs` (Matrix Job) +Builds GraphQL subgraph packages for each service: + +| Service | Project | Subgraph Name | +|---------|---------|---------------| +| novel-service | FictionArchive.Service.NovelService | Novel | +| translation-service | FictionArchive.Service.TranslationService | Translation | +| scheduler-service | FictionArchive.Service.SchedulerService | Scheduler | +| user-service | FictionArchive.Service.UserService | User | + +**Note:** File Service and Authentication Service are not subgraphs (no GraphQL schema). + +**Steps:** +1. Checkout repository +2. Setup .NET 8.0 +3. Install HotChocolate Fusion CLI +4. Restore and build service project +5. Export GraphQL schema (`schema export`) +6. Pack subgraph into `.fsp` file +7. Upload artifact (retained 30 days) + +#### 2. `build-gateway` (Depends on `build-subgraphs`) +Composes the API gateway from subgraph packages. + +**Steps:** +1. Checkout repository +2. Setup .NET 8.0 and Fusion CLI +3. Download all subgraph artifacts +4. Configure Docker-internal URLs (`http://{service}-service:8080/graphql`) +5. Compose gateway schema using Fusion CLI +6. Build gateway project +7. Build and push Docker image **Image Tags:** - `//fictionarchive-api:latest` @@ -131,23 +157,54 @@ Configure these in **Settings → Actions → Variables**: **Trigger:** Push tag matching `v*.*.*` (e.g., `v1.0.0`) **Jobs:** -1. `build-and-push` - Matrix job building all backend service images -2. `build-frontend` - Builds and pushes frontend image -**Services Built:** -- `fictionarchive-api` -- `fictionarchive-novel-service` -- `fictionarchive-user-service` -- `fictionarchive-translation-service` -- `fictionarchive-file-service` -- `fictionarchive-scheduler-service` -- `fictionarchive-authentication-service` -- `fictionarchive-frontend` +#### 1. `build-and-push` (Matrix Job) +Builds and pushes all backend service images: + +| Service | Dockerfile | +|---------|------------| +| novel-service | FictionArchive.Service.NovelService/Dockerfile | +| user-service | FictionArchive.Service.UserService/Dockerfile | +| translation-service | FictionArchive.Service.TranslationService/Dockerfile | +| file-service | FictionArchive.Service.FileService/Dockerfile | +| scheduler-service | FictionArchive.Service.SchedulerService/Dockerfile | +| authentication-service | FictionArchive.Service.AuthenticationService/Dockerfile | + +#### 2. `build-frontend` +Builds and pushes the frontend image with environment-specific build arguments. + +**Build Args:** +- `VITE_GRAPHQL_URI` +- `VITE_OIDC_AUTHORITY` +- `VITE_OIDC_CLIENT_ID` +- `VITE_OIDC_REDIRECT_URI` +- `VITE_OIDC_POST_LOGOUT_REDIRECT_URI` **Image Tags:** - `//fictionarchive-:` - `//fictionarchive-:latest` +### Claude PR Assistant (`claude_assistant.yml`) + +**Trigger:** Comments or issues containing `@claude`: +- Issue comments +- Pull request review comments +- Pull request reviews +- New issues (opened or assigned) + +**Permissions Required:** +- `contents: write` +- `pull-requests: write` +- `issues: write` +- `id-token: write` + +**Usage:** +Mention `@claude` in any issue or PR comment to invoke the AI assistant for: +- Code review assistance +- Bug analysis +- Implementation suggestions +- Documentation help + ## Container Registry Images are pushed to the Gitea Container Registry at: @@ -155,6 +212,19 @@ Images are pushed to the Gitea Container Registry at: //fictionarchive-: ``` +### Image Naming Convention + +| Image | Description | +|-------|-------------| +| `fictionarchive-api` | API Gateway (GraphQL Federation) | +| `fictionarchive-novel-service` | Novel Service | +| `fictionarchive-user-service` | User Service | +| `fictionarchive-translation-service` | Translation Service | +| `fictionarchive-file-service` | File Service | +| `fictionarchive-scheduler-service` | Scheduler Service | +| `fictionarchive-authentication-service` | Authentication Service | +| `fictionarchive-frontend` | Web Frontend | + ### Pulling Images ```bash @@ -184,13 +254,13 @@ docker pull //fictionarchive-api:latest - Ensure the `REGISTRY_TOKEN` secret is configured in repository settings - Verify the token has `write:package` scope -**"Failed to trigger gateway workflow"** -- Ensure `GITEA_TOKEN` secret is configured -- Verify the token has `write:repository` scope - **"No subgraph artifacts found"** -- The gateway build requires subgraph artifacts from a previous `build-subgraphs` run -- Trigger `build-subgraphs.yml` manually or push a change to a service +- The gateway build requires subgraph artifacts from the `build-subgraphs` job +- If subgraph builds failed, check the matrix job logs for errors + +**"Schema export failed"** +- Ensure the service project has a valid `subgraph-config.json` +- Check that the service starts correctly for schema export ### Frontend Build Failures @@ -204,6 +274,13 @@ docker pull //fictionarchive-api:latest - Verify `REGISTRY_TOKEN` has correct permissions - Check that the token hasn't expired +### Claude Assistant Failures + +**"Claude assistant not responding"** +- Verify `CLAUDE_CODE_OAUTH_TOKEN` is configured +- Verify `CLAUDE_GITEA_TOKEN` is configured and has write permissions +- Check that the comment contains `@claude` mention + ## Local Testing To test workflows locally before pushing: diff --git a/docker-compose.yml b/docker-compose.yml index 91f0e5c..c3c26d9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,9 +34,7 @@ services: # Backend Services # =========================================== novel-service: - build: - context: . - dockerfile: FictionArchive.Service.NovelService/Dockerfile + image: git.orfl.xyz/conco/fictionarchive-novel-service:latest environment: ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_NovelService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq @@ -51,9 +49,7 @@ services: restart: unless-stopped translation-service: - build: - context: . - dockerfile: FictionArchive.Service.TranslationService/Dockerfile + image: git.orfl.xyz/conco/fictionarchive-translation-service:latest environment: ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_TranslationService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq @@ -66,9 +62,7 @@ services: restart: unless-stopped scheduler-service: - build: - context: . - dockerfile: FictionArchive.Service.SchedulerService/Dockerfile + image: git.orfl.xyz/conco/fictionarchive-scheduler-service:latest environment: ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_SchedulerService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq @@ -80,9 +74,7 @@ services: restart: unless-stopped user-service: - build: - context: . - dockerfile: FictionArchive.Service.UserService/Dockerfile + image: git.orfl.xyz/conco/fictionarchive-user-service:latest environment: ConnectionStrings__DefaultConnection: Host=postgres;Database=FictionArchive_UserService;Username=${POSTGRES_USER:-postgres};Password=${POSTGRES_PASSWORD:-postgres} ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq @@ -94,9 +86,7 @@ services: restart: unless-stopped authentication-service: - build: - context: . - dockerfile: FictionArchive.Service.AuthenticationService/Dockerfile + image: git.orfl.xyz/conco/fictionarchive-authentication-service:latest environment: ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq depends_on: @@ -105,9 +95,7 @@ services: restart: unless-stopped file-service: - build: - context: . - dockerfile: FictionArchive.Service.FileService/Dockerfile + image: git.orfl.xyz/conco/fictionarchive-file-service:latest environment: ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq S3__Endpoint: ${S3_ENDPOINT:-https://s3.orfl.xyz} @@ -130,9 +118,7 @@ services: # API Gateway # =========================================== api-gateway: - build: - context: . - dockerfile: FictionArchive.API/Dockerfile + image: git.orfl.xyz/conco/fictionarchive-api:latest environment: ConnectionStrings__RabbitMQ: amqp://${RABBITMQ_USER:-guest}:${RABBITMQ_PASSWORD:-guest}@rabbitmq labels: @@ -154,15 +140,7 @@ services: # Frontend # =========================================== frontend: - build: - context: ./fictionarchive-web - dockerfile: Dockerfile - args: - VITE_GRAPHQL_URI: https://api.fictionarchive.orfl.xyz/graphql/ - VITE_OIDC_AUTHORITY: ${OIDC_AUTHORITY:-https://auth.orfl.xyz/application/o/fiction-archive/} - VITE_OIDC_CLIENT_ID: ${OIDC_CLIENT_ID} - VITE_OIDC_REDIRECT_URI: https://fictionarchive.orfl.xyz/ - VITE_OIDC_POST_LOGOUT_REDIRECT_URI: https://fictionarchive.orfl.xyz/ + image: git.orfl.xyz/conco/fictionarchive-frontend:latest labels: - "traefik.enable=true" - "traefik.http.routers.frontend.rule=Host(`fictionarchive.orfl.xyz`)"