feat(121+122): smsplanet conversation, notifications, default footer

Phase 121 — SMSPLANET Conversation + Notifications:
- migration 20260512_000110 adds smsplanet conversation + notifications tables
- src/Modules/Sms (SmsConversationService, SmsMessageRepository, SmsplanetWebhookController)
- src/Modules/Notifications (Repository, Controller, ApiController)
- order SMS tab, notification center, sender mode, inbound webhook
- public notifications.js + layouts/app.php integration

Phase 122 — SMSPLANET Default SMS Footer:
- migration 20260512_000111 adds smsplanet_integration_settings.default_footer
- footer appended to test SMS and order SMS, validated against 918 char limit
- settings textarea + compact order SMS note when footer configured

Bundled (could not split per-phase without hunk staging):
- routes/web.php (also carries Phase 118 fakturownia redirects)
- DOCS/{ARCHITECTURE,DB_SCHEMA,TECH_CHANGELOG}.md (118 + 121 + 122 entries)
- .paul/codebase/{architecture,db_schema,tech_changelog}.md (118 + 121 + 122)
- .paul/STATE.md, ROADMAP.md, changelog/2026-05-12.md (UNIFY closure)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-05-12 20:37:41 +02:00
parent 8f14851d85
commit 360eef128d
34 changed files with 2538 additions and 128 deletions

View File

