Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b19ad5c
Initial prompt for Claude Code
lucwollants Jan 29, 2026
a4c379e
Add rules about security
lucwollants Jan 29, 2026
28fbf6f
Structure documentation inside the docs folder to make CLAUDE.md ligh…
lucwollants Jan 29, 2026
17e985e
Only enable Claude review manually for now
lucwollants Jan 29, 2026
d218825
Move the review guidelines to a dedicated document
lucwollants Jan 29, 2026
cd985ac
Add guidelines about small commits and human review
lucwollants Jan 29, 2026
84d4748
Remove meaningless comments
lucwollants Jan 29, 2026
3f2fe83
Skip praise
lucwollants Jan 29, 2026
c4af643
Reference the doc folder
lucwollants Jan 29, 2026
cb1a733
Remove the steps AI already knows/does
lucwollants Jan 29, 2026
d440f40
Add a domain file to describe key concepts of UDB3
lucwollants Jan 29, 2026
4533209
Add extra commands on how to execute features
lucwollants Jan 29, 2026
b274e86
Add extra URLs that can be used to verify results
lucwollants Jan 29, 2026
a7a7f80
Remove redundant data
lucwollants Jan 29, 2026
bd2f0bb
Rename refactor to features
lucwollants Jan 29, 2026
05c9fa5
Split SAPI3 into specific files
lucwollants Jan 29, 2026
2a1a6d3
Fix broken link
lucwollants Jan 29, 2026
2e1e5f3
Manual review and cleanup
lucwollants Jan 29, 2026
f158c30
Merge branch 'master' into claude-code-prompt
lucwollants Jan 30, 2026
1270576
Add guidelines for commenting code as less as possible
lucwollants Feb 2, 2026
b8e75da
Tweak coding guidelines order
lucwollants Feb 2, 2026
c4c547a
Add rule for naming exceptions
lucwollants Feb 2, 2026
53609a0
Improve commit guidelines
lucwollants Feb 2, 2026
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
82 changes: 5 additions & 77 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,17 @@ name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]

jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
if: contains(github.event.comment.body, '@claude')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read # Required for Claude to read CI results on PRs
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@v5
Expand All @@ -35,76 +25,14 @@ jobs:
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

# Enable progress tracking
track_progress: true

# Your custom review instructions
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }}
Review this pull request and provide inline feedback using the GitHub review system. Follow these steps:
1. Start a review: Use `mcp__github__create_pending_pull_request_review` to start a pending review.
2. Get diff information: Use `mcp__github__get_pull_request_diff` to see the code changes and line numbers.
- If the pull request has many changes, paginate the diff using the `page` and `per_page` parameters.
- Example: To get the first 100 lines, call `mcp__github__get_pull_request_diff` with `per_page=100` and `page=1`. For the next 100 lines, use `page=2`, and so on.
- Continue fetching pages until all changes are retrieved.
3. Add inline comments: Use `mcp__github__add_comment_to_pending_review` to provide feedback on specific lines of code snippets.
- **When suggesting code changes, format them as GitHub suggestion blocks so they can be committed directly:**
- For single-line suggestions, use:
```suggestion
suggested code here
```
- For multi-line suggestions, use:
```suggestion:-0+1
suggested code here
```
(Adjust the numbers to match how many lines to remove and add)
- Only provide suggestion blocks when you have a concrete, actionable fix
- Include explanation text before or after the suggestion block
4. Submit for review: Use `mcp__github__submit_pending_pull_request_review` with the event type set to "COMMENT" (not "REQUEST_CHANGES") to publish all comments for non-blocking review.
Focus on the following focus areas:
1. **Code Quality**
- Clean code principles and best practices
- Proper error handling and edge cases
- Code readability and maintainability
- **Provide suggestion blocks for improvements when possible**
2. **Security**
- Check for potential security vulnerabilities
- Validate input sanitization
- Review authentication/authorization logic
- **Suggest secure alternatives with suggestion blocks**
3. **Performance**
- Identify potential performance bottlenecks
- Review database queries for efficiency
- Check for memory leaks or resource issues
- **Offer optimized code via suggestion blocks**
4. **Testing**
- Verify adequate test coverage
- Review test quality and edge cases
- Check for missing test scenarios
5. **Documentation**
- Ensure code is properly documented
- Verify README updates for new features
- Check API documentation accuracy
Provide detailed feedback using inline comments for specific issues.
Use suggestion blocks liberally to make it easy for developers to apply fixes.
Use top-level comments for general observations or praise.
# Tools for comprehensive PR review
Review this pull request following the guidelines in docs/review-guidelines.md.
Provide detailed inline feedback using suggestion blocks where applicable.
claude_args: |
--allowedTools "mcp__github__get_pull_request,mcp__github__create_pending_pull_request_review,mcp__github__add_comment_to_pending_review,mcp__github__submit_pending_pull_request_review,mcp__github__get_pull_request_diff"
# When track_progress is enabled:
# - Creates a tracking comment with progress checkboxes
# - Includes all PR context (comments, attachments, images)
# - Updates progress as the review proceeds
# - Marks as completed when done
25 changes: 25 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# UDB3 Backend

