Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"env": {
"COMPOSE_USER": "deploy"
},
"permissions": {
"allow": [
"Bash(cat:*)",
"Bash(diff:*)",
"Bash(echo:*)",
"Bash(find:*)",
"Bash(gh:*)",
"Bash(git:*)",
"Bash(grep:*)",
"Bash(head:*)",
"Bash(ls:*)",
"Bash(pwd)",
"Bash(tail:*)",
"Bash(task:*)",
"Bash(tree:*)",
"Bash(wc:*)",
"Bash(which:*)",
"Bash(docker compose exec:*)",
"Bash(docker compose run:*)",
"Bash(docker compose up:*)",
"Bash(docker compose ps:*)",
"Bash(docker compose logs:*)",
"Bash(docker compose top:*)",
"Bash(docker compose config:*)",
"Bash(docker compose pull:*)",
"Bash(docker compose images:*)",
"Bash(docker network:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(gh issue delete:*)",
"Bash(gh release delete:*)",
"Bash(gh repo delete:*)",
"Bash(gh label delete:*)",
"Read(./.env.local)",
"Read(./.env.local.*)",
"Read(./config/secrets/*)"
],
"ask": [
"Bash(docker compose down:*)",
"Bash(docker compose stop:*)",
"Bash(docker compose rm:*)",
"Bash(docker compose restart:*)",
"Bash(gh issue create:*)",
"Bash(gh issue close:*)",
"Bash(gh issue edit:*)",
"Bash(gh issue comment:*)",
"Bash(gh pr create:*)",
"Bash(gh pr close:*)",
"Bash(gh pr merge:*)",
"Bash(gh pr edit:*)",
"Bash(gh pr comment:*)",
"Bash(gh pr review:*)",
"Bash(gh release create:*)",
"Bash(gh release edit:*)",
"Bash(gh repo create:*)",
"Bash(gh label create:*)",
"Bash(gh label edit:*)",
"Bash(git push:*)",
"Bash(git branch -d:*)",
"Bash(git branch -D:*)",
"Bash(git tag -d:*)",
"Bash(git tag -a:*)",
"Bash(git tag :*)",
"Bash(git reset:*)",
"Bash(git rebase:*)",
"Bash(git merge:*)",
"Bash(git stash drop:*)",
"Bash(git clean:*)",
"Bash(git checkout -- :*)",
"Bash(git restore:*)",
"Bash(git commit:*)"
]
},
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "docker compose up --detach --quiet-pull 2>/dev/null || true",
"timeout": 60,
"statusMessage": "Starting Docker services..."
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "case \"$CLAUDE_FILE_PATH\" in *.php) docker compose exec -T phpfpm vendor/bin/php-cs-fixer fix --quiet \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac",
"timeout": 30
},
{
"type": "command",
"command": "case \"$CLAUDE_FILE_PATH\" in *.php) docker compose exec -T phpfpm vendor/bin/phpstan analyse --no-progress --error-format=raw \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac",
"timeout": 30
},
{
"type": "command",
"command": "case \"$CLAUDE_FILE_PATH\" in *.twig) docker compose exec -T phpfpm vendor/bin/twig-cs-fixer lint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac",
"timeout": 15
},
{
"type": "command",
"command": "case \"$CLAUDE_FILE_PATH\" in */composer.json) docker compose exec -T phpfpm composer normalize --quiet 2>/dev/null || true ;; esac",
"timeout": 30
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "docker compose exec -T phpfpm bin/console lint:container 2>/dev/null || true",
"timeout": 30,
"statusMessage": "Validating Symfony DI container..."
}
]
}
]
},
"enabledPlugins": {
"php-lsp@claude-plugins-official": true,
"code-simplifier@claude-plugins-official": true,
"context7@claude-plugins-official": true,
"code-review@claude-plugins-official": true,
"security-guidance@claude-plugins-official": true,
"playwright@claude-plugins-official": true,
"feature-dev@claude-plugins-official": true,
"itkdev-skills@itkdev-marketplace": true
},
"alwaysThinkingEnabled": true,
"defaultMode": "acceptEdits"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think this should be the default behavior, it will not match all users workflow. The "alwaysThinkingEnabled" will burn tokens and time way to fast. It is better to do "ultrathink" when you need it.

}
15 changes: 15 additions & 0 deletions .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ jobs:
docker compose exec phpfpm bin/console messenger:setup-transports failed
docker compose exec phpfpm bin/console doctrine:schema:validate

phpstan:
runs-on: ubuntu-latest
name: PHPStan
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Create docker network
run: docker network create frontend

