# Employee Entry Date Implementation Plan > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add an `entryDate` field to Employee, automatically populated from `contractStartDate` at creation. **Architecture:** New nullable `DATE` column on `employees` table. The `EmployeeWriteProcessor` sets `entryDate` from the first contract period's start date during employee creation. Exposed read-only in the API. No fallback needed — existing employees will be updated manually in prod DB. **Tech Stack:** Symfony/Doctrine (backend), Nuxt/Vue/TypeScript (frontend) --- ## File Structure | File | Action | Responsibility | |------|--------|----------------| | `src/Entity/Employee.php` | Modify | Add `entryDate` column + getter/setter, expose in `employee:read` | | `src/State/EmployeeWriteProcessor.php` | Modify | Set `entryDate` from `contractStartDate` on creation | | `migrations/Version20260312120000.php` | Create | Add `entry_date` column to `employees` table | | `tests/State/EmployeeWriteProcessorTest.php` | Modify | Assert `entryDate` is set on new employee | | `frontend/services/dto/employee.ts` | Modify | Add `entryDate` field to `Employee` type | | `frontend/pages/employees/index.vue` | Modify | Display entry date in employee list | --- ## Chunk 1: Backend ### Task 1: Migration **Files:** - Create: `migrations/Version20260312120000.php` - [ ] **Step 1: Create the migration file** ```php addSql('ALTER TABLE employees ADD entry_date DATE DEFAULT NULL COMMENT \'(DC2Type:date_immutable)\''); } public function down(Schema $schema): void { $this->addSql('ALTER TABLE employees DROP entry_date'); } } ``` - [ ] **Step 2: Run migration** Run: `php bin/console doctrine:migrations:migrate --no-interaction` Expected: Migration applied successfully - [ ] **Step 3: Commit** ```bash git add migrations/Version20260312120000.php git commit -m "feat : ajout colonne entry_date sur employees" ``` --- ### Task 2: Entity — add `entryDate` property **Files:** - Modify: `src/Entity/Employee.php:56-61` (insert after `displayOrder`) - [ ] **Step 1: Add the column, getter, and setter to Employee entity** Add after the `displayOrder` property (line 58): ```php #[ORM\Column(type: 'date_immutable', nullable: true)] #[Groups(['employee:read'])] private ?\DateTimeImmutable $entryDate = null; ``` Add getter and setter after `setDisplayOrder()` (after line 167): ```php public function getEntryDate(): ?\DateTimeImmutable { return $this->entryDate; } public function setEntryDate(?\DateTimeImmutable $entryDate): self { $this->entryDate = $entryDate; return $this; } ``` - [ ] **Step 2: Verify schema is in sync** Run: `php bin/console doctrine:schema:validate` Expected: OK (or only existing unrelated warnings) - [ ] **Step 3: Commit** ```bash git add src/Entity/Employee.php git commit -m "feat : ajout propriete entryDate sur Employee" ``` --- ### Task 3: Set `entryDate` on employee creation **Files:** - Modify: `src/State/EmployeeWriteProcessor.php:60-71` - Modify: `tests/State/EmployeeWriteProcessorTest.php` - [ ] **Step 1: Write the failing test** Add `use ApiPlatform\Metadata\Post;` to the imports at the top of the test file (alongside the existing `Delete` and `Patch` imports). Then add this test method to `EmployeeWriteProcessorTest`: ```php public function testSetsEntryDateOnNewEmployee(): void { $employee = new Employee(); $employee->setFirstName('Jane'); $employee->setLastName('Doe'); $employee->setContractStartDate('2026-04-01'); $employee->setContractNature('CDI'); $contract = new Contract() ->setName('35h') ->setTrackingMode(Contract::TRACKING_TIME) ->setWeeklyHours(35); $employee->setContract($contract); $persistProcessor = $this->createMock(ProcessorInterface::class); $removeProcessor = $this->createStub(ProcessorInterface::class); $entityManager = $this->createStub(EntityManagerInterface::class); $periodRepository = $this->createStub(EmployeeContractPeriodReadRepositoryInterface::class); $changeRequestFactory = new EmployeeContractChangeRequestFactory(); $periodManager = $this->createMock(EmployeeContractPeriodManagerInterface::class); $persistProcessor ->expects(self::once()) ->method('process') ->willReturn($employee); $periodManager ->expects(self::once()) ->method('ensureContractPeriodExists'); $processor = new EmployeeWriteProcessor( $persistProcessor, $removeProcessor, $entityManager, $periodRepository, $changeRequestFactory, $periodManager ); $processor->process($employee, new Post()); self::assertNotNull($employee->getEntryDate()); self::assertSame('2026-04-01', $employee->getEntryDate()->format('Y-m-d')); } ``` - [ ] **Step 2: Run test to verify it fails** Run: `php bin/phpunit tests/State/EmployeeWriteProcessorTest.php --filter=testSetsEntryDateOnNewEmployee` Expected: FAIL — `entryDate` is null - [ ] **Step 3: Implement — set entryDate in EmployeeWriteProcessor** In `src/State/EmployeeWriteProcessor.php`, inside the `if ($isNew)` block (line 60-71), add **before** `return $result;` (line 71): ```php $data->setEntryDate($startDate); ``` The full block becomes: ```php if ($isNew) { $startDate = $changeRequest->contractStartDate ?? new DateTimeImmutable('1970-01-01'); $nature = $changeRequest->contractNature ?? ContractNature::CDI; $this->periodManager->ensureContractPeriodExists( employee: $data, contract: $currentContract, startDate: $startDate, endDate: $changeRequest->contractEndDate, nature: $nature ); $data->setEntryDate($startDate); return $result; } ``` - [ ] **Step 4: Run test to verify it passes** Run: `php bin/phpunit tests/State/EmployeeWriteProcessorTest.php --filter=testSetsEntryDateOnNewEmployee` Expected: PASS - [ ] **Step 5: Run all EmployeeWriteProcessor tests** Run: `php bin/phpunit tests/State/EmployeeWriteProcessorTest.php` Expected: All tests pass (no regression) - [ ] **Step 6: Commit** ```bash git add src/State/EmployeeWriteProcessor.php tests/State/EmployeeWriteProcessorTest.php git commit -m "feat : remplissage automatique entryDate a la creation employe" ``` --- ## Chunk 2: Frontend ### Task 4: Update frontend DTO and display entry date **Files:** - Modify: `frontend/services/dto/employee.ts:14-25` - Modify: `frontend/pages/employees/index.vue` - [ ] **Step 1: Add `entryDate` to the Employee DTO** In `frontend/services/dto/employee.ts:24`, add `entryDate` after `displayOrder`: ```typescript displayOrder?: number entryDate?: string | null ``` - [ ] **Step 2: Display entry date in the employee card hover overlay** In `frontend/pages/employees/index.vue`, inside the hover overlay `
Entree : {{ employee.entryDate ? employee.entryDate.split('-').reverse().join('/') : '-' }}
``` This uses string splitting instead of `new Date()` to avoid timezone parsing issues with date-only strings. - [ ] **Step 3: Verify in browser** 1. Check the API response for an employee: `GET /api/employees` should include `entryDate` field (confirms backend `employee:read` group works) 2. Open the employee list page, hover over a card — entry date should appear in the overlay 3. Create a new employee, verify the entry date shows the contract start date 4. Existing employees without entry date should show "-" - [ ] **Step 4: Commit** ```bash git add frontend/services/dto/employee.ts frontend/pages/employees/index.vue git commit -m "feat : affichage date d'entree dans la liste employes" ```