Skip to content

Commit e0d9f81

Browse files
authored
Merge branch 'develop' into feature/issue-60-adr-user-approval
2 parents 443efb0 + b91aa5c commit e0d9f81

93 files changed

Lines changed: 7693 additions & 1320 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,7 @@ BRAND_NAME="AI Bibliotek"
3434
BRAND_TAGLINE="del & hjemtag assistenter"
3535
BRAND_INITIALS="AI"
3636
###< brand identity ###
37+
38+
###> doctrine/doctrine-bundle ###
39+
DATABASE_URL="mysql://db:db@mariadb:3306/db?serverVersion=10.11.16-MariaDB&charset=utf8mb4"
40+
###< doctrine/doctrine-bundle ###

.env.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
# define your env variables for the test env here
22
KERNEL_CLASS='App\Kernel'
33
APP_SECRET='$ecretf0rt3st'
4+
5+
DATABASE_URL="mysql://root:password@mariadb:3306/db_test?serverVersion=10.11.16-MariaDB&charset=utf8mb4"

.github/ISSUE_TEMPLATE/issue.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
name: Issue
3+
about: General issue template with a human summary and a detailed AI brief.
4+
title: ""
5+
labels: []
6+
assignees: []
7+
---
8+
# Resume
9+
10+
## Description
11+
12+
<!-- 1–3 sentences: what this issue is about and why it matters. -->
13+
14+
## Tasks
15+
16+
<!-- Concise checklist. One unit of work or acceptance criterion per item. -->
17+
18+
- [ ]
19+
- [ ]
20+
- [ ]
21+
22+
---
23+
24+
# Details - AI specificities
25+
26+
<!--
27+
Include anything that helps the agent act correctly:
28+
29+
- Goal and motivation (the "why").
30+
- Scope and explicit non-goals.
31+
- Relevant files, services, routes, or domain terms (link or path them).
32+
- Constraints: coding standards, ADRs, security/compliance requirements.
33+
- Inputs/outputs, data shapes, edge cases.
34+
- Acceptance criteria and how to verify (commands, URLs, fixtures).
35+
- Links to related issues, PRs, ADRs, or external docs.
36+
-->

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#### Links to issues
2+
3+
Please add links to github issues that this PR addresses.
4+
5+
#### Description
6+
7+
Please include a short description of the suggested change and the reasoning behind the approach you have chosen.
8+
9+
#### Screenshot of the result
10+
11+
If your change affects the user interface you should include a screenshot of the result with the pull request.
12+
13+
#### Checklist
14+
15+
- [ ] My code is covered by test cases.
16+
- [ ] My code passes our test (all our tests).
17+
- [ ] My code passes our static analysis suite.
18+
- [ ] My code passes our continuous integration process.
19+
20+
If your code does not pass all the requirements on the checklist you have to add a comment explaining why this change
21+
should be exempt from the list.
22+
23+
#### Additional comments or questions
24+
25+
If you have any further comments or questions for the reviewer please add them here.
26+
27+
---
28+
29+
# Details - AI specificities
30+
31+
<!--
32+
Detailed brief for AI assistants reviewing or following up on this PR.
33+
Include anything that isn't obvious from the diff:
34+
35+
- Goal and motivation (the "why").
36+
- Scope and explicit non-goals.
37+
- Architectural decisions, ADRs referenced, or conventions applied.
38+
- Trade-offs considered and why this approach was chosen.
39+
- Areas needing extra scrutiny (security, performance, migrations).
40+
- Follow-up work intentionally left out of this PR.
41+
- Links to related issues, PRs, ADRs, or external docs.
42+
-->

.github/workflows/tests.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ jobs:
2222
- name: Build Tailwind CSS
2323
run: docker compose run --rm phpfpm bin/console tailwind:build
2424

