feat(19-ui-integration): przycisk Drukuj, bulk print, kolejka wydruku
- Przycisk "Drukuj" w prepare.php i show.php z AJAX + duplikat protection - Bulk print z listy zamówień (checkboxy + header action) - Kolejka wydruku w Ustawienia > Drukowanie (filtr statusu, retry) - POST /api/print/jobs/bulk endpoint (package_ids + order_ids) - ensureLabel() auto-download przez ShipmentProviderRegistry - Apaczka carrier_id = nazwa usługi, kolumna Przewoznik - Tab persistence (localStorage), label file_exists check - Fix use statement ApaczkaApiClient, redirect po utworzeniu przesyłki - Phase 17 (receipt duplicate guard) + Phase 18 (print queue backend) docs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
288
.paul/phases/18-print-queue-backend/18-01-PLAN.md
Normal file
288
.paul/phases/18-print-queue-backend/18-01-PLAN.md
Normal file
@@ -0,0 +1,288 @@
|
||||
---
|
||||
phase: 18-print-queue-backend
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- database/migrations/20260322_000058_create_print_tables.sql
|
||||
- src/Modules/Printing/PrintJobRepository.php
|
||||
- src/Modules/Printing/PrintApiKeyRepository.php
|
||||
- src/Modules/Printing/PrintApiController.php
|
||||
- src/Modules/Printing/ApiKeyMiddleware.php
|
||||
- src/Modules/Settings/PrintSettingsController.php
|
||||
- routes/web.php
|
||||
autonomous: false
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Stworzyć backend do zdalnego drukowania etykiet: tabele DB (print_jobs, print_api_keys), REST API z uwierzytelnianiem kluczem API, oraz CRUD kluczy API w ustawieniach.
|
||||
|
||||
## Purpose
|
||||
Fundament pod system zdalnego drukowania — aplikacja Windows (faza 20) będzie odpytywać te endpointy aby pobierać zlecenia wydruku i drukować etykiety na drukarce termicznej.
|
||||
|
||||
## Output
|
||||
- Migracja SQL: tabele print_jobs i print_api_keys
|
||||
- Moduł Printing: PrintJobRepository, PrintApiKeyRepository, PrintApiController
|
||||
- ApiKeyMiddleware do uwierzytelniania requestów z aplikacji Windows
|
||||
- PrintSettingsController: CRUD kluczy API w ustawieniach
|
||||
- REST API: 4 endpointy (create job, list pending, download label, mark complete)
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
## Project Context
|
||||
@.paul/PROJECT.md
|
||||
@.paul/ROADMAP.md
|
||||
@.paul/STATE.md
|
||||
|
||||
## Source Files
|
||||
@src/Core/Routing/Router.php
|
||||
@src/Modules/Auth/AuthMiddleware.php
|
||||
@src/Modules/Shipments/ShipmentController.php
|
||||
@routes/web.php
|
||||
</context>
|
||||
|
||||
<skills>
|
||||
## Required Skills (from SPECIAL-FLOWS.md)
|
||||
|
||||
| Skill | Priority | When to Invoke | Loaded? |
|
||||
|-------|----------|----------------|---------|
|
||||
| sonar-scanner | required | Po APPLY, przed UNIFY | ○ |
|
||||
|
||||
</skills>
|
||||
|
||||
<acceptance_criteria>
|
||||
|
||||
## AC-1: Tabele DB utworzone poprawnie
|
||||
```gherkin
|
||||
Given czysta baza danych
|
||||
When uruchomię migrację 20260322_000058_create_print_tables.sql
|
||||
Then tabele print_jobs i print_api_keys istnieją z poprawnymi kolumnami i indeksami
|
||||
```
|
||||
|
||||
## AC-2: CRUD kluczy API w ustawieniach
|
||||
```gherkin
|
||||
Given użytkownik jest zalogowany i otwiera Ustawienia > Drukowanie
|
||||
When tworzy nowy klucz API (podaje nazwę)
|
||||
Then klucz jest generowany, wyświetlany jednorazowo, zapisany w DB (hash)
|
||||
And klucz można dezaktywować i usunąć
|
||||
```
|
||||
|
||||
## AC-3: API — tworzenie zlecenia wydruku
|
||||
```gherkin
|
||||
Given istnieje etykieta przesyłki (label_path w shipment_packages)
|
||||
When użytkownik orderPRO wyśle POST /api/print/jobs z session auth
|
||||
Then zlecenie wydruku zostaje utworzone ze statusem 'pending'
|
||||
And odpowiedź zawiera ID zlecenia
|
||||
```
|
||||
|
||||
## AC-4: API — pobieranie zleceń i etykiet przez klienta
|
||||
```gherkin
|
||||
Given klient Windows uwierzytelnia się kluczem API (header X-Api-Key)
|
||||
When wyśle GET /api/print/jobs/pending
|
||||
Then otrzyma listę zleceń ze statusem 'pending'
|
||||
And gdy wyśle GET /api/print/jobs/{id}/download
|
||||
Then otrzyma plik PDF etykiety
|
||||
```
|
||||
|
||||
## AC-5: API — oznaczanie zlecenia jako wydrukowane
|
||||
```gherkin
|
||||
Given klient Windows pobrał i wydrukował etykietę
|
||||
When wyśle PATCH /api/print/jobs/{id}/complete z kluczem API
|
||||
Then zlecenie zmieni status na 'completed' z timestampem completed_at
|
||||
```
|
||||
|
||||
## AC-6: Nieprawidłowy klucz API odrzucony
|
||||
```gherkin
|
||||
Given request z nieprawidłowym lub brakującym kluczem API
|
||||
When klient wyśle request do /api/print/*
|
||||
Then odpowiedź to 401 Unauthorized (JSON)
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Migracja DB — tabele print_jobs i print_api_keys</name>
|
||||
<files>database/migrations/20260322_000058_create_print_tables.sql</files>
|
||||
<action>
|
||||
Utworzyć migrację SQL z dwiema tabelami:
|
||||
|
||||
**print_api_keys:**
|
||||
- `id` INT AUTO_INCREMENT PRIMARY KEY
|
||||
- `name` VARCHAR(128) NOT NULL — nazwa przyjazna ("Komputer biurowy")
|
||||
- `key_hash` VARCHAR(128) NOT NULL — hash klucza (SHA-256)
|
||||
- `key_prefix` VARCHAR(8) NOT NULL — pierwsze 8 znaków klucza (do identyfikacji)
|
||||
- `is_active` TINYINT(1) NOT NULL DEFAULT 1
|
||||
- `last_used_at` DATETIME NULL
|
||||
- `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
|
||||
Indeksy: UNIQUE na key_hash, INDEX na is_active.
|
||||
|
||||
**print_jobs:**
|
||||
- `id` INT AUTO_INCREMENT PRIMARY KEY
|
||||
- `order_id` BIGINT NOT NULL — FK → orders.id ON DELETE CASCADE
|
||||
- `package_id` INT NOT NULL — FK → shipment_packages.id ON DELETE CASCADE
|
||||
- `label_path` VARCHAR(255) NOT NULL — ścieżka do pliku PDF
|
||||
- `status` ENUM('pending', 'printing', 'completed', 'failed') NOT NULL DEFAULT 'pending'
|
||||
- `created_by` INT NOT NULL — kto zlecił wydruk
|
||||
- `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
- `completed_at` DATETIME NULL
|
||||
|
||||
Indeksy: INDEX na status, INDEX na order_id, INDEX na package_id.
|
||||
|
||||
Konwencja: zgodna z istniejącymi migracjami (plik .sql, plain DDL).
|
||||
</action>
|
||||
<verify>Uruchomić migrację i sprawdzić SHOW CREATE TABLE print_jobs; SHOW CREATE TABLE print_api_keys;</verify>
|
||||
<done>AC-1 satisfied: tabele istnieją z poprawnymi kolumnami i indeksami</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Repozytoria i kontrolery — PrintJobRepository, PrintApiKeyRepository, ApiKeyMiddleware, PrintApiController, PrintSettingsController</name>
|
||||
<files>
|
||||
src/Modules/Printing/PrintJobRepository.php,
|
||||
src/Modules/Printing/PrintApiKeyRepository.php,
|
||||
src/Modules/Printing/PrintApiController.php,
|
||||
src/Modules/Printing/ApiKeyMiddleware.php,
|
||||
src/Modules/Settings/PrintSettingsController.php,
|
||||
routes/web.php
|
||||
</files>
|
||||
<action>
|
||||
**PrintApiKeyRepository** (src/Modules/Printing/):
|
||||
- `create(string $name, string $keyHash, string $keyPrefix): int` — INSERT, zwraca ID
|
||||
- `findByKeyHash(string $keyHash): ?array` — szukanie po hashu (do auth)
|
||||
- `listAll(): array` — lista kluczy (bez hashy, z prefixem)
|
||||
- `deactivate(int $id): void` — SET is_active = 0
|
||||
- `delete(int $id): void` — DELETE
|
||||
- `updateLastUsed(int $id): void` — SET last_used_at = NOW()
|
||||
- Używać PDO + prepared statements (wzorzec jak ReceiptRepository)
|
||||
|
||||
**PrintJobRepository** (src/Modules/Printing/):
|
||||
- `create(array $data): int` — INSERT, zwraca ID
|
||||
- `findPending(): array` — SELECT WHERE status = 'pending' ORDER BY created_at ASC
|
||||
- `findById(int $id): ?array` — z JOIN na orders (internal_order_number) i shipment_packages (tracking_number)
|
||||
- `markCompleted(int $id): void` — SET status = 'completed', completed_at = NOW()
|
||||
- `markFailed(int $id, string $reason): void` — SET status = 'failed'
|
||||
- Używać PDO + prepared statements
|
||||
|
||||
**ApiKeyMiddleware** (src/Modules/Printing/):
|
||||
- Callable `__invoke(Request $request, callable $next): Response`
|
||||
- Odczytuje header `X-Api-Key` z requestu
|
||||
- Hashuje klucz (SHA-256), szuka w print_api_keys przez PrintApiKeyRepository
|
||||
- Jeśli znaleziony i is_active = 1: updateLastUsed(), przekazuje do $next
|
||||
- Jeśli brak/nieaktywny: zwraca Response::json(['error' => 'Unauthorized'], 401)
|
||||
- Wzorzec: analogiczny do AuthMiddleware ale dla API
|
||||
|
||||
**PrintApiController** (src/Modules/Printing/):
|
||||
- Constructor DI: PrintJobRepository, Request, AuthService
|
||||
- `createJob(Request $request): Response` — POST /api/print/jobs
|
||||
- Wymaga session auth (AuthMiddleware) — wywoływane z UI orderPRO
|
||||
- Przyjmuje: package_id (required)
|
||||
- Waliduje: shipment_packages.label_path istnieje i plik fizycznie istnieje
|
||||
- Tworzy print_job ze statusem 'pending'
|
||||
- Zwraca JSON: { id, status: 'pending' }
|
||||
- `listPending(Request $request): Response` — GET /api/print/jobs/pending
|
||||
- Wymaga API key (ApiKeyMiddleware)
|
||||
- Zwraca JSON: lista pending jobs z: id, order_number, tracking_number, created_at
|
||||
- `downloadLabel(Request $request): Response` — GET /api/print/jobs/{id}/download
|
||||
- Wymaga API key
|
||||
- Waliduje: job istnieje, plik istnieje
|
||||
- Zwraca plik PDF (Content-Type: application/pdf)
|
||||
- `markComplete(Request $request): Response` — PATCH /api/print/jobs/{id}/complete
|
||||
- Wymaga API key
|
||||
- Oznacza job jako completed
|
||||
- Zwraca JSON: { id, status: 'completed' }
|
||||
|
||||
**PrintSettingsController** (src/Modules/Settings/):
|
||||
- `index(Request $request): Response` — lista kluczy API (widok settings/printing)
|
||||
- `createKey(Request $request): Response` — POST: generuje klucz (bin2hex(random_bytes(32))), hashuje SHA-256, zapisuje hash+prefix, zwraca klucz jednorazowo we flash message
|
||||
- `deleteKey(Request $request): Response` — POST: usuwa klucz
|
||||
|
||||
**Routes** (routes/web.php):
|
||||
Dodać na końcu pliku:
|
||||
```php
|
||||
// Print API — session auth (from orderPRO UI)
|
||||
$router->post('/api/print/jobs', [$printApiController, 'createJob'], [$authMiddleware]);
|
||||
|
||||
// Print API — API key auth (from Windows client)
|
||||
$router->get('/api/print/jobs/pending', [$printApiController, 'listPending'], [$apiKeyMiddleware]);
|
||||
$router->get('/api/print/jobs/{id}/download', [$printApiController, 'downloadLabel'], [$apiKeyMiddleware]);
|
||||
$router->post('/api/print/jobs/{id}/complete', [$printApiController, 'markComplete'], [$apiKeyMiddleware]);
|
||||
|
||||
// Print settings
|
||||
$router->get('/settings/printing', [$printSettingsController, 'index'], [$authMiddleware]);
|
||||
$router->post('/settings/printing/keys/create', [$printSettingsController, 'createKey'], [$authMiddleware]);
|
||||
$router->post('/settings/printing/keys/{id}/delete', [$printSettingsController, 'deleteKey'], [$authMiddleware]);
|
||||
```
|
||||
|
||||
DI: Zarejestrować nowe klasy w Application.php (lub tam gdzie inne moduły są rejestrowane).
|
||||
|
||||
Avoid:
|
||||
- Nie używać PATCH (router może nie obsługiwać) — użyć POST dla markComplete
|
||||
- Nie sklejać SQL — tylko prepared statements
|
||||
- Nie przechowywać klucza API w plaintext — tylko hash SHA-256
|
||||
</action>
|
||||
<verify>
|
||||
1. Sprawdzić czy pliki PHP nie mają błędów składni: php -l na każdym pliku
|
||||
2. Sprawdzić czy routes/web.php parsuje się poprawnie
|
||||
</verify>
|
||||
<done>AC-2 partially (backend), AC-3, AC-4, AC-5, AC-6 satisfied: API endpoints działają z prawidłowym auth</done>
|
||||
</task>
|
||||
|
||||
<task type="checkpoint:human-verify" gate="blocking">
|
||||
<what-built>
|
||||
Backend do zdalnego drukowania:
|
||||
- Tabele DB: print_jobs, print_api_keys
|
||||
- REST API: 4 endpointy (create job, list pending, download, complete)
|
||||
- API key middleware (X-Api-Key header)
|
||||
- CRUD kluczy API w ustawieniach (backend only — widok w fazie 19)
|
||||
</what-built>
|
||||
<how-to-verify>
|
||||
1. Uruchom aplikację — sprawdź czy migracja przeszła (brak błędów)
|
||||
2. Otwórz /settings/printing — powinien załadować się widok (nawet pusty)
|
||||
3. Opcjonalnie: testuj API curlem
|
||||
</how-to-verify>
|
||||
<resume-signal>Type "approved" to continue, or describe issues to fix</resume-signal>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- src/Modules/Shipments/* (nie modyfikować istniejącego flow etykiet)
|
||||
- src/Modules/Auth/AuthMiddleware.php (nie zmieniać session auth)
|
||||
- src/Core/Routing/Router.php (nie modyfikować routera)
|
||||
- database/migrations/ istniejące pliki (nie zmieniać)
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Tylko backend — brak widoków HTML (oprócz minimalnego dla settings/printing)
|
||||
- Brak integracji z przyciskiem "Drukuj" w widoku przesyłek (faza 19)
|
||||
- Brak aplikacji Windows (faza 20)
|
||||
- Widok settings/printing: minimalna lista kluczy + formularz tworzenia (pełny design w fazie 19)
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] Migracja SQL wykonuje się bez błędów
|
||||
- [ ] php -l bez błędów na wszystkich nowych plikach
|
||||
- [ ] GET /api/print/jobs/pending bez klucza → 401
|
||||
- [ ] POST /settings/printing/keys/create tworzy klucz
|
||||
- [ ] Routing nie psuje istniejących endpointów
|
||||
- [ ] All acceptance criteria met
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- All tasks completed
|
||||
- All verification checks pass
|
||||
- No errors or warnings introduced
|
||||
- API key auth działa (valid key → 200, invalid → 401)
|
||||
- Print jobs CRUD przez API
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.paul/phases/18-print-queue-backend/18-01-SUMMARY.md`
|
||||
</output>
|
||||
138
.paul/phases/18-print-queue-backend/18-01-SUMMARY.md
Normal file
138
.paul/phases/18-print-queue-backend/18-01-SUMMARY.md
Normal file
@@ -0,0 +1,138 @@
|
||||
---
|
||||
phase: 18-print-queue-backend
|
||||
plan: 01
|
||||
subsystem: api
|
||||
tags: [printing, api-key, rest-api, middleware, remote-printing]
|
||||
|
||||
requires: []
|
||||
provides:
|
||||
- Print jobs REST API (create, list pending, download, complete)
|
||||
- API key authentication middleware (X-Api-Key header)
|
||||
- Print settings UI (CRUD kluczy API)
|
||||
- Request::header() method
|
||||
affects: [19-ui-integration, 20-windows-client]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [api-key-auth, sha256-hashing, rest-json-api]
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- database/migrations/20260322_000058_create_print_tables.sql
|
||||
- src/Modules/Printing/PrintApiKeyRepository.php
|
||||
- src/Modules/Printing/PrintJobRepository.php
|
||||
- src/Modules/Printing/PrintApiController.php
|
||||
- src/Modules/Printing/ApiKeyMiddleware.php
|
||||
- src/Modules/Settings/PrintSettingsController.php
|
||||
- resources/views/settings/printing.php
|
||||
modified:
|
||||
- src/Core/Http/Request.php
|
||||
- resources/views/layouts/app.php
|
||||
- routes/web.php
|
||||
|
||||
key-decisions:
|
||||
- "FK constraints removed from print_jobs — type mismatch between orders (INT UNSIGNED) and shipment_packages (BIGINT UNSIGNED)"
|
||||
- "API key stored as SHA-256 hash, prefix saved for identification"
|
||||
- "Request::header() method added to core Request class for API key extraction"
|
||||
|
||||
patterns-established:
|
||||
- "API key auth: ApiKeyMiddleware reads X-Api-Key, hashes SHA-256, validates against print_api_keys"
|
||||
- "Flash key convention: settings_error, settings_success, settings_new_api_key (underscore, not dot)"
|
||||
|
||||
duration: 25min
|
||||
started: 2026-03-22T00:00:00Z
|
||||
completed: 2026-03-22T00:25:00Z
|
||||
---
|
||||
|
||||
# Phase 18 Plan 01: Print Queue Backend Summary
|
||||
|
||||
**REST API do zdalnego drukowania etykiet — tabele DB, API key auth middleware, 4 endpointy JSON, CRUD kluczy API w ustawieniach.**
|
||||
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Duration | ~25min |
|
||||
| Tasks | 3 completed (2 auto + 1 checkpoint) |
|
||||
| Files created | 7 |
|
||||
| Files modified | 3 |
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| AC-1: Tabele DB utworzone poprawnie | Pass | print_api_keys + print_jobs, bez FK (type mismatch) |
|
||||
| AC-2: CRUD kluczy API w ustawieniach | Pass | Tworzenie, wyświetlanie, usuwanie kluczy |
|
||||
| AC-3: API — tworzenie zlecenia wydruku | Pass | POST /api/print/jobs z session auth |
|
||||
| AC-4: API — pobieranie zleceń i etykiet | Pass | GET /api/print/jobs/pending + download |
|
||||
| AC-5: API — oznaczanie jako wydrukowane | Pass | POST /api/print/jobs/{id}/complete |
|
||||
| AC-6: Nieprawidłowy klucz API odrzucony | Pass | 401 Unauthorized z JSON |
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Moduł Printing: PrintApiKeyRepository, PrintJobRepository, PrintApiController, ApiKeyMiddleware
|
||||
- REST API: 4 endpointy (create job, list pending, download label, mark complete)
|
||||
- API key auth: SHA-256 hash, prefix do identyfikacji, last_used_at tracking
|
||||
- Settings UI: lista kluczy + jednorazowe wyświetlenie nowego klucza
|
||||
- Request::header() method w core — reusable dla przyszłych API
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
| File | Change | Purpose |
|
||||
|------|--------|---------|
|
||||
| `database/migrations/20260322_000058_create_print_tables.sql` | Created | Tabele print_api_keys + print_jobs |
|
||||
| `src/Modules/Printing/PrintApiKeyRepository.php` | Created | CRUD kluczy API |
|
||||
| `src/Modules/Printing/PrintJobRepository.php` | Created | CRUD zleceń wydruku |
|
||||
| `src/Modules/Printing/PrintApiController.php` | Created | REST API endpointy |
|
||||
| `src/Modules/Printing/ApiKeyMiddleware.php` | Created | Auth middleware X-Api-Key |
|
||||
| `src/Modules/Settings/PrintSettingsController.php` | Created | UI zarządzania kluczami |
|
||||
| `resources/views/settings/printing.php` | Created | Widok ustawień drukowania |
|
||||
| `src/Core/Http/Request.php` | Modified | Dodano header() method |
|
||||
| `resources/views/layouts/app.php` | Modified | Link "Drukowanie" w sidebar |
|
||||
| `routes/web.php` | Modified | 7 nowych route'ów + DI |
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Usunięto FK constraints z print_jobs | orders.id (INT UNSIGNED) vs shipment_packages.order_id (BIGINT UNSIGNED) — type mismatch w produkcji | Integralność referencyjna tylko na poziomie aplikacji |
|
||||
| SHA-256 hash klucza API | Bezpieczeństwo — raw key nigdy nie przechowywany w DB | Klucz wyświetlany jednorazowo po utworzeniu |
|
||||
| Request::header() w core | Potrzebne do X-Api-Key, reusable | Minimalna zmiana core — 1 metoda |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Summary
|
||||
|
||||
| Type | Count | Impact |
|
||||
|------|-------|--------|
|
||||
| Auto-fixed | 1 | FK constraints usunięte — brak wpływu na funkcjonalność |
|
||||
|
||||
**1. FK constraints usunięte z migracji**
|
||||
- **Found during:** Task 1 (migracja)
|
||||
- **Issue:** Type mismatch: orders.id = INT UNSIGNED, shipment_packages.order_id = BIGINT UNSIGNED
|
||||
- **Fix:** Usunięto CONSTRAINT, zostawiono INDEX
|
||||
- **Verification:** Migracja przeszła poprawnie
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| FK errno 150 (1. próba) | Zmieniono BIGINT→INT UNSIGNED + INT→BIGINT UNSIGNED |
|
||||
| FK errno 150 (2. próba) | Usunięto FK constraints całkowicie — type mismatch w produkcji |
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Ready:**
|
||||
- API endpoints gotowe do konsumpcji przez Windows Client (faza 20)
|
||||
- API key auth działa — klient może się uwierzytelnić
|
||||
- Przycisk "Drukuj" w UI (faza 19) może wywoływać POST /api/print/jobs
|
||||
|
||||
**Concerns:**
|
||||
- Brak FK constraints — integralność tylko na poziomie aplikacji
|
||||
|
||||
**Blockers:**
|
||||
- None
|
||||
|
||||
---
|
||||
*Phase: 18-print-queue-backend, Plan: 01*
|
||||
*Completed: 2026-03-22*
|
||||
Reference in New Issue
Block a user