@@ -0,0 +1,210 @@
---
phase: 122-smsplanet-default-sms-footer
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- database/migrations/20260512_000111_smsplanet_default_footer.sql
- src/Modules/Settings/SmsplanetIntegrationRepository.php
- src/Modules/Settings/SmsplanetIntegrationController.php
- src/Modules/Sms/SmsConversationService.php
- resources/views/settings/smsplanet.php
- resources/views/orders/show.php
- resources/lang/pl.php
- resources/scss/app.scss
- public/assets/css/app.css
- DOCS/DB_SCHEMA.md
- DOCS/ARCHITECTURE.md
- DOCS/TECH_CHANGELOG.md
autonomous: true
delegation: off
---
<objective>
## Goal
Dodać w konfiguracji SMSPLANET opcjonalną stałą stopkę, która jest automatycznie dopisywana do każdego SMS wychodzącego przez SMSPLANET.
## Purpose
Operator ma ustawić jeden wspólny podpis/stopkę firmy bez ręcznego kopiowania jej w każdej wiadomości SMS z zamówienia lub testu integracji.
## Output
Nowa migracja DB, rozszerzona konfiguracja SMSPLANET, dopinanie stopki w backendzie wysyłki, widoczna informacja w UI zamówienia oraz aktualizacja dokumentacji.
</objective>
<context>
<clarifications>
- **Doprecyzowania** — Czy plan wymaga dodatkowych pytań przed utworzeniem?
→ Odpowiedź: Nie. Przyjęte założenia: stopka jest opcjonalna; pusta wartość wyłącza funkcję; stopka dotyczy testowych SMS i SMS z zamówienia; finalna treść po dopięciu stopki musi mieścić się w limicie 918 znaków; w historii rozmowy zapisujemy finalną treść wysłaną do SMSPLANET.
</clarifications>
## Project Context
@.paul/PROJECT.md
@.paul/ROADMAP.md
@.paul/STATE.md
@.paul/codebase/architecture.md
@.paul/codebase/db_schema.md
@AGENTS.md
@DOCS/ARCHITECTURE.md
@DOCS/DB_SCHEMA.md
@.paul/phases/121-smsplanet-conversation-notifications/121-01-SUMMARY.md
## Source Files
@src/Modules/Settings/SmsplanetIntegrationRepository.php
@src/Modules/Settings/SmsplanetIntegrationController.php
@src/Modules/Settings/SmsplanetApiClient.php
@src/Modules/Sms/SmsConversationService.php
@resources/views/settings/smsplanet.php
@resources/views/orders/show.php
@resources/lang/pl.php
@resources/scss/app.scss
</context>
<skills>
## Required Skills (from SPECIAL-FLOWS.md)
| Skill | Priority | When to Invoke | Loaded? |
|-------|----------|----------------|---------|
| sonar-scanner CLI | required | After APPLY, before UNIFY | not loaded |
## Skill Invocation Checklist
- [ ] Run `sonar-scanner` after implementation, then record any new issues in `DOCS/todo.md` according to `.paul/SPECIAL-FLOWS.md`.
</skills>
<acceptance_criteria>
## AC-1: Footer Configuration
```gherkin
Given SMSPLANET integration settings are opened
When operator enters a default SMS footer and saves settings
Then orderPRO stores the footer separately from sender/auth settings and shows it again on reload
```
## AC-2: Footer Applied to Test SMS
```gherkin
Given a default SMS footer is configured
When operator sends a test SMS from SMSPLANET settings
Then the payload sent to SMSPLANET contains the test message with the footer appended exactly once
```
## AC-3: Footer Applied to Order SMS
```gherkin
Given a default SMS footer is configured
When operator sends SMS from the order conversation tab
Then SMSPLANET receives the message body with the footer appended and sms_messages stores the final sent body
```
## AC-4: Empty Footer Does Nothing
```gherkin
Given the default SMS footer is empty
When operator sends a test SMS or an order SMS
Then the outgoing message body remains unchanged
```
## AC-5: Length Validation Uses Final Body
```gherkin
Given message text plus configured footer would exceed 918 characters
When operator tries to send SMS
Then orderPRO rejects the send with a clear validation error before calling SMSPLANET
```
</acceptance_criteria>
<tasks>
<task type="auto">
<name>Task 1: Persist SMSPLANET default footer</name>
<files>database/migrations/20260512_000111_smsplanet_default_footer.sql, src/Modules/Settings/SmsplanetIntegrationRepository.php, src/Modules/Settings/SmsplanetIntegrationController.php, DOCS/DB_SCHEMA.md, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md</files>
<action>
Add persistence and settings contract:
- Create migration adding nullable `default_footer` TEXT column to `smsplanet_integration_settings`.
- Make migration idempotent using `information_schema.COLUMNS`, because Phase 121 showed migrations may be retried after partial execution.
- Extend `SmsplanetIntegrationRepository::getSettings()` and `getCredentials()` to expose trimmed `default_footer`.
- Extend `saveSettings()` to accept and store `default_footer`; normalize line endings, trim surrounding whitespace, allow empty/null.
- Validate footer length conservatively (max 300 characters) so the setting cannot consume the whole SMS limit.
- Extend `SmsplanetIntegrationController::save()` to pass the new field.
- Update DB/architecture/changelog docs with the new column and footer behavior.
- Use PDO prepared statements only.
</action>
<verify>`C:\xampp\php\php.exe -l` on changed PHP files; inspect migration for valid MySQL syntax and idempotent guards.</verify>
<done>AC-1 persistence/contract satisfied.</done>
</task>
<task type="auto">
<name>Task 2: Apply footer to every outbound SMSPLANET send</name>
<files>src/Modules/Settings/SmsplanetIntegrationController.php, src/Modules/Sms/SmsConversationService.php, resources/views/orders/show.php, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md</files>
<action>
Apply footer in backend send paths:
- Add a small private method in `SmsConversationService` to build the final outbound body from user text plus `credentials['default_footer']`.
- Use a blank line separator between message body and footer when footer is non-empty.
- Ensure footer is appended exactly once per send operation; do not mutate the stored configuration value.
- Validate the final message body length against the existing 918-character limit before calling `SmsplanetApiClient`.
- Store the final sent body in `sms_messages.body`, because conversation history should match what customer received.
- Apply the same final-body logic in `SmsplanetIntegrationController::test()` before `sendSms()`, with a shared helper if practical without over-abstracting.
- Show a compact note in the order SMS form that a configured footer will be added automatically; do not inline CSS.
</action>
<verify>`C:\xampp\php\php.exe -l` on changed PHP files/views; manually review that SMSPLANET API calls receive final body and no double footer path exists.</verify>
<done>AC-2, AC-3, AC-4 and AC-5 satisfied.</done>
</task>
<task type="auto">
<name>Task 3: Add footer UI and rebuild styles</name>
<files>resources/views/settings/smsplanet.php, resources/lang/pl.php, resources/scss/app.scss, public/assets/css/app.css, DOCS/TECH_CHANGELOG.md</files>
<action>
Add compact UI for footer:
- Add textarea in SMSPLANET settings form labeled as default SMS footer.
- Keep UI compact and aligned with the existing two-column settings layout.
- Add hint explaining that footer is appended to test SMS and order conversation SMS.
- Escape all output with `$e()`.
- Put any needed layout styling in `resources/scss/app.scss`; do not add inline styles.
- Rebuild `public/assets/css/app.css`.
</action>
<verify>`C:\xampp\php\php.exe -l resources/views/settings/smsplanet.php resources/lang/pl.php`; `npm run build:css`.</verify>
<done>AC-1 UI satisfied and compiled CSS updated.</done>
</task>
</tasks>
<boundaries>
## DO NOT CHANGE
- Do not modify runtime DB host handling; `DB_HOST_REMOTE` remains agent-only for manual DB operations.
- Do not alter inbound webhook parsing or phone/order matching except if needed to keep PHP syntax valid.
- Do not add native `alert()` or `confirm()`.
- Do not inline CSS in views.
- Do not add a new SMS provider or change HostedSMS behavior.
- Do not implement per-order/per-user footer overrides in this plan.
## SCOPE LIMITS
- Footer is global SMSPLANET-only configuration.
- Footer applies only to outbound SMSPLANET sends from settings test and order conversation.
- No UI preview/counter is required in this plan unless it is trivial and does not expand scope.
- No automatic migration run on production is required during planning; APPLY should attempt migration when environment is available.
</boundaries>
<verification>
Before declaring plan complete:
- [ ] `C:\xampp\php\php.exe -l` passes for changed PHP files and PHP views.
- [ ] `npm run build:css` completes.
- [ ] Migration applies when DB is available.
- [ ] SMSPLANET settings save and reload footer.
- [ ] Test SMS uses message plus footer.
- [ ] Order SMS uses message plus footer and stores final body.
- [ ] Empty footer leaves body unchanged.
- [ ] Over-limit final body is rejected before SMSPLANET API call.
- [ ] `DOCS/DB_SCHEMA.md`, `DOCS/ARCHITECTURE.md`, `DOCS/TECH_CHANGELOG.md` updated.
- [ ] `sonar-scanner` attempted after APPLY; new issues recorded per `.paul/SPECIAL-FLOWS.md` if scan runs.
</verification>
<success_criteria>
- Operator can configure one persistent SMSPLANET default footer.
- Every outbound SMSPLANET message includes the footer exactly once when configured.
- History stores the actual final sent SMS body.
- Existing sender mode, inbound webhook and notification behavior remain unchanged.
- Verification passes or environment-specific gaps are documented in SUMMARY.md.
</success_criteria>
<output>
After completion, create `.paul/phases/122-smsplanet-default-sms-footer/122-01-SUMMARY.md`.
</output>