25+
- name: Create the test database
26+
run: docker compose run --rm phpfpm bin/console --env=test doctrine:database:create --if-not-exists --no-interaction
27+
2528
- name: Run PHPUnit with coverage
26-
run: docker compose run -e XDEBUG_MODE=coverage --rm phpfpm vendor/bin/phpunit --coverage-clover=coverage/clover.xml
29+
run: docker compose run -e XDEBUG_MODE=coverage --rm phpfpm vendor/bin/phpunit --bootstrap=tests/bootstrap_integration.php --coverage-clover=coverage/clover.xml
2730

2831
- name: Enforce coverage threshold (100%)
2932
run: docker compose run --rm phpfpm vendor/bin/coverage-check coverage/clover.xml 100

.php-cs-fixer.dist.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,4 @@
1313
$config = new PhpCsFixer\Config();
1414
$config->setFinder($finder);
1515

16-
$config->setRules([
17-
'@Symfony' => true,
18-
]);
19-
2016
return $config;

CHANGELOG.md

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,48 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- Catalogue listing page with filters
13+
([#15](https://github.com/itk-dev/ai-lib/issues/15)).
14+
- Initial Symfony 8 application scaffold on the ITK Dev Docker
15+
`symfony-8` template (phpfpm 8.4, nginx, MariaDB, Mailpit, Traefik),
16+
including dev dependencies for coding standards (`php-cs-fixer`,
17+
`twig-cs-fixer`) and composer normalization
18+
([#1](https://github.com/itk-dev/ai-lib/issues/1)).
19+
- Architecture Decision Records under `docs/adr/` with index and the
20+
first ADR `001-tech-stack-docker-symfony`
21+
([#11](https://github.com/itk-dev/ai-lib/issues/11)).
1222
- `CLAUDE.md` with project-level operating instructions for AI agents
13-
(stack, structure, execution policy, branching, commits, CHANGELOG,
14-
ADRs, domain glossary).
15-
- Initial Symfony 8 application scaffold.
16-
- PHPUnit test harness with 100% coverage gate enforced in CI via
23+
— stack, structure, execution policy, branching, commits, CHANGELOG,
24+
ADR conventions, translations, brand env vars, Tailwind rebuild
25+
notes, and the domain glossary
26+
([#5](https://github.com/itk-dev/ai-lib/issues/5)).
27+
- Human-facing `README.md` rewritten around the AI Bibliotek catalog
28+
— project description, status banner, feature list, tech stack,
29+
Task-based local development workflow, contributing pointers, and
30+
prototype references
31+
([#28](https://github.com/itk-dev/ai-lib/issues/28)).
32+
- `CONTRIBUTING.md` documenting branching, Conventional Commits,
33+
coding standards, changelog expectations, and the pull-request
34+
workflow
35+
([#9](https://github.com/itk-dev/ai-lib/issues/9)).
36+
- Project license declared as **MPL-2.0** — full `LICENSE` text at
37+
the repo root, `composer.json` `license` field updated from
38+
`proprietary` to `MPL-2.0`, and ADR `004-project-license-mpl-2`
39+
recording the rationale
40+
([#32](https://github.com/itk-dev/ai-lib/issues/32)).
41+
- `Taskfile.yml` exposing common developer commands via `task --list`
42+
(compose helpers, composer, console, coding-standards family) with
43+
README updates documenting `task` as a host requirement
44+
([#29](https://github.com/itk-dev/ai-lib/issues/29)).
45+
- Frontend tooling: Tailwind CSS via `symfonycasts/tailwind-bundle`,
46+
Symfony AssetMapper, and Stimulus via `symfony/stimulus-bundle`,
47+
with base Twig layout (`templates/base.html.twig`), asset
48+
entrypoints (`assets/app.js`, `assets/styles/app.css`), Tailwind v4
49+
design tokens (`@theme`), and ADR `002-frontend-tooling`
50+
([#38](https://github.com/itk-dev/ai-lib/issues/38)).
51+
- PHPUnit test harness with a 100 % coverage gate enforced in CI via
1752
`rregeer/phpunit-coverage-check`
1853
([#31](https://github.com/itk-dev/ai-lib/issues/31)).
19-
- ADR 006 (Draft) — user registration, approval, and account-state
20-
model: a `status` enum (`pending | approved | blocked`) on `User`,
21-
an env-var allow-list of e-mail domains for self-signup, and a
22-
`UserCheckerInterface` gating login
23-
([#60](https://github.com/itk-dev/ai-lib/issues/60)).
24-
25-
### Changed
26-
2754
- README refocused as human-facing project documentation: project purpose,
2855
tech stack, and local development bootstrap. Developer command reference
2956
moved to `CLAUDE.md` (and later `CONTRIBUTING.md`, tracked in #9).
@@ -34,13 +61,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3461
- Frontend tooling: Tailwind CSS (via `symfonycasts/tailwind-bundle`),
3562
Symfony AssetMapper, and Stimulus (via `symfony/stimulus-bundle`).
3663
Decision recorded in [ADR 002](docs/adr/002-frontend-tooling.md).
64+
([#14](https://github.com/itk-dev/ai-lib/issues/14), [#16](https://github.com/itk-dev/ai-lib/issues/16)).
3765
- Base Twig layout (`templates/base.html.twig`) and frontend asset
3866
entrypoints (`assets/app.js`, `assets/styles/app.css`).
3967
- Placeholder frontpage at `/` (`App\Controller\FrontpageController`)
40-
that previews the AI Bibliotek design with hardcoded sample data:
41-
hero, search prompt, sample-assistant rail, "Sådan virker det"
42-
steps, and "Kommer snart" chips. Follows the prototype mock at
43-
`itk-dev/research-projects/docs/public/projects/ai-bibliotek/mocks`.
68+
previewing the AI Bibliotek design with hardcoded sample data
69+
(hero, search box, sample-assistant rail, "Sådan virker det" steps),
70+
site chrome (header with brand + nav, footer), the Stimulus
71+
`nav_toggle_controller` driving the mobile menu, and a
72+
`block-on-label` GitHub Action providing a per-PR merge gate
73+
([#40](https://github.com/itk-dev/ai-lib/issues/40)).
74+
- User authentication: `User` Doctrine entity (email, hashed password,
75+
roles), `UserRepository` (with `PasswordUpgraderInterface`), the
76+
`UserManager` service that hides persistence + hashing, form-login
77+
firewall + `/login` + `/logout`, fixtures for two baseline users
78+
(`alice@example.test`, `bob@example.test` — password `password`),
79+
console commands `app:user:create` and `app:user:change-password`,
80+
and end-to-end functional + unit tests
81+
([#2](https://github.com/itk-dev/ai-lib/issues/2)).
82+
- PHPUnit suite split into `unit` (no database) and `integration` (full
83+
kernel) testsuites under `tests/Unit/` and `tests/Integration/`, with
84+
transactional database isolation per integration test via
85+
`dama/doctrine-test-bundle`. The integration suite uses a dedicated
86+
`tests/bootstrap_integration.php` that builds the schema from ORM
87+
metadata and loads baseline `UserFixtures` once before any test;
88+
DAMA's per-test transaction rolls back mutations so the baseline
89+
persists. The default `tests/bootstrap.php` is minimal and is used
90+
by `task test-unit`. `task test-unit` and `task test-integration`
91+
expose the suites individually.
92+
- Reusable Twig form components under `templates/components/Form/`:
93+
`Form/Label`, `Form/Input`, and `Form/Button` (with `variant` and
94+
`size` props for future styling variants). The `/login` template
95+
consumes them instead of inlining the input/label/button markup.
4496
- Site chrome (header with brand + nav, footer) in
4597
`templates/base.html.twig`, with the Fraunces/Geist font stack
4698
preloaded from Google Fonts.
@@ -53,13 +105,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
53105
per-PR merge gate for dependencies (e.g. another PR that must land
54106
first).
55107
- `LICENSE` file at repo root containing the full Mozilla Public License 2.0 text.
56-
- ADR `docs/adr/002-project-license-mpl-2.md` recording the MPL-2.0 license
57-
decision and its rationale.
58-
- License section in `README.md` referencing the new `LICENSE` file and ADR.
59108
- Project license declared as **MPL-2.0** (Mozilla Public License 2.0); the
60109
`license` field in `composer.json` updated from the Symfony skeleton
61110
default `proprietary` to the SPDX identifier `MPL-2.0`.
62-
- Added develop branch
63111
- `Taskfile.yml` exposing common developer commands via `task --list`
64112
(compose helpers, composer, console, coding-standards family).
65113
- README documents [Task](https://taskfile.dev) as a host requirement and
@@ -68,6 +116,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
68116
documenting the choice of Symfony 8 on the ITK Dev Docker `symfony-8` template.
69117
- `CONTRIBUTING.md` documenting branching, Conventional Commits, coding
70118
standards, changelog expectations and the pull-request workflow.
71-
- Rewrite the project README around the AI Bibliotek catalog: adds project
72-
description, status banner, feature list, tech stack, Task-based local
73-
development workflow, contributing pointers, and prototype references.
119+
- GitHub issue template `.github/ISSUE_TEMPLATE/issue.md` and pull-request
120+
template `.github/PULL_REQUEST_TEMPLATE.md`, each with a human-facing
121+
"Resume" / checklist section followed by an "AI specificities" detail
122+
block so other agents can continue work from a structured brief
123+
([#69](https://github.com/itk-dev/ai-lib/issues/69)).

CLAUDE.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,19 +105,87 @@ These come from the `symfony-8` template — don't edit them without a reason.
105105
If a project-specific override is needed, override via the template's
106106
documented mechanism (e.g. `.php-cs-fixer.php` next to `.php-cs-fixer.dist.php`).
107107

108+
### Tests are not modified without approval
109+
110+
Do **not** edit, rename, delete, or skip files under `tests/` (or any other
111+
test files) without explicit user approval — even when a failure looks like
112+
a stale assertion. If a change you're making appears to require test
113+
updates, stop and describe to the user, briefly:
114+
115+
- Which test files / test methods need to change.
116+
- What the change is (assertion update, fixture change, new case, removal).
117+
- Why it's needed (production behavior changed, contract widened, etc.).
118+
119+
Wait for the user to approve before touching the files. The 100% coverage
120+
gate (see "Common commands") means test edits have real consequences;
121+
the user decides whether the production change or the test is wrong.
122+
123+
## Coding practices
124+
125+
Style conventions code in this project follows, on top of the linter
126+
rules in "Coding standards" above.
127+
128+
### Defer to symfony.com/doc when implementing Symfony features
129+
130+
When you add or change functionality that lives on top of a Symfony
131+
component — controllers, routing, security, forms, validation,
132+
Doctrine integration, console commands, messenger, mailer,
133+
translation, asset mapping, Twig extensions, etc. — open the
134+
relevant chapter on <https://symfony.com/doc> first and base the
135+
implementation on the approach the docs show. The docs name the
136+
component, demonstrate the idiom, and link the configuration
137+
references; following them keeps the code in step with the
138+
framework instead of drifting into bespoke shapes that look
139+
reasonable but miss built-in conventions.
140+
141+
When the docs offer more than one path (e.g. PHP attributes vs.
142+
YAML config, MapEntity vs. ParamConverter), pick the one that
143+
matches what's already in this codebase. If nothing comparable
144+
exists yet, prefer the most recent idiom shown in the docs — the
145+
attribute-driven, autoconfigured, autowired style.
146+
147+
Cite the relevant doc URL in the PR description for any change
148+
that introduces a Symfony-component idiom for the first time, so
149+
reviewers can compare the implementation against the source.
150+
108151
### Controllers stay thin
109152

110153
Controllers handle routes and template/response rendering only — no business
111154
logic. Push logic into a service class. A controller action looks like:
112155
inject service → call service method → return `render()` / `Response` /
113156
`RedirectResponse`.
114157

158+
**Do not add PHPDoc to controllers.** The class name, route attribute,
159+
action name, parameter types, and return type already describe what an
160+
action does; class- and method-level docblocks duplicate that. Push the
161+
explanatory prose into the (fully documented) service the controller
162+
delegates to. If a controller is so unusual that it needs a docblock to
163+
explain itself, that's the signal it's doing too much.
164+
115165
### Service classes are fully documented
116166

117167
Every service class method (public, protected, private) carries a PHPDoc block
118168
with a one-line summary, a description of intent, `@param` per parameter,
119169
`@return`, and `@throws` for every exception that can be raised.
120170

171+
### Test methods carry a one-line intent comment
172+
173+
Each `public function test…` opens with a single-line comment that
174+
names what the test asserts, starting with `// Tests …`,
175+
`// Ensures …`, or `// Verifies …`. Pick whichever verb reads
176+
naturally for the assertion in question.
177+
178+
- One line, terse — not a docblock, not a paragraph.
179+
- Placed immediately above the method declaration.
180+
- If a block-level docblock already exists on the method (e.g. to
181+
explain *why* the test matters in context), keep it and put the
182+
one-liner beneath it. The docblock serves the *why*; the one-liner
183+
names the *what*.
184+
185+
The comment is for a reader scanning the file's table of contents
186+
without reading method bodies. Matches the convention applied across
187+
every test file on the project.
188+
121189
## Workflows
122190

123191
The `.github/workflows/*.yaml` files are mirrored from
@@ -138,6 +206,10 @@ open a PR upstream rather than patching locally.
138206
- Pass all required CI checks before merging.
139207
- Carry a `CHANGELOG.md` update under `## [Unreleased]` for any user-visible
140208
change.
209+
- If a PR carries the `do-not-merge` label, the PR description must spell
210+
out **what blocks the merge and why** (e.g. waiting on upstream change,
211+
dependent PR, unresolved decision). Keep this up to date — remove or
212+
rewrite the block reason as blockers resolve.
141213

142214
## Commits
143215

@@ -158,6 +230,18 @@ Keep subject lines under ~70 characters. Use the body for the *why*.
158230
Add an entry to `## [Unreleased]` under the right section (`Added`, `Changed`,
159231
`Fixed`, `Removed`, `Deprecated`, `Security`) for every meaningful change.
160232

233+
**Pre-release rule:** while the project has no tagged releases yet,
234+
*everything* is `Added` — there is no prior released version for a
235+
change to be `Changed`, `Fixed`, `Removed`, `Deprecated`, or `Security`
236+
relative to. Keep those sections empty (or omit them) and fold the
237+
entry into `Added`, even when the work edits or replaces material that
238+
already exists in `[Unreleased]`. Before adding to any non-`Added`
239+
section, check `git tag` (or the GitHub releases page) and confirm at
240+
least one release exists; if none does, use `Added`. Once the first
241+
release is cut, the standard Keep a Changelog sections apply normally
242+
from the next `[Unreleased]` onward. See PR #57 for the prior
243+
consolidation that established this convention.
244+
161245
## GitHub issue types and labels
162246

163247
Every issue **must** have its native **issue type** set to one of:
@@ -176,6 +260,13 @@ fall back to the REST API (`PATCH /repos/{owner}/{repo}/issues/{n}` with
176260
`type=<Name>`) when available, otherwise ask the user to set it in the
177261
UI. Labels can always be set with `gh issue create --label`.
178262

263+
When creating an issue, use the repository's issue template at
264+
`.github/ISSUE_TEMPLATE/issue.md`. Preserve its structure — every heading
265+
and HTML comment marker stays in its original order — and fill each
266+
section from the available context. Pass it via `gh issue create
267+
--body-file` (or `--body` with the rendered content) rather than hand-
268+
rolling a description.
269+
179270
## Pushing
180271

181272
SSH keys aren't available to the Claude session. Push one-off via HTTPS:

0 commit comments

Comments
 (0)