Compare commits

..

6 Commits

Author SHA1 Message Date
gitea-actions d01bbfbc65 chore: bump version to v0.1.43
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 17s
2026-05-28 09:42:08 +00:00
matthieu 92a6343b66 [ERP-43] Migrer les tables Category et CategoryType (#14)
Auto Tag Develop / tag (push) Successful in 8s
## Ticket
- Lesstime : [#43](https://gitea.malio.fr) — Migrer les tables Category et CategoryType (M0 Catalog, position 0.1)

## Contenu
Migration Doctrine `migrations/Version20260527164000.php` (namespace racine `DoctrineMigrations`, règle ABSOLUE Starseed n°11) :
- Table `category_type` : `id INT IDENTITY`, `code VARCHAR(40)` (UNIQUE), `label VARCHAR(120)`
- Table `category` : `id`, `name`, `category_type_id` (FK RESTRICT), `deleted_at` (soft delete), + 4 colonnes Timestampable/Blamable (`created_at`/`updated_at` NOT NULL, `created_by`/`updated_by` nullable FK `"user"` ON DELETE SET NULL)
- Index unique partiel `uq_category_name_type_active` sur `(LOWER(name), category_type_id) WHERE deleted_at IS NULL` → matérialise **RG-1.07**
- Index `idx_category_deleted_at`, `idx_category_type_id`, `idx_category_created_by`, `idx_category_updated_by`

## Tests
- `make php-cs-fixer-allow-risky` ✓
- `make db-reset` ✓ (migration exécutée sans erreur)
- `make test` ✓ — 248 tests / 858 assertions, 0 échec
- Vérification psql `\d category` ✓ (index partiel + 8 colonnes + 3 FK avec les bons ON DELETE)

## ⚠ Mode stacked PR
Cette MR cible `feature/ERP-52-creer-pattern-timestampable-blamable-shared` au lieu de `develop`. Quand la MR #13 (ERP-52) sera mergée sur develop, Matthieu repointera la cible de cette MR vers develop.

Reviewer suggéré : Tristan

---------

Co-authored-by: Matthieu <mtholot19@gmail.com>
Reviewed-on: #14
Reviewed-by: Autin <tristan@yuno.malio.fr>
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
2026-05-28 09:40:00 +00:00
gitea-actions 02df221a0b chore: bump version to v0.1.42
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 20s
2026-05-28 09:39:02 +00:00
matthieu 6efe7aa8ea [ERP-52] Créer le pattern Timestampable + Blamable Shared (#13)
Auto Tag Develop / tag (push) Successful in 9s
## Contexte
Ticket Lesstime : [#52](https://project.malio-dev.fr/projects/6/tasks/463)
Position dans le groupe M0 : 0.0 (prérequis transverse)

## Implémentation
- 2 interfaces (`TimestampableInterface`, `BlamableInterface`) dans `Shared/Domain/Contract/`
- 1 trait (`TimestampableBlamableTrait`) dans `Shared/Domain/Trait/`
- 1 Subscriber Doctrine (`TimestampableBlamableSubscriber`) dans `Shared/Infrastructure/Doctrine/`
- 1 ligne `resolve_target_entities` ajoutée à `config/packages/doctrine.yaml` (`UserInterface` → `User`)
- 1 test architecture (`EntitiesAreTimestampableBlamableTest`) garde-fou L3 de la spec § 2.8.bis
- 1 test unitaire (`TimestampableBlamableSubscriberTest`) 4 cas

## Décision EXCLUDED (cf. réponse review)
Les 4 entités préexistantes (`User`, `Role`, `Permission`, `Site`) sont **whitelistées** dans `EXCLUDED` avec justification par entrée, plutôt que rétrofitées dans ce ticket. Le rétrofit de `User` et `Site` est documenté en **HP-9 / HP-10** (récursion Blamable + migration → décision archi scopée). Doc mise à jour : spec § 2.8.bis, § 9, et `.claude/rules/backend.md`.

## Tests
- PHPUnit : 5 nouveaux tests, 0 échec, 0 risky (248 tests / 874 assertions au total)
- php-cs-fixer : OK

## Reviewer suggéré
- Tristan

---------

Co-authored-by: Matthieu <mtholot19@gmail.com>
Reviewed-on: #13
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
2026-05-28 09:37:18 +00:00
gitea-actions 6c27ac8640 chore: bump version to v0.1.41
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 22s
2026-05-28 09:33:38 +00:00
matthieu 2ef344e22f ci : speed up PR workflow (nuxt build cache + remove broken runner cache) (#21)
Auto Tag Develop / tag (push) Successful in 11s
## Contexte
2 fixes CI extraits de la MR #13 (ERP-52) pour propreté. Ces commits sont indépendants du pattern Shared.

## Contenu
- db6619a ci(frontend) : accelere le job PR (nuxt build + cache node_modules & build Nuxt/Vite)
- 8035a9d ci : retire tout le caching (backend de cache runner injoignable, timeout 4m30)

## Reviewer suggéré
Matthieu (CI infra).

---------

Co-authored-by: Matthieu <mtholot19@gmail.com>
Reviewed-on: #21
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
2026-05-28 09:32:27 +00:00
3 changed files with 103 additions and 12 deletions
+12 -11
View File
@@ -60,14 +60,9 @@ jobs:
coverage: none
tools: composer:v2
- name: Cache Composer
uses: actions/cache@v4
with:
path: ~/.composer/cache
key: composer-${{ hashFiles('composer.lock') }}
restore-keys: |
composer-
# Cache Composer retire : meme cause que cote front — le backend de cache
# du runner Gitea est injoignable (ETIMEDOUT) et fait timeouter le step
# ~4 min 30. A re-activer si le serveur de cache du runner est repare.
- name: Install PHP dependencies
run: composer install --no-interaction --no-progress --prefer-dist
@@ -99,12 +94,15 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
# Pas de `cache: npm` : le backend de cache du runner Gitea est injoignable
# (ETIMEDOUT) et chaque tentative de restauration attend ~4 min 30 avant de
# timeout — c'est ce qui plombait le job. Node 22 est deja dans le
# tool-cache du runner (install instantane), et `npm ci` a froid ne prend
# que ~30s. A re-activer si le serveur de cache du runner est repare.
- name: Setup Node 22
uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install Node dependencies
run: npm ci
@@ -115,5 +113,8 @@ jobs:
- name: Unit tests (Vitest)
run: npm run test
# `nuxt build` (et non `build:dist`/`nuxt generate`) : l'app est en SSR off
# (SPA), le prerender de generate n'apporte rien a une quality gate — on
# veut seulement valider que le bundle compile.
- name: Build production (nuxt build)
run: npm run build:dist
run: npm run build
+1 -1
View File
@@ -1,2 +1,2 @@
parameters:
app.version: '0.1.40'
app.version: '0.1.43'
+90
View File
@@ -0,0 +1,90 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* M0 — Catalog : creation des tables `category_type` (referentiel) et `category`.
*
* Le referentiel `category_type` est cree vide ; ses valeurs seront seedees
* ulterieurement (cf. spec-back M0 § 9 HP-1).
*
* Index unique partiel sur (LOWER(name), category_type_id) WHERE deleted_at
* IS NULL : permet la recreation d'une categorie apres suppression logique
* (cf. RG-1.07). Postgres supporte nativement le `CREATE UNIQUE INDEX ... WHERE`.
*
* Les 4 colonnes Timestampable/Blamable (`created_at`, `updated_at`,
* `created_by`, `updated_by`) materialisent le pattern Shared (cf. ERP-52,
* spec-back M0 § 2.8) : NOT NULL pour les dates (remplies par le subscriber),
* nullable + ON DELETE SET NULL pour les FK user (creation hors contexte HTTP
* et suppression d'un user sans bloquer les categories existantes).
*
* Migration placee au namespace racine `DoctrineMigrations` (regle ABSOLUE
* Starseed n°11) : avec plusieurs migrations_paths, Doctrine Migrations 3.x
* trie par FQCN alphabetique et non par version timestamp → l'init des tables
* d'un module doit vivre au namespace racine pour garantir l'ordre sur base
* vide.
*/
final class Version20260527164000 extends AbstractMigration
{
public function getDescription(): string
{
return 'M0 Catalog : tables category_type et category, index unique partiel.';
}
public function up(Schema $schema): void
{
$this->addSql(<<<'SQL'
CREATE TABLE category_type (
id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
code VARCHAR(40) NOT NULL,
label VARCHAR(120) NOT NULL,
PRIMARY KEY (id)
)
SQL);
$this->addSql('CREATE UNIQUE INDEX uq_category_type_code ON category_type (code)');
$this->addSql(<<<'SQL'
CREATE TABLE category (
id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name VARCHAR(120) NOT NULL,
category_type_id INT NOT NULL,
deleted_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL,
created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL,
updated_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL,
created_by INT DEFAULT NULL,
updated_by INT DEFAULT NULL,
PRIMARY KEY (id),
CONSTRAINT fk_category_type
FOREIGN KEY (category_type_id) REFERENCES category_type (id) ON DELETE RESTRICT,
CONSTRAINT fk_category_created_by
FOREIGN KEY (created_by) REFERENCES "user" (id) ON DELETE SET NULL,
CONSTRAINT fk_category_updated_by
FOREIGN KEY (updated_by) REFERENCES "user" (id) ON DELETE SET NULL
)
SQL);
// Unicite (name, type) case-insensitive, seulement sur les non-soft-deleted.
$this->addSql(<<<'SQL'
CREATE UNIQUE INDEX uq_category_name_type_active
ON category (LOWER(name), category_type_id)
WHERE deleted_at IS NULL
SQL);
$this->addSql('CREATE INDEX idx_category_deleted_at ON category (deleted_at)');
$this->addSql('CREATE INDEX idx_category_type_id ON category (category_type_id)');
$this->addSql('CREATE INDEX idx_category_created_by ON category (created_by)');
$this->addSql('CREATE INDEX idx_category_updated_by ON category (updated_by)');
}
public function down(Schema $schema): void
{
// Ordre important : `category` porte les FK vers `category_type`.
$this->addSql('DROP TABLE category');
$this->addSql('DROP TABLE category_type');
}
}