View File

@@ -0,0 +1,50 @@
---
phase: 122-smsplanet-default-sms-footer
plan: 01
status: applied
applied_at: 2026-05-12 21:25:00
---
# APPLY Summary - Phase 122 Plan 01
## Tasks Completed
- Task 1: Persist SMSPLANET default footer - PASS
- Task 2: Apply footer to every outbound SMSPLANET send - PASS
- Task 3: Add footer UI and rebuild styles - PASS
## Implemented
- Added `database/migrations/20260512_000111_smsplanet_default_footer.sql` with idempotent `information_schema.COLUMNS` guard for `smsplanet_integration_settings.default_footer`.
- Extended `SmsplanetIntegrationRepository` to expose, validate, normalize, persist, and return `default_footer`.
- Extended SMSPLANET settings save/test flow so test SMS uses final body with footer and validates the final body against 918 characters.
- Extended `SmsConversationService` so order SMS uses final body with footer, stores final body in `sms_messages.body`, and rejects over-limit final body before API call.
- Added SMSPLANET settings textarea and compact order SMS note when a footer is configured.
- Updated `DOCS/DB_SCHEMA.md`, `DOCS/ARCHITECTURE.md`, `DOCS/TECH_CHANGELOG.md`, and PAUL codebase docs.
## Verification
- `C:\xampp\php\php.exe -l src/Modules/Settings/SmsplanetIntegrationRepository.php` - PASS
- `C:\xampp\php\php.exe -l src/Modules/Settings/SmsplanetIntegrationController.php` - PASS
- `C:\xampp\php\php.exe -l src/Modules/Sms/SmsConversationService.php` - PASS
- `C:\xampp\php\php.exe -l src/Modules/Orders/OrdersController.php` - PASS
- `C:\xampp\php\php.exe -l resources/views/settings/smsplanet.php` - PASS
- `C:\xampp\php\php.exe -l resources/views/orders/show.php` - PASS
- `C:\xampp\php\php.exe -l resources/lang/pl.php` - PASS
- `npm run build:css` - PASS
- `C:\xampp\php\php.exe bin\migrate.php` with standard `DB_HOST=localhost` - FAIL, local MySQL refused connection.
- Manual migration run with process-only `DB_HOST=DB_HOST_REMOTE` - PASS, `[ok] 20260512_000111_smsplanet_default_footer.sql`.
- `information_schema.COLUMNS` check for `default_footer` - PASS (`TEXT`, nullable).
- `sonar-scanner` - FAIL, CLI not available in PATH.
## Manual Gaps
- Real SMSPLANET test send with configured footer not executed in browser.
- Order conversation SMS send with configured footer not executed in browser.
- Empty-footer send path not manually exercised in browser.
- Over-limit final body rejection reviewed in code but not manually triggered through UI.
## Deviations
- No functional deviation from plan.
- SonarQube scan could not run because `sonar-scanner` is not installed or not in PATH.