- name: Run PHPStan
run: |
docker compose run --rm phpfpm composer install --no-interaction
docker compose run --rm phpfpm vendor/bin/phpstan analyse

phpunit:
runs-on: ubuntu-latest
name: PHP Unit tests
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- [#58](https://github.com/itk-dev/devops_itksites/pull/58)
5002: Added export to everything
- [#62](https://github.com/itk-dev/devops_itksites/pull/62)
6869: Add agents.md and Claude Code configuration for AI coding agents

## [1.8.10] - 2025-07-02

Expand Down
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
[![Codecov](https://img.shields.io/codecov/c/github/itk-dev/devops_itksites?style=flat-square&logo=codecov)](https://codecov.io/gh/itk-dev/devops_itksites)
[![GitHub last commit](https://img.shields.io/github/last-commit/itk-dev/devops_itksites?style=flat-square)](https://github.com/itk-dev/devops_itksites/commits/develop/)
[![GitHub License](https://img.shields.io/github/license/itk-dev/devops_itksites?style=flat-square)](https://github.com/itk-dev/devops_itksites/blob/develop/LICENSE)
[![agents.md](https://img.shields.io/badge/%F0%9F%A4%96_agents.md-AI%20ready-8A2BE2?style=flat-square)](https://github.com/itk-dev/devops_itksites/blob/develop/agents.md)

This is our internal server and site registration tool. It works in tandem with our
[ITK sites server harvester](https://github.com/itk-dev/devops_itkServerHarvest).
Expand Down Expand Up @@ -130,3 +131,34 @@ during development to automatically rebuild assets when source files change.
```sh
docker compose run --rm node yarn coding-standards-check
```

### 🤖 AI coding agents

This project includes an [`agents.md`](agents.md) file that provides project
context for AI coding agents. The file describes the project architecture,
technology stack, development commands, CI/CD setup, and coding conventions.

`agents.md` is a vendor-neutral standard supported by tools such as
[Claude Code](https://claude.ai/claude-code),
[OpenCode](https://opencode.ai/), and others.

Tool-specific configuration (permissions, hooks, plugins) lives in `.claude/`
and is not portable across tools.

#### Claude Code plugins

The following plugins are enabled in `.claude/settings.json`:

| Plugin | Purpose | Source |
|---|---|---|
| `php-lsp` | PHP language server for type-aware code intelligence | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) |
| `context7` | Up-to-date documentation lookup for Symfony, Doctrine, API Platform, etc. | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) |
| `code-review` | Pull request code review | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) |
| `code-simplifier` | Suggests clarity and maintainability improvements | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) |
| `security-guidance` | Flags potential security issues (OWASP, injection, etc.) | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) |
| `playwright` | Browser automation for debugging and testing the EasyAdmin UI | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) |
| `feature-dev` | Guided feature development with codebase exploration and architecture focus | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) |

> **Note:** The `php-lsp` plugin requires [Intelephense](https://intelephense.com/)
> installed globally: `npm install -g intelephense`. All other plugins work
> without additional dependencies.
142 changes: 142 additions & 0 deletions claude.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# 🤖 Code Agents - DevOps ITKsites
Copy link
Contributor

@cableman cableman Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note this file is not read by claude, this is jetbrains only


## Project Overview

**DevOps ITKsites** is an internal Symfony application for server and site
registration/monitoring at ITK Dev. It receives `DetectionResults` from the
[ITK sites server harvester](https://github.com/itk-dev/devops_itkServerHarvest)
and processes them asynchronously to track servers, sites, domains, Docker
images, packages, modules, CVEs, and git repositories.

## Technology Stack

- **Language**: PHP 8.4+ (Symfony 7.3)
- **API**: API Platform 4.0 (REST)
- **Admin UI**: EasyAdmin 4.x
- **Database**: Doctrine ORM 3.x / DBAL 4.x with MariaDB
- **Messaging**: Symfony Messenger (AMQP/RabbitMQ)
- **Auth**: OpenID Connect (`itk-dev/openid-connect-bundle`)
- **Frontend**: Webpack Encore, Stimulus.js
- **Testing**: PHPUnit 11+
- **Code Quality**: PHP-CS-Fixer, PHPStan, Rector

## Architecture

```mermaid
graph TD
A[Harvester] -->|POST DetectionResult| B[API Platform REST endpoint]
B --> C[Symfony Messenger]
C --> D[Async Message Handlers]
D --> D1[DirectoryHandler]
D --> D2[DockerImageHandler]
D --> D3[DrupalHandler]
D --> D4[GitHandler]
D --> D5[NginxHandler]
D --> D6[SymfonyHandler]
D1 & D2 & D3 & D4 & D5 & D6 --> E[Doctrine ORM]
E --> F[MariaDB]
F --> G[EasyAdmin UI]
```

### Key Directories

| Directory | Purpose |
|---|---|
| `src/Entity/` | ~20 Doctrine entities (Server, Site, Domain, Installation, Package, DockerImage, Advisory, etc.) |
| `src/Handler/` | DetectionResult handlers (Directory, Docker, Drupal, Git, Nginx, Symfony) |
| `src/MessageHandler/` | Async message processing (PersistDetectionResult, ProcessDetectionResult) |
| `src/Admin/` | EasyAdmin CRUD controllers |
| `src/ApiResource/` | API Platform resource definitions |
| `src/Service/` | Factories (PackageVersion, ModuleVersion, Advisory) and export services |
| `src/Repository/` | Doctrine repositories |
| `config/packages/` | Bundle configurations |
| `migrations/` | Doctrine migrations |
| `fixtures/` | Hautelook/Alice test fixtures |
| `tests/` | PHPUnit tests (Api, Controller, MessageHandler) |

### Data Flow

All analyzed data (sites, installations, domains, packages, etc.) can be
truncated and rebuilt by replaying DetectionResults. Manually maintained data
(Servers, OIDC setups, Service Certificates) is separate and must be preserved.

## Development Environment

```sh
# Start services (MariaDB, PHP-FPM 8.4, Nginx, Mailpit)
docker compose pull && docker compose up --detach

# Install dependencies
docker compose exec phpfpm composer install

# Run migrations
docker compose exec phpfpm bin/console doctrine:migrations:migrate --no-interaction

# Load fixtures
docker compose exec phpfpm composer fixtures

# Login as admin (after fixtures)
docker compose exec phpfpm bin/console itk-dev:openid-connect:login admin@example.com

# Process message queues
docker compose exec phpfpm composer queues

# Build frontend assets
docker compose run --rm node yarn install && docker compose run --rm node yarn build
```

## Quality Checks

All commands run inside Docker containers:

```sh
# PHP coding standards (PHP-CS-Fixer)
docker compose exec phpfpm composer coding-standards-check
docker compose exec phpfpm composer coding-standards-apply

# PHPUnit tests (creates test DB, runs migrations, executes tests)
docker compose exec phpfpm composer tests

# Frontend coding standards
docker compose run --rm node yarn coding-standards-check

# API spec export (must be committed)
docker compose exec phpfpm composer update-api-spec
```

## CI/CD

### GitHub Actions (`pr.yaml`)

Pull requests run these checks:

1. **Composer validation** - validates and installs (prod + dev)
2. **Doctrine schema validation** - migrations + schema check against MariaDB
3. **PHP-CS-Fixer** - coding standards
4. **PHPUnit** - unit/integration tests with MariaDB
5. **API spec validation** - ensures exported OpenAPI spec is up to date
6. **Fixtures** - verifies fixtures load successfully
7. **Asset build** - verifies frontend assets compile
8. **Changelog** - ensures CHANGELOG.md is updated

### Woodpecker CI (deployment)

- `stg.yml` - Deploys to staging on push to develop
- `prod.yml` - Deploys to production on release (Ansible playbook, runs migrations + transport setup)

## PR Guidelines

- PRs must link to a ticket
- Code must pass all CI checks (tests, coding standards, static analysis)
- CHANGELOG.md must be updated
- UI changes require screenshots
- Base branch: `develop`

## Important Conventions

- Entity classes extend `AbstractBaseEntity` (provides `id`, `createdAt`, `updatedAt`)
- Detection handlers implement `DetectionResultHandlerInterface`
- Handlers are auto-tagged and injected via tagged iterator in `services.yaml`
- Async processing uses Symfony Messenger with AMQP transport
- Environment-specific config goes in `.env.local` (not committed)
- API specs (`public/api-spec-v1.yaml` and `.json`) must be regenerated and committed when API changes
2 changes: 1 addition & 1 deletion docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ services:
environment:
- RABBITMQ_DEFAULT_USER=user
- RABBITMQ_DEFAULT_PASS=password
- RABBITMQ_ERLANG_COOKIE='d53f219cd9376f8f440aaf9889f315ab'
- RABBITMQ_ERLANG_COOKIE='local-dev-cookie-not-a-secret'
healthcheck:
test: rabbitmq-diagnostics check_port_connectivity
interval: 1s
Expand Down
Loading