feat(23-shipment-presets-backend): tabela DB, repository CRUD i JSON API dla presetów przesyłek
Phase 23 complete: - Migracja shipment_presets (16 kolumn: name, color, carrier, wymiary, waga, itp.) - ShipmentPresetRepository z findAll/findById/create/update/delete - ShipmentPresetController z 4 endpointami JSON API - Routing w routes/web.php z auth middleware Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
225
.paul/phases/23-shipment-presets-backend/23-01-PLAN.md
Normal file
225
.paul/phases/23-shipment-presets-backend/23-01-PLAN.md
Normal file
@@ -0,0 +1,225 @@
|
||||
---
|
||||
phase: 23-shipment-presets-backend
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- database/migrations/20260322_000059_create_shipment_presets_table.sql
|
||||
- src/Modules/Shipments/ShipmentPresetRepository.php
|
||||
- src/Modules/Shipments/ShipmentPresetController.php
|
||||
- routes/web.php
|
||||
autonomous: true
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Stworzyć tabelę DB `shipment_presets` oraz pełny backend CRUD (JSON API) do zarządzania presetami przesyłek.
|
||||
|
||||
## Purpose
|
||||
Presety przesyłek pozwalają użytkownikom jednym kliknięciem wypełnić formularz przygotowania przesyłki zapisanymi wcześniej parametrami (przewoźnik, usługa, wymiary, waga itp.). Ta faza buduje fundament danych i API — UI będzie w fazie 24.
|
||||
|
||||
## Output
|
||||
- Migracja SQL tworząca tabelę `shipment_presets`
|
||||
- `ShipmentPresetRepository` z metodami CRUD
|
||||
- `ShipmentPresetController` z endpointami JSON API
|
||||
- Routing w `routes/web.php`
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
@.paul/ROADMAP.md
|
||||
@.paul/STATE.md
|
||||
|
||||
## Source Files
|
||||
@routes/web.php
|
||||
@src/Modules/Shipments/ShipmentController.php
|
||||
@src/Modules/Shipments/ShipmentPackageRepository.php
|
||||
@resources/views/shipments/prepare.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
No specialized flows required for this plan (SPECIAL-FLOWS.md: sonar-scanner required post-APPLY).
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Tabela shipment_presets istnieje w bazie
|
||||
```gherkin
|
||||
Given migracja została uruchomiona
|
||||
When sprawdzam strukturę tabeli shipment_presets
|
||||
Then tabela zawiera kolumny: id, name, color, carrier, provider_code, delivery_method_id, credentials_id, carrier_id, package_type, length_cm, width_cm, height_cm, weight_kg, sender_point_id, label_format, sort_order, created_at, updated_at
|
||||
```
|
||||
|
||||
## AC-2: API zwraca listę presetów
|
||||
```gherkin
|
||||
Given w tabeli istnieją presety
|
||||
When wysyłam GET /api/shipment-presets
|
||||
Then otrzymuję JSON z tablicą presetów posortowanych po sort_order
|
||||
```
|
||||
|
||||
## AC-3: API tworzy nowy preset
|
||||
```gherkin
|
||||
Given wysyłam POST /api/shipment-presets z danymi formularza
|
||||
When dane są poprawne (name wymagane)
|
||||
Then preset zostaje zapisany w bazie i zwrócony jako JSON z id
|
||||
```
|
||||
|
||||
## AC-4: API aktualizuje preset
|
||||
```gherkin
|
||||
Given istnieje preset o id=1
|
||||
When wysyłam PUT /api/shipment-presets/1 z nowymi danymi
|
||||
Then preset zostaje zaktualizowany w bazie
|
||||
```
|
||||
|
||||
## AC-5: API usuwa preset
|
||||
```gherkin
|
||||
Given istnieje preset o id=1
|
||||
When wysyłam DELETE /api/shipment-presets/1
|
||||
Then preset zostaje usunięty z bazy
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Migracja DB — tabela shipment_presets</name>
|
||||
<files>database/migrations/20260322_000059_create_shipment_presets_table.sql</files>
|
||||
<action>
|
||||
Utworzyć migrację SQL tworzącą tabelę `shipment_presets`:
|
||||
|
||||
```sql
|
||||
CREATE TABLE shipment_presets (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
color VARCHAR(7) NOT NULL DEFAULT '#3b82f6',
|
||||
carrier VARCHAR(32) NOT NULL COMMENT 'allegro, inpost, apaczka',
|
||||
provider_code VARCHAR(32) NOT NULL COMMENT 'allegro_wza, apaczka, inpost',
|
||||
delivery_method_id VARCHAR(128) NOT NULL,
|
||||
credentials_id VARCHAR(128) NOT NULL DEFAULT '',
|
||||
carrier_id VARCHAR(64) NOT NULL DEFAULT '',
|
||||
package_type VARCHAR(16) NOT NULL DEFAULT 'PACKAGE',
|
||||
length_cm DECIMAL(8,1) NOT NULL DEFAULT 25.0,
|
||||
width_cm DECIMAL(8,1) NOT NULL DEFAULT 20.0,
|
||||
height_cm DECIMAL(8,1) NOT NULL DEFAULT 8.0,
|
||||
weight_kg DECIMAL(8,3) NOT NULL DEFAULT 1.000,
|
||||
sender_point_id VARCHAR(64) NOT NULL DEFAULT '',
|
||||
label_format VARCHAR(8) NOT NULL DEFAULT 'PDF',
|
||||
sort_order INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
```
|
||||
|
||||
Kolumna `color` przechowuje hex kolor przycisku (np. #3b82f6).
|
||||
Brak user_id — presety globalne.
|
||||
</action>
|
||||
<verify>Uruchomić migrację na bazie: php -l na pliku SQL nie ma sensu, ale sprawdzić składnię wizualnie. Migracja zostanie uruchomiona ręcznie.</verify>
|
||||
<done>AC-1 satisfied: tabela shipment_presets z pełnym zestawem kolumn</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: ShipmentPresetRepository — CRUD na tabeli</name>
|
||||
<files>src/Modules/Shipments/ShipmentPresetRepository.php</files>
|
||||
<action>
|
||||
Utworzyć klasę `ShipmentPresetRepository` w namespace `App\Modules\Shipments`:
|
||||
|
||||
- Constructor: `__construct(private readonly PDO $pdo)`
|
||||
- `findAll(): array` — SELECT * ORDER BY sort_order ASC, id ASC
|
||||
- `findById(int $id): ?array` — SELECT WHERE id = :id
|
||||
- `create(array $data): int` — INSERT, return lastInsertId
|
||||
- `update(int $id, array $data): void` — UPDATE WHERE id = :id
|
||||
- `delete(int $id): void` — DELETE WHERE id = :id
|
||||
|
||||
Wzorować się na istniejącym `ShipmentPackageRepository` — ten sam styl (PDO prepared statements, final class).
|
||||
|
||||
Kolumny do zapisu w create/update:
|
||||
name, color, carrier, provider_code, delivery_method_id, credentials_id, carrier_id,
|
||||
package_type, length_cm, width_cm, height_cm, weight_kg, sender_point_id, label_format, sort_order
|
||||
|
||||
Avoid: Medoo — ten moduł używa czystego PDO (jak ShipmentPackageRepository).
|
||||
</action>
|
||||
<verify>php -l src/Modules/Shipments/ShipmentPresetRepository.php — brak błędów składniowych</verify>
|
||||
<done>AC-2 partially (repository layer ready), AC-3, AC-4, AC-5 data layer ready</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: ShipmentPresetController + routing</name>
|
||||
<files>src/Modules/Shipments/ShipmentPresetController.php, routes/web.php</files>
|
||||
<action>
|
||||
1. Utworzyć `ShipmentPresetController` w namespace `App\Modules\Shipments`:
|
||||
- Constructor: `__construct(private readonly ShipmentPresetRepository $repository)`
|
||||
- `list(Request $request): Response` — GET, zwraca JSON array presetów
|
||||
- `store(Request $request): Response` — POST, walidacja (name required), tworzy preset, zwraca JSON z id + 201
|
||||
- `update(Request $request): Response` — PUT, walidacja, aktualizuje preset, zwraca JSON 200
|
||||
- `destroy(Request $request): Response` — DELETE, usuwa preset, zwraca JSON 204
|
||||
|
||||
Dla store/update wyciągnąć dane z request:
|
||||
- name, color, carrier, provider_code, delivery_method_id, credentials_id, carrier_id,
|
||||
package_type, length_cm, width_cm, height_cm, weight_kg, sender_point_id, label_format, sort_order
|
||||
|
||||
Walidacja: `name` nie może być pusty. Resztę ustawić z defaults.
|
||||
Brak CSRF dla JSON API — ale wymagać auth middleware.
|
||||
|
||||
2. W `routes/web.php`:
|
||||
- Dodać `use App\Modules\Shipments\ShipmentPresetRepository;`
|
||||
- Dodać `use App\Modules\Shipments\ShipmentPresetController;`
|
||||
- Instancja: `$presetRepository = new ShipmentPresetRepository($app->db());`
|
||||
- Instancja: `$presetController = new ShipmentPresetController($presetRepository);`
|
||||
- Routing (z $authMiddleware):
|
||||
```
|
||||
$router->get('/api/shipment-presets', [$presetController, 'list'], [$authMiddleware]);
|
||||
$router->post('/api/shipment-presets', [$presetController, 'store'], [$authMiddleware]);
|
||||
$router->put('/api/shipment-presets/{id}', [$presetController, 'update'], [$authMiddleware]);
|
||||
$router->delete('/api/shipment-presets/{id}', [$presetController, 'destroy'], [$authMiddleware]);
|
||||
```
|
||||
|
||||
Umieścić routing w sekcji API (po print API routes, przed zamknięciem).
|
||||
|
||||
Wzorować styl Response na istniejących API controllerach (PrintApiController — Response::json).
|
||||
</action>
|
||||
<verify>php -l src/Modules/Shipments/ShipmentPresetController.php — brak błędów składniowych. Sprawdzić że routes/web.php nie ma syntax errors: php -l routes/web.php</verify>
|
||||
<done>AC-2, AC-3, AC-4, AC-5 satisfied: pełny JSON API dla presetów</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- src/Modules/Shipments/ShipmentController.php (modyfikacja w fazie 24)
|
||||
- resources/views/shipments/prepare.php (modyfikacja w fazie 24)
|
||||
- src/Modules/Shipments/ShipmentPackageRepository.php (stabilne)
|
||||
- Istniejące migracje w database/migrations/
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Tylko backend (tabela + repository + controller + routing)
|
||||
- Brak zmian UI — to faza 24
|
||||
- Brak walidacji CSRF w API JSON (auth middleware wystarczający)
|
||||
- Presety globalne (bez user_id)
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] Migracja SQL poprawna składniowo
|
||||
- [ ] php -l na ShipmentPresetRepository.php — OK
|
||||
- [ ] php -l na ShipmentPresetController.php — OK
|
||||
- [ ] php -l na routes/web.php — OK
|
||||
- [ ] Routing dodany z auth middleware
|
||||
- [ ] All acceptance criteria met
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Tabela shipment_presets gotowa do migracji
|
||||
- Repository z pełnym CRUD
|
||||
- Controller z 4 endpointami JSON API
|
||||
- Routing zarejestrowany w routes/web.php
|
||||
- Brak błędów PHP
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.paul/phases/23-shipment-presets-backend/23-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user