Phase 127 complete: - add global Erli settings schema and encrypted API key repository - add real read-only Erli API connection test and settings UI - expose Erli in integrations hub and update PAUL/docs state
13 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
| phase | plan | type | wave | depends_on | files_modified | autonomous | delegation | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 127-erli-integration-foundation | 01 | execute | 1 |
|
true | auto |
Purpose
Erli is the next sales channel in orderPRO. This plan creates the same kind of safe integration footing that Allegro, Fakturownia, HostedSMS and SMSPLANET already use, without starting order import, label generation, status sync or tracking yet.
Output
- New
erli_integration_settingstable linked to oneintegrations.type='erli'row. - New Settings module classes for Erli configuration and API connection testing.
- New
/settings/integrations/erliscreen with save/test actions. - Erli visible in
/settings/integrations. - Documentation updated for schema, architecture and technical changelog.
Project Context
@.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md @.paul/codebase/architecture.md @.paul/codebase/db_schema.md
Required Project Docs
@DOCS/DB_SCHEMA.md @DOCS/ARCHITECTURE.md @DOCS/TECH_CHANGELOG.md
Existing Patterns To Reuse
@src/Modules/Settings/FakturowniaIntegrationRepository.php @src/Modules/Settings/FakturowniaIntegrationController.php @src/Modules/Settings/FakturowniaApiClient.php @src/Modules/Settings/SmsplanetIntegrationRepository.php @src/Modules/Settings/SmsplanetIntegrationController.php @src/Modules/Settings/IntegrationsHubController.php @src/Modules/Settings/IntegrationsRepository.php @resources/views/settings/fakturownia.php @resources/views/settings/smsplanet.php @database/migrations/20260512_000108_create_smsplanet_integration_settings.sql @routes/web.php @resources/lang/pl.php
External API Reference
Erli API documentation: https://erli.pl/svc/shop-api/doc/
- REST API over HTTPS.
- Authorization uses Bearer API key in the
Authorizationheader. - Requests should include a meaningful
User-Agent. - Rate limiting can return HTTP 429.
- For this plan, use a safe read-only documented endpoint for connection testing, preferably the inbox endpoint (
/inbox) with a small limit if supported by the docs.
| Skill | Priority | When to Invoke | Loaded? |
|---|---|---|---|
| /feature-dev | optional | New marketplace integration work | ○ |
| /code-review | optional | After implementation, before UNIFY | ○ |
| /frontend-design | optional | New settings UI screen | ○ |
| sonar-scanner | required | After APPLY, before UNIFY | ○ |
BLOCKING: sonar-scanner is required after APPLY and before UNIFY when available in PATH.
<acceptance_criteria>
AC-1: Schema And Single Integration Row
Given migrations are run
When the Erli foundation migration executes
Then the database contains exactly one global `erli_integration_settings` row linked to one `integrations.type='erli'` row
And the settings table stores the API key only in encrypted form
And the migration is idempotent when run again
AC-2: Save Erli Configuration
Given an authenticated operator opens `/settings/integrations/erli`
When they enter an API key, optional seller/account label, and active flag, then submit the form with a valid CSRF token
Then the configuration is saved
And returning to the screen shows that the secret is saved without revealing the raw API key
And invalid or missing required values produce a Polish error flash
AC-3: Real API Connection Test
Given a complete and active Erli configuration is saved
When the operator clicks "Test polaczenia"
Then orderPRO sends a real authenticated read-only request to the Erli API
And stores `last_test_status`, `last_test_http_code`, `last_test_message`, and `last_test_at` in `integrations`
And the UI shows a readable success or failure result
AC-4: Integrations Hub Visibility
Given the operator opens `/settings/integrations`
When the hub renders integration rows
Then Erli appears with configured/missing secret status, active status, last test timestamp, and a configure link to `/settings/integrations/erli`
AC-5: Documentation Updated
Given Phase 127 changes are implemented
When documentation is reviewed
Then `DOCS/DB_SCHEMA.md`, `DOCS/ARCHITECTURE.md`, and `DOCS/TECH_CHANGELOG.md` describe the new Erli table, classes, routes, and decision boundaries
</acceptance_criteria>
Task 1: Create Erli settings schema and repository database/migrations/20260515_000114_create_erli_integration_settings.sql, src/Modules/Settings/ErliIntegrationRepository.php Create an idempotent migration for a single global Erli configuration: - Insert or update base `integrations` row: `type='erli'`, `name='Erli'`, production API `base_url` from official docs, timeout around 15 seconds, active by default. - Create `erli_integration_settings` with `id TINYINT UNSIGNED PRIMARY KEY` fixed at 1, nullable unique `integration_id` FK to `integrations(id)`, `api_key_encrypted TEXT NULL`, optional `account_label VARCHAR(128) NULL`, timestamps, and no sandbox/environment column. - Insert row `id=1` linked to the Erli integration via `ON DUPLICATE KEY UPDATE`. - Avoid `SELECT 1` no-op migrations; use real DDL/DML only, matching the project migration rule.Create `ErliIntegrationRepository`:
- Mirror single-instance patterns from `FakturowniaIntegrationRepository` and `SmsplanetIntegrationRepository`.
- Use `IntegrationSecretCipher` for API key encryption/decryption.
- Expose `getSettings()`, `saveSettings(array $payload)`, `getCredentials(): ?array`, and private helpers for `ensureBaseIntegration()`, `ensureRow()`, validation and decryption.
- Preserve saved secret when the API key input is left empty on edit.
- Validate required API key on first save and active flag on the base integration.
- Use PDO prepared statements only.
`php -l src/Modules/Settings/ErliIntegrationRepository.php` and review migration SQL for idempotent `CREATE TABLE IF NOT EXISTS` + `ON DUPLICATE KEY UPDATE`
AC-1 and AC-2 schema/repository portions satisfied
Task 2: Add Erli API client, controller, routes and settings view
src/Modules/Settings/ErliApiClient.php, src/Modules/Settings/ErliIntegrationController.php, routes/web.php, resources/views/settings/erli.php, resources/lang/pl.php
Create `ErliApiClient`:
- Implement `testConnection(array $credentials): array{ok: bool, http_code: int, message: string}`.
- Send a real authenticated GET request to a read-only Erli endpoint from the official docs, preferably `/inbox` with a minimal limit when supported.
- Use `Authorization: Bearer {api_key}`, `Accept: application/json`, and `User-Agent: orderPRO/1.0 (+contact/orderpro)` style header.
- Use cURL with `SslCertificateResolver::resolve()`, timeouts, SSL verification, JSON/error parsing and no `curl_close()`.
- Treat 2xx as success, 401/403 as auth failure, 429 as rate-limit failure with readable Polish message, and other non-2xx as failure with a safe body snippet.
Create `ErliIntegrationController`:
- Actions: `index`, `save`, `test`.
- Use CSRF `_token`, `Flash`, `RedirectPathResolver`, and existing layout conventions.
- `test` must load saved credentials, call `ErliApiClient::testConnection()`, then write result via `IntegrationsRepository::updateTestResult()`.
Wire in `routes/web.php`:
- Instantiate repository/client/controller with existing `$app->db()` and integration secret.
- Register authenticated routes: `GET /settings/integrations/erli`, `POST /settings/integrations/erli/save`, `POST /settings/integrations/erli/test`.
Create `resources/views/settings/erli.php`:
- Compact settings page consistent with Fakturownia/SMSPLANET pages.
- Fields: account label (optional), API key password input with saved/missing hint, active checkbox.
- Test section with button/form and last test panel.
- Use reusable alert component includes; do not add inline CSS, native `alert()` or `confirm()`.
Add translation keys under settings for Erli provider labels, form fields, flash messages and hub provider name.
`php -l src/Modules/Settings/ErliApiClient.php`, `php -l src/Modules/Settings/ErliIntegrationController.php`, `php -l resources/views/settings/erli.php`, and `php -l routes/web.php`
AC-2 and AC-3 satisfied: operator can save Erli config and run a real API test
Task 3: Add Erli to hub and update technical documentation
src/Modules/Settings/IntegrationsHubController.php, DOCS/DB_SCHEMA.md, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md
Update `IntegrationsHubController`:
- Add `ErliIntegrationRepository` constructor dependency.
- Add `buildErliRow()` mirroring Fakturownia/SMSPLANET single-instance hub rows.
- Include Erli in the rows array with configured/missing secret status, active status, last test timestamp, and configure URL `/settings/integrations/erli`.
- Keep constructor wiring in `routes/web.php` consistent with the new dependency from Task 2.
Update documentation:
- `DOCS/DB_SCHEMA.md`: add `erli_integration_settings` under Integrations with columns, FK, single-row constraint, and encrypted secret note.
- `DOCS/ARCHITECTURE.md`: add Erli foundation classes/routes to Settings and hub integration sections; explicitly state import/status/shipments are deferred to phases 128-131.
- `DOCS/TECH_CHANGELOG.md`: add a 2026-05-15 Phase 127 Plan 01 entry explaining what changed and why.
`php -l src/Modules/Settings/IntegrationsHubController.php` and text search confirms `Erli` appears in hub translations/docs
AC-4 and AC-5 satisfied
DO NOT CHANGE
- Do not modify Allegro, shopPRO, Fakturownia, HostedSMS or SMSPLANET behavior except for constructor wiring needed to add Erli to the hub.
- Do not change order import,
OrderImportRepository, order list/detail behavior, shipment creation, tracking, status mapping, statistics aggregation, or automation execution in this plan. - Do not introduce
DB_HOST_REMOTEinto runtime configuration. - Do not store raw Erli API keys in plaintext, logs, flash messages, docs, or views.
SCOPE LIMITS
- No order import from Erli in Phase 127; that starts in Phase 128.
- No Erli status mapping or status sync in Phase 127; that starts in Phase 129.
- No label generation or shipment integration in Phase 127; that starts in Phase 130.
- No tracking or automation hooks in Phase 127; that starts in Phase 131.
- No sandbox/environment switch per user clarification.
- No new frontend build requirement unless existing SCSS already requires it for changed shared styles; this plan should use existing compact form/card classes.
<success_criteria>
- Erli has one global encrypted configuration in DB.
- Operator can save Erli API key without exposing it after save.
- Test connection performs a real authenticated read-only Erli API request and persists the result.
- Erli appears in the integrations hub.
- Documentation reflects the new schema and architecture.
- No unrelated marketplace/order/shipment behavior changed. </success_criteria>