feat(116): hostedsms integration settings

Phase 116 complete:
- add HostedSMS settings with encrypted password storage
- add SimpleAPI real test SMS flow and integrations hub row
- document schema, architecture, changelog, and PAUL state

Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
2026-05-12 12:25:07 +02:00
parent adacb65110
commit bc2ed2c8e2
20 changed files with 1282 additions and 56 deletions

View File

@@ -0,0 +1,205 @@
---
phase: 116-hostedsms-integration
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- database/migrations/20260512_000107_create_hostedsms_integration_settings.sql
- src/Modules/Settings/HostedSmsApiClient.php
- src/Modules/Settings/HostedSmsIntegrationRepository.php
- src/Modules/Settings/HostedSmsIntegrationController.php
- src/Modules/Settings/IntegrationsHubController.php
- routes/web.php
- resources/views/settings/hostedsms.php
- resources/views/settings/integrations.php
- resources/views/layouts/app.php
- resources/lang/pl.php
- DOCS/DB_SCHEMA.md
- DOCS/ARCHITECTURE.md
- DOCS/TECH_CHANGELOG.md
- .paul/codebase/db_schema.md
- .paul/codebase/architecture.md
- .paul/codebase/tech_changelog.md
autonomous: true
delegation: auto
---
<objective>
## Goal
Dodac pierwsza wersje integracji HostedSMS: pojedyncza globalna konfiguracja konta oraz formularz realnej wysylki testowego SMS-a z edytowalna trescia.
## Purpose
Operator ma moc potwierdzic, ze dane HostedSMS sa poprawne, zanim integracja zostanie uzyta w automatyzacjach lub komunikacji z klientami.
## Output
Nowa podstrona `/settings/integrations/hostedsms`, zapis konfiguracji w DB, klient API SimpleAPI, akcja testowej wysylki SMS i wpis w hubie integracji.
</objective>
<context>
<clarifications>
- **Test SMS** - Czy test ma faktycznie wysylac wiadomosc?
-> Odpowiedz: Ma faktycznie wysylac testowy sms.
- **Liczba kont** - Jedna globalna konfiguracja czy wiele kont?
-> Odpowiedz: Wystarczy jedna.
- **Tresc testu** - Tresc testowego SMS ma byc stala czy edytowalna?
-> Odpowiedz: Edytowalna.
</clarifications>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
@AGENTS.md
@DOCS/DB_SCHEMA.md
@DOCS/ARCHITECTURE.md
## API Context
HostedSMS SimpleAPI z dokumentacji `https://panel.hostedsms.pl/Doc/HostedSms-Opis_Techniczny_API_pl.pdf`:
- endpoint podstawowy: `POST https://api.hostedsms.pl/SimpleApi`
- endpoint zapasowy: `POST https://api2.hostedsms.pl/SimpleApi`
- pola: `UserEmail`, `Password`, `Sender`, `Phone`, `Message`, opcjonalnie `ConvertMessageToGSM7`
- numer telefonu w formacie miedzynarodowym, np. `48xxxxxxxxx`
- odpowiedz JSON zawiera `MessageId` przy sukcesie albo `ErrorMessage` przy bledzie; HTTP 200 moze oznaczac blad biznesowy
## Source Files
@routes/web.php
@src/Modules/Settings/IntegrationsRepository.php
@src/Modules/Settings/IntegrationSecretCipher.php
@src/Modules/Settings/IntegrationsHubController.php
@src/Modules/Settings/FakturowniaIntegrationRepository.php
@src/Modules/Settings/FakturowniaIntegrationController.php
@src/Modules/Settings/FakturowniaApiClient.php
@resources/views/settings/fakturownia.php
@resources/views/settings/fakturownia-edit.php
@resources/views/settings/integrations.php
@resources/views/layouts/app.php
@resources/lang/pl.php
</context>
<skills>
## Required Skills (from SPECIAL-FLOWS.md)
| Skill | Priority | When to Invoke | Loaded? |
|-------|----------|----------------|---------|
| sonar-scanner | required | Po APPLY, przed UNIFY | o |
## Skill Invocation Checklist
- [ ] Uruchomic `sonar-scanner` po implementacji, jezeli CLI i SonarQube sa dostepne.
</skills>
<acceptance_criteria>
## AC-1: Zapis konfiguracji HostedSMS
```gherkin
Given zalogowany operator jest na stronie ustawien HostedSMS
When wpisze UserEmail, haslo, nadpis Sender, status aktywnosci i zapisze formularz z poprawnym CSRF
Then konfiguracja zostanie zapisana jako jedna globalna integracja, haslo bedzie zaszyfrowane przez IntegrationSecretCipher, a zapisany sekret nie bedzie widoczny w formularzu
```
## AC-2: Walidacja konfiguracji
```gherkin
Given operator probuje zapisac lub testowac HostedSMS
When brakuje loginu, hasla przy pierwszym zapisie, nadpisu Sender albo numer testowy nie jest w formacie miedzynarodowym
Then aplikacja pokazuje czytelny blad i nie wykonuje wysylki testowej bez kompletnych danych
```
## AC-3: Realny test wysylki SMS
```gherkin
Given konfiguracja HostedSMS jest zapisana z poprawnymi danymi
When operator poda numer testowy i edytowalna tresc testowa oraz kliknie wysylke testowa
Then aplikacja wykona POST do HostedSMS SimpleAPI, zapisze wynik w polach last_test_* integracji i pokaze MessageId albo komunikat bledu z API
```
## AC-4: Widocznosc w panelu integracji
```gherkin
Given operator otwiera Ustawienia > Integracje
When integracja HostedSMS istnieje albo jeszcze nie jest skonfigurowana
Then hub pokazuje wiersz HostedSMS ze statusem konfiguracji, aktywnosci, ostatniego testu i linkiem do ustawien
```
## AC-5: Dokumentacja i zgodnosc projektu
```gherkin
Given funkcja zostala wdrozona
When sprawdzane sa dokumenty techniczne i testy
Then DOCS oraz .paul/codebase opisuja nowa tabele, klasy, endpointy i przeplyw, a testy/lint nie wykazuja regresji
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Dodac model konfiguracji HostedSMS</name>
<files>database/migrations/20260512_000107_create_hostedsms_integration_settings.sql, src/Modules/Settings/HostedSmsIntegrationRepository.php</files>
<action>
Utworz migracje dla pojedynczej tabeli `hostedsms_integration_settings` z rekordem `id=1`, `integration_id` jako UNIQUE FK do `integrations`, polami `user_email`, `password_encrypted`, `sender`, `convert_message_to_gsm7`, `created_at`, `updated_at`.
Repozytorium ma zapewniac bazowy rekord `integrations` typu `hostedsms`, nazwa `HostedSMS`, base_url `https://api.hostedsms.pl/SimpleApi`, zwracac status `has_password` bez ujawniania hasla, zapisywac nowe haslo tylko gdy pole formularza nie jest puste, przy pierwszym zapisie wymagac hasla oraz uzywac `IntegrationSecretCipher` i prepared statements.
</action>
<verify>C:\xampp\php\php.exe -l src/Modules/Settings/HostedSmsIntegrationRepository.php</verify>
<done>AC-1 i AC-2 spelnione dla warstwy zapisu konfiguracji.</done>
</task>
<task type="auto">
<name>Task 2: Dodac klienta SimpleAPI i kontroler ustawien</name>
<files>src/Modules/Settings/HostedSmsApiClient.php, src/Modules/Settings/HostedSmsIntegrationController.php, routes/web.php</files>
<action>
Utworz `HostedSmsApiClient` wykonujacy POST form-urlencoded do SimpleAPI z `Accept: application/json`, SSL verification i CA z `SslCertificateResolver`. Parsuj odpowiedz JSON: `MessageId` oznacza sukces, `ErrorMessage` blad biznesowy mimo HTTP 200; blad cURL/HTTP ma trafic do komunikatu.
Utworz `HostedSmsIntegrationController` z akcjami `index`, `save`, `test`. `save` waliduje CSRF, login e-mail, sender i wymaganie hasla przy pierwszym zapisie. `test` waliduje CSRF, numer w formacie miedzynarodowym (`^\d{8,15}$`, z hintem `48...`), tresc niepusta i maks. 4000 znakow. Test realnie wysyla SMS i zapisuje `last_test_status`, `last_test_http_code`, `last_test_message` przez `IntegrationsRepository::updateTestResult`.
Podlacz DI i trasy: GET `/settings/integrations/hostedsms`, POST `/settings/integrations/hostedsms/save`, POST `/settings/integrations/hostedsms/test`.
</action>
<verify>C:\xampp\php\php.exe -l src/Modules/Settings/HostedSmsApiClient.php; C:\xampp\php\php.exe -l src/Modules/Settings/HostedSmsIntegrationController.php; C:\xampp\php\php.exe -l routes/web.php</verify>
<done>AC-2 i AC-3 spelnione dla backendu i realnej wysylki testowej.</done>
</task>
<task type="auto">
<name>Task 3: Dodac UI, hub integracji i dokumentacje</name>
<files>resources/views/settings/hostedsms.php, resources/views/settings/integrations.php, resources/views/layouts/app.php, resources/lang/pl.php, src/Modules/Settings/IntegrationsHubController.php, DOCS/DB_SCHEMA.md, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md, .paul/codebase/db_schema.md, .paul/codebase/architecture.md, .paul/codebase/tech_changelog.md</files>
<action>
Dodaj kompaktowy widok ustawien HostedSMS bez inline CSS w nowych blokach. Formularz konfiguracji ma pokazac pola: UserEmail, nowe haslo (placeholder gdy zapisane), Sender, checkbox konwersji do GSM7, aktywnosc. Sekcja testu ma miec numer telefonu i edytowalna tresc z domyslna wartoscia `Test orderPRO HostedSMS`.
Dodaj HostedSMS do hubu integracji i aktywnego menu ustawien. Jezeli potrzeba nowych styli, umiesc je w SCSS, nie w widoku.
Zaktualizuj dokumentacje techniczna: tabela `hostedsms_integration_settings`, nowe klasy, trasy i przeplyw testowej wysylki.
</action>
<verify>C:\xampp\php\php.exe -l resources/views/settings/hostedsms.php; C:\xampp\php\php.exe -l src/Modules/Settings/IntegrationsHubController.php; npm run build --if-present</verify>
<done>AC-4 i AC-5 spelnione dla UI, hubu i dokumentacji.</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- Nie podpinac `DB_HOST_REMOTE` do runtime aplikacji.
- Nie dodawac automatyzacji SMS, szablonow SMS ani wysylki z zamowien w tym planie.
- Nie dodawac natywnych `alert()` / `confirm()`.
- Nie przenosic ani refaktoryzowac istniejacych integracji poza minimalnym dopieciem HostedSMS.
## SCOPE LIMITS
- Tylko jedna globalna konfiguracja HostedSMS.
- Tylko realna wysylka testowa SMS z ustawien.
- Bez historii wyslanych SMS poza istniejacym `last_test_*` i ewentualnym `integration_test_logs`, jesli aktualny `IntegrationsRepository` juz go uzywa.
- Bez raportow dostarczenia, FullApi, WebService2SMS i endpointu zapasowego `api2` w pierwszej wersji, chyba ze zostanie uzyty jako prosty fallback po bledzie polaczenia.
</boundaries>
<verification>
Before declaring plan complete:
- [ ] `C:\xampp\php\php.exe bin/migrate.php`
- [ ] `C:\xampp\php\php.exe -l` dla nowych/zmienionych plikow PHP
- [ ] `npm run build --if-present`
- [ ] Manualnie: zapis konfiguracji HostedSMS, wysylka testowego SMS na numer w formacie `48...`, komunikat z `MessageId`
- [ ] `sonar-scanner` po APPLY, jezeli CLI i SonarQube sa dostepne
- [ ] DOCS i `.paul/codebase` zaktualizowane
- [ ] All acceptance criteria met
</verification>
<success_criteria>
- Operator moze zapisac jedna konfiguracje HostedSMS bez ujawniania hasla.
- Operator moze wyslac realny testowy SMS z edytowalna trescia.
- Wynik testu jest widoczny w ekranie HostedSMS i hubie integracji.
- Migracje, lint i build przechodza albo blokery srodowiskowe sa jasno opisane w SUMMARY.
</success_criteria>
<output>
After completion, create `.paul/phases/116-hostedsms-integration/116-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,173 @@
---
phase: 116-hostedsms-integration
plan: 01
subsystem: settings-integrations
tags: [hostedsms, sms, api, settings, integration]
requires:
- phase: 113-fakturownia-integration-foundation
provides: integrations hub patterns and encrypted integration settings pattern
provides:
- HostedSMS global settings screen
- HostedSMS SimpleAPI client
- Real test SMS flow with persisted last_test status
affects: [settings, integrations, future-sms-automation]
tech-stack:
added: []
patterns: [single-row integration settings, IntegrationSecretCipher encrypted secret, integrations.last_test observability]
key-files:
created:
- database/migrations/20260512_000107_create_hostedsms_integration_settings.sql
- src/Modules/Settings/HostedSmsApiClient.php
- src/Modules/Settings/HostedSmsIntegrationRepository.php
- src/Modules/Settings/HostedSmsIntegrationController.php
- resources/views/settings/hostedsms.php
modified:
- routes/web.php
- src/Modules/Settings/IntegrationsHubController.php
- resources/lang/pl.php
- DOCS/DB_SCHEMA.md
- DOCS/ARCHITECTURE.md
- DOCS/TECH_CHANGELOG.md
key-decisions:
- "HostedSMS starts as one global account, not multi-account."
- "Test action sends a real SMS because SimpleAPI has no ping endpoint."
- "Inbound SMS replies are deferred; HostedSMS supports inbound retrieval only after DCS/HostedSMS activation."
patterns-established:
- "Provider settings screen stores secrets encrypted and only renders has_secret state."
- "HostedSMS API result uses MessageId as success and ErrorMessage as business failure."
duration: 1h
started: 2026-05-12T10:34:00+02:00
completed: 2026-05-12T12:10:00+02:00
---
# Phase 116 Plan 01: HostedSMS Integration Settings + Test SMS Summary
HostedSMS now has a settings screen, encrypted credential storage, SimpleAPI client, integrations-hub status, and a real test-SMS flow confirmed by the user.
## Performance
| Metric | Value |
|--------|-------|
| Duration | ~1h |
| Started | 2026-05-12T10:34:00+02:00 |
| Completed | 2026-05-12T12:10:00+02:00 |
| Tasks | 3 completed |
| Files modified | 20 |
## Acceptance Criteria Results
| Criterion | Status | Notes |
|-----------|--------|-------|
| AC-1: Zapis konfiguracji HostedSMS | Pass | Global settings row, encrypted password, non-revealing UI implemented. |
| AC-2: Walidacja konfiguracji | Pass | CSRF, e-mail, password, sender, phone and message validation implemented. |
| AC-3: Realny test wysylki SMS | Pass | User confirmed `OK HTTP 200` with MessageId `d935d71a-d9a0-4cfb-be06-03fe36c71150` at `2026-05-12 12:03:22`. |
| AC-4: Widocznosc w panelu integracji | Pass | HostedSMS row added to `/settings/integrations`. |
| AC-5: Dokumentacja i zgodnosc projektu | Pass | DOCS and `.paul/codebase` updated; lint/build passed. Sonar CLI unavailable. |
## Accomplishments
- Added `hostedsms_integration_settings` and idempotent seed of base `integrations` row.
- Added `HostedSmsIntegrationRepository`, `HostedSmsApiClient`, and `HostedSmsIntegrationController`.
- Added routes `GET/POST /settings/integrations/hostedsms...`.
- Added compact UI for settings and editable real test SMS.
- Improved final test display from raw `MessageId: ...` text to a cleaner status panel with date, status, HTTP code and separate message identifier.
- Documented that inbound SMS replies are possible in HostedSMS only through the inbound/Webserwis2SMS side after activation by DCS/HostedSMS, so reply handling is future scope.
## Task Commits
| Task | Commit | Type | Description |
|------|--------|------|-------------|
| Task 1: Model konfiguracji HostedSMS | `ecef7c7` | feat | Migration + repository. |
| Task 2: Klient SimpleAPI i kontroler | `ecef7c7` | feat | API client + controller + routes. |
| Task 3: UI, hub i dokumentacja | `ecef7c7` | feat | Settings view, hub row, translations, docs. |
## Files Created/Modified
| File | Change | Purpose |
|------|--------|---------|
| `database/migrations/20260512_000107_create_hostedsms_integration_settings.sql` | Created | HostedSMS settings table and base integration seed. |
| `src/Modules/Settings/HostedSmsApiClient.php` | Created | HostedSMS SimpleAPI POST client. |
| `src/Modules/Settings/HostedSmsIntegrationRepository.php` | Created | Single-row settings repository with encrypted password. |
| `src/Modules/Settings/HostedSmsIntegrationController.php` | Created | Settings save and real test SMS actions. |
| `resources/views/settings/hostedsms.php` | Created | HostedSMS settings and test UI. |
| `routes/web.php` | Modified | DI wiring and HostedSMS routes. |
| `src/Modules/Settings/IntegrationsHubController.php` | Modified | HostedSMS row in integrations hub. |
| `resources/lang/pl.php` | Modified | Polish UI labels/messages. |
| `DOCS/DB_SCHEMA.md` | Modified | Schema documentation. |
| `DOCS/ARCHITECTURE.md` | Modified | Architecture documentation. |
| `DOCS/TECH_CHANGELOG.md` | Modified | Technical changelog. |
| `.paul/codebase/*` | Modified | PAUL codebase docs mirror. |
| `.paul/PROJECT.md` | Modified | Phase 116 marked as shipped. |
| `.paul/ROADMAP.md` | Modified | Phase 116 marked complete. |
| `.paul/STATE.md` | Modified | Loop closed and next action updated. |
## Decisions Made
| Decision | Rationale | Impact |
|----------|-----------|--------|
| One HostedSMS account | User confirmed one account is enough for first version. | Simpler table and UI; no account selector needed. |
| Real SMS test | User requested actual test SMS and SimpleAPI has no ping endpoint. | Test consumes provider credits but verifies the real path. |
| Editable test message | User requested editable message. | UI exposes a textarea with default `Test orderPRO HostedSMS`. |
| Defer inbound replies | HostedSMS requires inbound interface activation by provider. | Future phase can add `GetUnreadInputSmses` / `GetInputSmses` polling after activation. |
## Deviations from Plan
### Summary
| Type | Count | Impact |
|------|-------|--------|
| Scope additions | 1 | Cosmetic improvement to last-test panel after user feedback. |
| Deferred | 1 | Inbound SMS reply handling deferred. |
### Auto-fixed Issues
**1. Last test display too raw**
- **Found during:** User verification after successful SMS.
- **Issue:** UI showed `MessageId: ...` as plain text.
- **Fix:** Split the persisted MessageId into a separate `Identyfikator wiadomości` row inside a status alert.
- **Files:** `resources/views/settings/hostedsms.php`, `resources/lang/pl.php`, changelog docs.
- **Verification:** PHP lint and user accepted: "jest ok".
### Deferred Items
- HostedSMS inbound replies: Requires provider-side activation of the inbound/Webserwis2SMS feature, then a future plan can poll/store inbound messages.
## Issues Encountered
| Issue | Resolution |
|-------|------------|
| Local migration initially blocked because MySQL refused connection | User later confirmed working test in app, so DB/runtime path is verified. |
| `sonar-scanner` unavailable in PATH | Documented as skill gap; not blocking UNIFY. |
| `vendor/bin/phpunit` missing | Documented; no PHPUnit run. |
## Verification Results
- PASS: PHP lint for new/changed PHP files and view/lang files.
- PASS: `npm run build --if-present`.
- PASS: `git diff --check` with line-ending warnings only.
- PASS: User confirmed real HostedSMS test SMS: `2026-05-12 12:03:22 OK HTTP 200`, MessageId `d935d71a-d9a0-4cfb-be06-03fe36c71150`.
- GAP: `sonar-scanner` not available in PATH.
- GAP: PHPUnit unavailable because `vendor/bin/phpunit` is missing.
## Skill Audit
| Expected | Invoked | Notes |
|----------|---------|-------|
| sonar-scanner | Gap | CLI not found in PATH during APPLY verification. |
## Next Phase Readiness
**Ready:**
- HostedSMS credentials can be saved and verified.
- Future SMS automation can reuse `HostedSmsIntegrationRepository::getCredentials()` and `HostedSmsApiClient::sendSms()`.
**Concerns:**
- Inbound SMS replies require HostedSMS/DCS activation before implementation.
- No persistent SMS send history exists yet beyond `integrations.last_test_*`.
**Blockers:**
- None for closing Phase 116.
---
*Phase: 116-hostedsms-integration, Plan: 01*
*Completed: 2026-05-12*