From 8ba1f80bda0533ab4bd16271882780316794cb14 Mon Sep 17 00:00:00 2001 From: martinydeAI Date: Thu, 11 Jun 2026 12:37:18 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20add=20ADR=20003=20=E2=80=94=20admin=20/?= =?UTF-8?q?=20CRUD=20tooling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the decision to build backend management screens with Symfony Form plus hand-written controllers and Twig templates rather than adopt an admin generator (EasyAdmin, Sonata, API Platform Admin). The backend surface is small, the assistant entity needs a first-class product UI anyway, and the user-management screens require row-level domain-manager scoping that a generic CRUD generator would only get in the way of. Both martinyde and tuj have indicated support on the issue. Status: Draft. Index updated. CHANGELOG entry under [Unreleased] / Added. Refs #39. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 3 + docs/adr/003-admin-crud-tooling.md | 142 +++++++++++++++++++++++++++++ docs/adr/README.md | 1 + 3 files changed, 146 insertions(+) create mode 100644 docs/adr/003-admin-crud-tooling.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 30aa2a5..9e247c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - PHPUnit test harness with 100% coverage gate enforced in CI via `rregeer/phpunit-coverage-check` ([#31](https://github.com/itk-dev/ai-lib/issues/31)). +- ADR 003 (Draft): admin / CRUD tooling — Symfony Form + hand-written + controllers and Twig templates over a generator + ([#39](https://github.com/itk-dev/ai-lib/issues/39)). ### Changed diff --git a/docs/adr/003-admin-crud-tooling.md b/docs/adr/003-admin-crud-tooling.md new file mode 100644 index 0000000..0f6a96b --- /dev/null +++ b/docs/adr/003-admin-crud-tooling.md @@ -0,0 +1,142 @@ +# 003: Admin / CRUD tooling — Symfony Form + hand-written controllers + +| Field | Value | +| ------------------ | -------------------------------------------------- | +| **Created By** | Martin Yde Granath | +| **Date** | 2026-06-11 | +| **Decision Maker** | ITK Dev team | +| **Stakeholders** | ITK Dev developers, future maintainers of ai-lib | +| **Status** | Draft | + +## Context + +ai-lib needs backend management screens for at least: + +- User management ([#12](https://github.com/itk-dev/ai-lib/issues/12), + [#13](https://github.com/itk-dev/ai-lib/issues/13)), where a domain + manager controls users within their own domain — i.e. row-level + scoping that is not a simple CRUD over the User entity. +- Assistant management + ([#14](https://github.com/itk-dev/ai-lib/issues/14), + [#20](https://github.com/itk-dev/ai-lib/issues/20)). The assistant + is the product's core entity; managing one needs a proper, end-user + facing frontend rather than a generic admin grid. +- Smaller administrative surfaces: tag/category management + ([#16](https://github.com/itk-dev/ai-lib/issues/16)) and submission + moderation ([#25](https://github.com/itk-dev/ai-lib/issues/25)). + +Before any of these are built we need to choose how admin screens are +produced so the same approach is used throughout the codebase. + +This ADR is scoped to the **admin / CRUD generator** choice. Form +component conventions (location of form types, validation strategy, +form theme) and the in-admin authorisation model are intentionally +left to follow-on decisions once the data model and role model are +clearer. + +### Drivers + +- **Functional:** + - Support row-level authorisation (domain-manager scope), not just + whole-entity gates. + - Allow the assistant's management screens to be hand-crafted as + first-class product UI, not a generic admin view. + - Keep the small administrative surfaces (tags, moderation queue) + cheap to implement. +- **Non-functional:** + - Minimise added complexity and dependencies during early + development. + - Stay aligned with the rest of the stack — Symfony Form is already + available via `symfony/framework-bundle`. + - Keep the door open for adopting a generator later if scope grows. + +### Options Considered + +1. **Custom CRUD with Symfony Form + hand-written controllers and + Twig templates.** + - Pros: no extra dependency; full control over routing, templates, + and authorisation; aligns naturally with row-level scoping; small + forms are tractable to hand-write. + - Cons: more code per screen; no scaffolded list / filter / sort + UI; the team must agree on a few conventions (form type location, + template structure) to avoid drift. +2. **EasyAdmin (`EasyCorp/EasyAdminBundle`).** + - Pros: fastest path to a working admin from Doctrine entities; + built-in filters, search, sort, batch actions; PHP-only + configuration; integrates with Symfony Security. + - Cons: opinionated UI shipped with Bootstrap markup that conflicts + visually with the Tailwind frontend from ADR 002; the "all admin + in one dashboard controller" pattern grows into a god-controller + without careful splitting; row-level scoping (domain manager) + requires custom data providers and voters that work around the + bundle's defaults; non-Doctrine data sources are awkward. +3. **Sonata Admin.** + - Pros: feature-rich. + - Cons: heavier setup; larger surface area; same UI-alignment + concerns as EasyAdmin; overkill for the few admin screens this + project actually needs. +4. **API Platform Admin (React-Admin).** + - Pros: natural choice if the project goes API-first with a + separate React frontend. + - Cons: presupposes an API-first architecture ai-lib has not + committed to; introduces a second runtime and build toolchain + just for the admin UI. + +## Decision + +Adopt **option 1 — custom CRUD with Symfony Form + hand-written +controllers and Twig templates** for all backend management screens. + +Rationale: + +- The backend surface is small. There are essentially three areas + (users, assistants, light moderation), and the assistant screens + are first-class product UI that any admin generator would have to + step aside for anyway. +- User management needs row-level scoping (a domain manager only sees + and edits their own domain's users). Implementing that on top of a + generic CRUD generator means writing custom data providers and + voters that override the generator's defaults — at which point the + generator is adding complexity without saving code. +- EasyAdmin's Bootstrap-themed UI would diverge from the Tailwind + frontend chosen in ADR 002. Aligning them is possible but is itself + a recurring cost. +- Symfony Form is already part of the framework and is well understood + by the team. Hand-writing the few remaining administrative forms is + tractable and easy to review. +- Keeping the dependency surface small now preserves the freedom to + adopt a generator later if the admin surface grows in ways we did + not predict. + +## Consequences + +### Positive + +- No additional bundle to track, configure, or upgrade. +- Each management screen owns its routing, template, and security + decisions, which makes row-level authorisation patterns natural to + express. +- The admin UI shares the same Tailwind component library as the + public site, so look and feel stay consistent without extra theming. +- Future contributors only need familiarity with Symfony's core + (Controller, Form, Twig, Security) — no bundle-specific patterns to + learn. + +### Negative / Trade-offs + +- More boilerplate per screen than a generator would produce. We + accept this because the number of screens is small. +- No built-in list / filter / sort UI primitives — the project will + need to evolve its own conventions for those once a second listing + screen lands. +- If the backend surface grows substantially later, the team may + re-open this decision and adopt a generator at that point; this ADR + would then be superseded. + +--- + +_Form component conventions and the in-admin authorisation model are +out of scope here and remain open. They will be settled in follow-on +decisions once the data model +([#14](https://github.com/itk-dev/ai-lib/issues/14)) and roles +([#12](https://github.com/itk-dev/ai-lib/issues/12)) firm up._ diff --git a/docs/adr/README.md b/docs/adr/README.md index 8ae100d..1ce13c8 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -23,3 +23,4 @@ See [adr.github.io](https://adr.github.io/) for background on the format. | -------------------------------------------- | -------------------------------------- | -------- | ---------- | | [001](001-tech-stack-docker-symfony.md) | Tech stack: Docker + Symfony | Accepted | 2026-06-08 | | [002](002-project-license-mpl-2.md) | Project license: MPL-2.0 | Accepted | 2026-06-08 | +| [003](003-admin-crud-tooling.md) | Admin / CRUD tooling | Draft | 2026-06-11 |