UiTdatabank 3 core application - an event-sourced backend built with Broadway.

## Quick Reference

| Task | Command |
|------|---------|
| Verify all changes | `make ci` |
| Run unit tests | `make test` |
| Run specific test | `make test-filter filter=ClassName` |
| Fix code style | `make cs-fix` |
| Start environment | `make up` |
| Shell access | `make bash` |

## Documentation

- [Architecture](docs/architecture.md) - System design, tech stack, message flow
- [Coding Guidelines](docs/coding-guidelines.md) - Code style, conventions, security
- [Commands](docs/commands.md) - All available make commands
- [Review Guidelines](docs/review-guidelines.md) - PR review process and focus areas

## Refactoring Plans

- [SAPI3 Acceptance Tests](docs/refactor/sapi3-acceptance-tests.md) - Search integration test improvements
87 changes: 87 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Architecture

UiTdatabank 3 (UDB3) is an event-sourced backend built with Broadway.

## Tech Stack

- **Language**: PHP 8.1+
- **Architecture**: Event Sourcing with [Broadway](https://github.com/broadway/broadway)
- **Database**: Doctrine DBAL
- **Message Broker**: RabbitMQ (AMQP)
- **Search**: SAPI3 (external Elasticsearch-based service)
- **Cache**: Redis
- **Testing**: PHPUnit (unit), Behat (acceptance)
- **Quality**: PHPStan (static analysis), PHP-CS-Fixer (code style)
- **Environment**: Docker with docker-compose

## Project Structure

```
├── app/ # Service providers and application wiring
├── src/ # Core domain code
├── tests/ # PHPUnit tests (mirrors src/ structure)
├── features/ # Behat acceptance tests
├── docker/ # Docker configuration
├── docs/ # Documentation
│ └── refactor/ # Refactoring plans and progress
└── vendor/ # Dependencies (never modify)
```

## Event Sourcing with Broadway

- **Aggregates**: Domain objects that emit events (in `src/`)
- **Projectors**: Build read models from events
- **Event Bus**: Distributes events to handlers

## Message Flow: Domain Events to Search Indexing

```
1. API Request (e.g., Create Event)
2. Command Handler processes command
3. Domain event created (e.g., EventCreated)
4. EventBus publishes event to subscribers
5. Projectors generate JSON-LD → emit *ProjectedToJSONLD events
6. AMQPPublisher sends message to RabbitMQ
7. External SAPI3 consumes message and indexes in Elasticsearch
```

### AMQP Configuration

- **Exchange**: `udb3.x.domain-events`
- **Routing**: Messages routed to `api`, `cli`, or `related` queues based on context
- **Message Types**:
- `application/vnd.cultuurnet.udb3-events.event-projected-to-jsonld+json`
- `application/vnd.cultuurnet.udb3-events.place-projected-to-jsonld+json`
- `application/vnd.cultuurnet.udb3-events.organizer-projected-to-jsonld+json`

### SAPI3 Integration

SAPI3 is an external search service (Elasticsearch-based) that:
- Consumes messages from RabbitMQ
- Indexes events, places, and organizers
- Provides search endpoints proxied by UDB3

**Configuration** (in `config.php`):
- Base URL: `http://search.uitdatabank.local:80`
- API Key: configured per environment

**Search Endpoints** (proxy to SAPI3):
- `/events` - Search events
- `/places` - Search places
- `/organizers` - Search organizers

## Docker Services

| Service | Port | Purpose |
|---------|------|---------|
| PHP | 80 | Application |
| MySQL | 3306 | Database |
| Redis | 6379 | Cache |
| RabbitMQ | 5672, 15672 | Message broker (AMQP, Management UI) |
| Mailpit | 1025, 8025 | Email testing (SMTP, Web UI) |
96 changes: 96 additions & 0 deletions docs/coding-guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Coding Guidelines

## General

- Use `final` classes by default
- Follow PSR-4 autoloading under `CultuurNet\UDB3\` namespace
- Keep classes small and focused (Single Responsibility)

## PHP 8.1 Features

Use **readonly properties** with constructor promotion for immutable class properties.

See `src/Doctrine/DBALDatabaseConnectionChecker.php` for an example.

> **Note**: Do NOT use PHP 8.2 `readonly class` syntax - we're on PHP 8.1.

## Testing

- Use `@test` annotation style for test methods
- Mock objects use intersection types: `Connection&MockObject`
- Prefer separate test methods over data providers for clarity
- Test file location mirrors source: `src/Foo/Bar.php` → `tests/Foo/BarTest.php`

## Naming

- Interfaces: Descriptive name without `Interface` suffix (e.g., `DatabaseConnectionChecker`)
- Implementations: Prefix with technology (e.g., `DBALDatabaseConnectionChecker`)

## Gotchas & Pitfalls

| Issue | Solution |
|-------|----------|
| Commands fail outside Docker | Use `make` commands, not direct `composer` calls |
| `withConsecutive` deprecation | Avoid in new tests - use separate test methods |
| Uppercase `String` type hint | Legacy code - don't "fix" these |
| Tests fail after changes | Run `make ci` before committing |

## Restrictions

- **Never** modify files in `vendor/`
- **Never** commit `.env` or credentials files
- **Avoid** creating new service providers - extend existing ones in `app/`
- **Avoid** adding dependencies without team discussion
- **Always** run `make ci` before considering work complete

## AI Restrictions

- **Never** create commits - only humans commit code
- **Plan** larger changes but implement step by step, waiting for human review between steps

## Dependency Injection

- Service providers in `app/` wire all dependencies
- Use **constructor injection**, not service locators
- Extract testable logic into separate classes with **interfaces**

See `src/Doctrine/DatabaseConnectionChecker.php` and `src/Doctrine/DBALDatabaseConnectionChecker.php` for an example of interface + implementation pattern.

## Workflow

- **Small commits**: One logical change per commit
- **Small pull requests**: Easier to review, faster to merge
- **Feature flags**: Deploy often, enable features when ready

## Preferences

When working on this codebase, prefer:

- Extracting logic into testable classes with interfaces over inline implementation
- Constructor injection over service locator patterns
- Explicit code over clever abstractions
- Integration with existing patterns over introducing new ones

## Security

### Never Commit

- `.env` files or environment-specific configurations
- API keys, tokens, or credentials
- Private keys or certificates
- Database connection strings with passwords
- Any hardcoded secrets

### Configuration

- Secrets belong in environment variables, not in code
- Use `.env.example` or `.env.dist` for documenting required env vars (without actual values)
- Configuration files with secrets should be in `.gitignore`

### Secure Coding

- No hardcoded credentials or secrets in code
- No sensitive data in log statements
- Validate input on user-provided data
- SQL queries use parameterized statements (handled by Doctrine DBAL)
- No sensitive data exposure in error messages
64 changes: 64 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Commands

> **Important**: Always use `make` commands, not direct `composer` or `vendor/bin` calls. The project runs in Docker.

## Quick Reference

| Task | Command |
|------|---------|
| Verify all changes | `make ci` |
| Run unit tests | `make test` |
| Run specific test | `make test-filter filter=ClassName` |
| Fix code style | `make cs-fix` |
| Start environment | `make up` |
| Shell access | `make bash` |

## Environment Management

```bash
make up # Start containers
make down # Stop containers
make bash # Shell into PHP container
make install # Install composer dependencies
make migrate # Run database migrations
make init # Install + migrate (fresh setup)
```

## Quality Assurance

```bash
make ci # Run ALL checks (PHPStan + tests + code style)
make stan # PHPStan static analysis only
make test # PHPUnit tests only
make cs # Code style check (dry-run)
make cs-fix # Auto-fix code style issues
```

## Unit Testing

```bash
make test # All unit tests
make test-filter filter=EventBusForwarding # Tests matching filter
make test-group group=integration # Tests in specific group
```

## Acceptance Testing (Behat)

```bash
make feature # All feature tests
make feature-tag tag=@events # Feature tests by tag
make feature-tag tag=@sapi3 # SAPI3 search integration tests
```

## AMQP Consumer

```bash
# Run message consumer (inside container)
php bin/console consume [consumer_name]
```

## Resources

- [Broadway Documentation](https://github.com/broadway/broadway)
- [Doctrine DBAL](https://www.doctrine-project.org/projects/dbal.html)
- [PHPStan](https://phpstan.org/)
Loading