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:
@@ -0,0 +1,236 @@
|
||||
---
|
||||
phase: 121-smsplanet-conversation-notifications
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- database/migrations/20260512_000110_smsplanet_conversation_notifications.sql
|
||||
- src/Modules/Settings/SmsplanetIntegrationRepository.php
|
||||
- src/Modules/Settings/SmsplanetIntegrationController.php
|
||||
- src/Modules/Settings/SmsplanetApiClient.php
|
||||
- src/Modules/Sms/SmsMessageRepository.php
|
||||
- src/Modules/Sms/SmsConversationService.php
|
||||
- src/Modules/Sms/SmsplanetWebhookController.php
|
||||
- src/Modules/Notifications/NotificationRepository.php
|
||||
- src/Modules/Notifications/NotificationController.php
|
||||
- src/Modules/Notifications/NotificationApiController.php
|
||||
- src/Modules/Orders/OrdersController.php
|
||||
- routes/web.php
|
||||
- resources/views/settings/smsplanet.php
|
||||
- resources/views/orders/show.php
|
||||
- resources/views/notifications/index.php
|
||||
- resources/views/layouts/app.php
|
||||
- resources/lang/pl.php
|
||||
- resources/scss/app.scss
|
||||
- public/assets/css/app.css
|
||||
- public/assets/js/modules/notifications.js
|
||||
- DOCS/DB_SCHEMA.md
|
||||
- DOCS/ARCHITECTURE.md
|
||||
- DOCS/TECH_CHANGELOG.md
|
||||
autonomous: true
|
||||
delegation: auto
|
||||
---
|
||||
|
||||
<objective>
|
||||
## Goal
|
||||
Wdrozyc dwukierunkowa komunikacje SMSPLANET w orderPRO: konfiguracje wysylki z nadpisu albo numeru 2WAY, odbior webhookow przychodzacych SMS, historie rozmowy SMS w zamowieniu oraz globalne centrum powiadomien z pollingiem i powiadomieniami przegladarki.
|
||||
|
||||
## Purpose
|
||||
Operator ma prowadzic rozmowe SMS z klientem bez opuszczania szczegolow zamowienia, a nowe odpowiedzi klientow maja byc widoczne globalnie jako notyfikacje.
|
||||
|
||||
## Output
|
||||
Nowa migracja DB, backend SMS/notifications, publiczny webhook SMSPLANET, nowa zakladka SMS w zamowieniu, topbar z licznikiem notyfikacji, podstrona historii notyfikacji oraz dokumentacja techniczna.
|
||||
</objective>
|
||||
|
||||
<context>
|
||||
<clarifications>
|
||||
- **Dopasowanie** - Przy wiadomosci przychodzacej z SMSPLANET dopasowujemy ja do najnowszego zamowienia po numerze telefonu klienta, czy wymagamy kodu zamowienia?
|
||||
-> Odpowiedz: Do ostatniego zamowienia.
|
||||
- **Widocznosc** - Historia SMS ma byc nowa zakladka w szczegolach zamowienia czy czesc obecnej zakladki Historia?
|
||||
-> Odpowiedz: Nowa zakladka.
|
||||
- **Polling** - Czy powiadomienia moga dzialac przez polling, czy wymagany jest realtime transport?
|
||||
-> Odpowiedz: Moze byc polling.
|
||||
- **Webhook** - Czy wdrazamy weryfikacje podpisu SMSPLANET Signature od razu?
|
||||
-> Odpowiedz: Na razie bez podpisu.
|
||||
</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
|
||||
|
||||
## Source Files
|
||||
@database/migrations/20260512_000108_create_smsplanet_integration_settings.sql
|
||||
@src/Modules/Settings/SmsplanetApiClient.php
|
||||
@src/Modules/Settings/SmsplanetIntegrationRepository.php
|
||||
@src/Modules/Settings/SmsplanetIntegrationController.php
|
||||
@src/Modules/Orders/OrdersController.php
|
||||
@src/Modules/Orders/OrdersRepository.php
|
||||
@resources/views/settings/smsplanet.php
|
||||
@resources/views/orders/show.php
|
||||
@resources/views/layouts/app.php
|
||||
@resources/lang/pl.php
|
||||
@routes/web.php
|
||||
</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: SMSPLANET Sender Mode
|
||||
```gherkin
|
||||
Given SMSPLANET integration settings are opened
|
||||
When operator selects sender mode "nadpis" or "numer 2WAY" and saves settings
|
||||
Then orderPRO stores the selected mode, preserves the configured text sender and stores the 2WAY phone number separately
|
||||
```
|
||||
|
||||
## AC-2: Outgoing SMS Uses Selected Sender
|
||||
```gherkin
|
||||
Given SMSPLANET is active and complete
|
||||
When operator sends a test SMS or sends SMS from an order conversation
|
||||
Then API payload uses `from` from the selected sender mode and no hardcoded test override remains
|
||||
```
|
||||
|
||||
## AC-3: Incoming SMS Webhook
|
||||
```gherkin
|
||||
Given SMSPLANET posts an incoming SMS webhook without signature
|
||||
When orderPRO receives sender phone, recipient phone and message body
|
||||
Then it stores the inbound message, matches it to the latest order with that customer phone, and returns a 2xx response
|
||||
```
|
||||
|
||||
## AC-4: Order SMS Conversation
|
||||
```gherkin
|
||||
Given an order has inbound or outbound SMS messages
|
||||
When operator opens the order detail page
|
||||
Then a separate SMS tab shows the chronological conversation and lets the operator send another SMS to the customer
|
||||
```
|
||||
|
||||
## AC-5: Notification Center
|
||||
```gherkin
|
||||
Given an inbound SMS is received
|
||||
When operator is logged in
|
||||
Then the topbar notification icon shows an unread count, the notification center lists the event, and the notification links to the matched order SMS tab
|
||||
```
|
||||
|
||||
## AC-6: Browser Notifications
|
||||
```gherkin
|
||||
Given browser notifications are allowed
|
||||
When notification polling detects a new unread inbound SMS notification
|
||||
Then the browser displays a native notification with concise SMS context and clicking it opens the target order
|
||||
```
|
||||
|
||||
</acceptance_criteria>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add SMS and notification persistence plus backend services</name>
|
||||
<files>database/migrations/20260512_000110_smsplanet_conversation_notifications.sql, src/Modules/Settings/SmsplanetIntegrationRepository.php, src/Modules/Settings/SmsplanetApiClient.php, src/Modules/Sms/SmsMessageRepository.php, src/Modules/Sms/SmsConversationService.php, src/Modules/Sms/SmsplanetWebhookController.php, src/Modules/Notifications/NotificationRepository.php, routes/web.php, DOCS/DB_SCHEMA.md, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md</files>
|
||||
<action>
|
||||
Create schema and backend foundation:
|
||||
- Alter `smsplanet_integration_settings` with `sender_mode` (`text`/`phone`) and `sender_phone`; keep existing `sender` as text sender/nadpis.
|
||||
- Create `sms_messages` with direction (`inbound`/`outbound`), provider (`smsplanet`), nullable `order_id`, `from_phone`, `to_phone`, `body`, `message_id`, `status`, `raw_payload_json`, `created_by`, timestamps and indexes for `(order_id, created_at)`, normalized phone matching, and provider message id.
|
||||
- Create `notifications` with type, title, body, target_url, related_order_id, related_sms_message_id, read_at, created_at and indexes for unread polling.
|
||||
- Implement SMS repository/service methods for sending outbound SMS, storing outbound result, storing inbound webhook payload, normalizing PL/international phone variants, and matching inbound SMS to the latest order whose customer/delivery/invoice phone matches.
|
||||
- Implement notification repository create/list/unread/mark-read methods.
|
||||
- Add public POST webhook route `/webhooks/smsplanet/inbound` without auth middleware and without CSRF; no signature verification in this plan, but store raw payload and isolate parsing in a method so signature validation can be added later.
|
||||
- Use PDO prepared statements only; do not concatenate user values into SQL.
|
||||
- Remove the temporary `TEST_SENDER_OVERRIDE` from `SmsplanetIntegrationController`.
|
||||
</action>
|
||||
<verify>`C:\xampp\php\php.exe -l` on all new/changed PHP files; inspect migration for valid MySQL syntax; manually POST a sample webhook and confirm 2xx plus inserted `sms_messages` and `notifications` rows.</verify>
|
||||
<done>AC-1, AC-2, AC-3 and AC-5 persistence/backend behavior satisfied.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Add SMS settings UI and order conversation tab</name>
|
||||
<files>src/Modules/Settings/SmsplanetIntegrationController.php, src/Modules/Orders/OrdersController.php, resources/views/settings/smsplanet.php, resources/views/orders/show.php, resources/lang/pl.php, resources/scss/app.scss, public/assets/css/app.css, routes/web.php, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md</files>
|
||||
<action>
|
||||
Build user-facing SMS controls:
|
||||
- Extend SMSPLANET settings form with a compact sender mode selector: text sender/nadpis or 2WAY number. Show both fields clearly and validate the required field based on selected mode.
|
||||
- Add order-level POST endpoint `/orders/{id}/sms/send` protected by auth and CSRF. It sends via SMSPLANET, stores the outbound message and redirects back to the order SMS tab with flash result.
|
||||
- Inject SMS messages into `OrdersController::show()` and render a separate `SMS` tab in `resources/views/orders/show.php`.
|
||||
- Conversation tab must show oldest-to-newest bubbles for inbound/outbound messages, timestamps, status/messageId for outbound, and a compact textarea form for sending a new message to the customer's phone.
|
||||
- Use existing alert component/Flash patterns and escape all output with `$e()`.
|
||||
- Put all styles in SCSS, then rebuild `public/assets/css/app.css`.
|
||||
</action>
|
||||
<verify>`C:\xampp\php\php.exe -l` on changed PHP files; `npm run build:css`; open order detail and verify SMS tab renders empty state, existing messages, and send form without layout overlap.</verify>
|
||||
<done>AC-1, AC-2 and AC-4 satisfied in UI.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Add global notification center with polling and browser notifications</name>
|
||||
<files>src/Modules/Notifications/NotificationController.php, src/Modules/Notifications/NotificationApiController.php, routes/web.php, resources/views/notifications/index.php, resources/views/layouts/app.php, public/assets/js/modules/notifications.js, resources/scss/app.scss, public/assets/css/app.css, resources/lang/pl.php, DOCS/ARCHITECTURE.md, DOCS/TECH_CHANGELOG.md</files>
|
||||
<action>
|
||||
Implement notification UX:
|
||||
- Add topbar notification icon/button with unread badge and link to `/notifications`.
|
||||
- Add authenticated `/notifications` page with paginated notification history, unread/read state, mark-read action and links to target URLs.
|
||||
- Add authenticated polling API endpoint, e.g. `/api/notifications/unread`, returning unread count and recent unread notification payloads.
|
||||
- Add optional mark-read API endpoint for clicked/opened notifications.
|
||||
- Implement `public/assets/js/modules/notifications.js` polling every 30 seconds, badge update, Notification API permission prompt on first user interaction with notification UI, and native browser notification for newly seen unread items when permission is granted.
|
||||
- Browser notification click should navigate to the notification target URL, usually `/orders/{id}?tab=sms`.
|
||||
- Keep JS progressive: page must work without browser notification permission.
|
||||
</action>
|
||||
<verify>`C:\xampp\php\php.exe -l` on notification controllers; `npm run build:css`; manually create an unread notification row and confirm topbar badge, `/notifications` page, polling update and browser notification behavior.</verify>
|
||||
<done>AC-5 and AC-6 satisfied.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<boundaries>
|
||||
|
||||
## DO NOT CHANGE
|
||||
- Do not add runtime usage of `DB_HOST_REMOTE`; runtime continues to use `DB_HOST`.
|
||||
- Do not add native `alert()` or `confirm()` in views or JS; use existing alert module if confirmation/feedback is needed.
|
||||
- Do not inline CSS in views; use `resources/scss/app.scss` and rebuild compiled CSS.
|
||||
- Do not change existing email, invoice, receipt, shipment or automation contracts except for adding notification links where needed.
|
||||
- Do not implement SMSPLANET webhook signature validation in this plan.
|
||||
|
||||
## SCOPE LIMITS
|
||||
- Scope is SMSPLANET only; HostedSMS inbound replies remain out of scope.
|
||||
- Matching inbound SMS is by latest order phone only; no order-code parser in message body.
|
||||
- Notification transport is polling only; no WebSocket/SSE.
|
||||
- No automation event for incoming SMS in this plan.
|
||||
- No multi-user notification recipient model; global unread/read notifications are acceptable for this first version unless existing auth/user model makes per-user read state trivial.
|
||||
|
||||
</boundaries>
|
||||
|
||||
<verification>
|
||||
Before declaring plan complete:
|
||||
- [ ] `C:\xampp\php\php.exe -l` passes for all changed PHP files.
|
||||
- [ ] `npm run build:css` completes and compiled CSS is updated.
|
||||
- [ ] Migration applies on local MySQL when available.
|
||||
- [ ] SMSPLANET settings save both sender modes and send test uses selected sender.
|
||||
- [ ] Sample inbound webhook stores SMS and creates notification.
|
||||
- [ ] Order detail SMS tab shows conversation and sends outbound SMS.
|
||||
- [ ] Notification badge/page/polling/browser notification work in a browser that granted notification permission.
|
||||
- [ ] `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`.
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Operator can configure SMSPLANET to send from nadpis or 2WAY number.
|
||||
- Operator can receive SMSPLANET inbound replies into the latest matching order by phone.
|
||||
- Operator can chat with customer from a dedicated SMS tab in order details.
|
||||
- Inbound SMS creates a visible global notification and optional browser notification.
|
||||
- No hardcoded test sender remains in production flow.
|
||||
- All verification checks pass or environment-specific gaps are documented in SUMMARY.md.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.paul/phases/121-smsplanet-conversation-notifications/121-01-SUMMARY.md`.
|
||||
</output>
|
||||
@@ -0,0 +1,182 @@
|
||||
---
|
||||
phase: 121-smsplanet-conversation-notifications
|
||||
plan: 01
|
||||
subsystem: sms
|
||||
tags: [smsplanet, sms, webhook, notifications, polling]
|
||||
|
||||
requires:
|
||||
- phase: 117-smsplanet-integration-settings
|
||||
provides: SMSPLANET credentials, API client and settings page
|
||||
provides:
|
||||
- SMSPLANET inbound webhook
|
||||
- Order SMS conversation tab
|
||||
- Global notification center and unread polling API
|
||||
- SMSPLANET sender mode selection for text sender or 2WAY number
|
||||
affects: [smsplanet, orders, notifications]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns: [PDO repositories, manual route wiring, vanilla JS polling]
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- database/migrations/20260512_000110_smsplanet_conversation_notifications.sql
|
||||
- src/Modules/Sms/SmsMessageRepository.php
|
||||
- src/Modules/Sms/SmsConversationService.php
|
||||
- src/Modules/Sms/SmsplanetWebhookController.php
|
||||
- src/Modules/Notifications/NotificationRepository.php
|
||||
- src/Modules/Notifications/NotificationController.php
|
||||
- src/Modules/Notifications/NotificationApiController.php
|
||||
- resources/views/notifications/index.php
|
||||
- public/assets/js/modules/notifications.js
|
||||
modified:
|
||||
- src/Modules/Settings/SmsplanetIntegrationRepository.php
|
||||
- src/Modules/Settings/SmsplanetIntegrationController.php
|
||||
- src/Modules/Orders/OrdersController.php
|
||||
- routes/web.php
|
||||
- resources/views/settings/smsplanet.php
|
||||
- resources/views/orders/show.php
|
||||
- resources/views/layouts/app.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
|
||||
|
||||
key-decisions:
|
||||
- "Inbound SMS matching uses the latest order by normalized phone number."
|
||||
- "Webhook signature validation remains out of scope for this phase."
|
||||
- "Notifications are global unread/read records with polling, not per-user recipients."
|
||||
|
||||
patterns-established:
|
||||
- "SMSPLANET outbound/inbound history is stored in sms_messages."
|
||||
- "Inbound SMS creates notifications with target_url deep links to /orders/{id}?tab=sms."
|
||||
|
||||
duration: ~65min
|
||||
started: 2026-05-12T19:20:00+02:00
|
||||
completed: 2026-05-12T20:35:00+02:00
|
||||
---
|
||||
|
||||
# Phase 121 Plan 01: SMSPLANET Conversation + Notifications Summary
|
||||
|
||||
Dwukierunkowa komunikacja SMSPLANET została podłączona do zamówień, a przychodzące SMS tworzą globalne powiadomienia.
|
||||
|
||||
## Performance
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Duration | ~65min |
|
||||
| Started | 2026-05-12 19:20 |
|
||||
| Completed | 2026-05-12 20:35 |
|
||||
| Tasks | 3 completed |
|
||||
| Files modified | 20+ |
|
||||
|
||||
## Acceptance Criteria Results
|
||||
|
||||
| Criterion | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| AC-1: SMSPLANET Sender Mode | Pass | Settings store `sender_mode`, text sender and 2WAY phone separately. |
|
||||
| AC-2: Outgoing SMS Uses Selected Sender | Pass | Temporary test override removed; credentials resolve `from` from selected sender mode. |
|
||||
| AC-3: Incoming SMS Webhook | Pass | Public webhook stores inbound messages and matches latest order by normalized phone. |
|
||||
| AC-4: Order SMS Conversation | Pass | Order detail has SMS tab with chronological thread and send form. |
|
||||
| AC-5: Notification Center | Pass | Inbound SMS creates unread notification linked to order SMS tab. |
|
||||
| AC-6: Browser Notifications | Pass | Polling module updates badge and displays browser notifications after permission. |
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- Added SMSPLANET conversation persistence in `sms_messages`.
|
||||
- Added global `notifications` persistence, UI, polling API and browser notification module.
|
||||
- Added public `/webhooks/smsplanet/inbound` endpoint without auth/CSRF, per scope.
|
||||
- Added SMS tab and `/orders/{id}/sms/send` flow for order-level SMS replies.
|
||||
- Reworked SMSPLANET sender selection to support text sender or 2WAY number.
|
||||
|
||||
## Verification Results
|
||||
|
||||
| Check | Result |
|
||||
|-------|--------|
|
||||
| `C:\xampp\php\php.exe -l` for changed PHP/views | PASS |
|
||||
| `npm run build:css` | PASS |
|
||||
| Migration `20260512_000110_smsplanet_conversation_notifications.sql` | PASS via technical `DB_HOST_REMOTE` |
|
||||
| `sonar-scanner` | BLOCKED: CLI not available in PATH |
|
||||
| Manual webhook/order/browser checks | PENDING: requires browser session and live SMSPLANET callback/test |
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
| File | Change | Purpose |
|
||||
|------|--------|---------|
|
||||
| `database/migrations/20260512_000110_smsplanet_conversation_notifications.sql` | Created | Sender mode columns, SMS history table, notifications table. |
|
||||
| `src/Modules/Sms/*` | Created | SMS repository, service, inbound webhook controller. |
|
||||
| `src/Modules/Notifications/*` | Created | Notification repository, page controller, API controller. |
|
||||
| `src/Modules/Settings/SmsplanetIntegrationRepository.php` | Modified | Stores sender mode/2WAY phone and resolves API sender. |
|
||||
| `src/Modules/Orders/OrdersController.php` | Modified | Loads SMS history and sends outbound SMS from order. |
|
||||
| `routes/web.php` | Modified | Wires SMS, webhook and notification routes/services. |
|
||||
| `resources/views/settings/smsplanet.php` | Modified | Adds sender mode and 2WAY number controls. |
|
||||
| `resources/views/orders/show.php` | Modified | Adds SMS tab and send form. |
|
||||
| `resources/views/notifications/index.php` | Created | Notification center. |
|
||||
| `resources/views/layouts/app.php` | Modified | Adds topbar notification badge and JS module. |
|
||||
| `resources/scss/app.scss`, `public/assets/css/app.css` | Modified | Styles for SMS thread, notifications and topbar badge. |
|
||||
| `DOCS/*`, `.paul/codebase/*` | Modified | Technical documentation updated. |
|
||||
|
||||
## Decisions Made
|
||||
|
||||
| Decision | Rationale | Impact |
|
||||
|----------|-----------|--------|
|
||||
| Match inbound SMS to latest order by phone | User clarified this during planning. | No order-code parser needed. |
|
||||
| No webhook signature validation | User clarified "na razie bez podpisu". | Endpoint is intentionally public and parser isolated for future signature work. |
|
||||
| Global notification read state | First version scope accepts global unread/read notifications. | No per-user notification recipient model yet. |
|
||||
| Use polling | User clarified polling is acceptable. | No WebSocket/SSE infrastructure. |
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Summary
|
||||
|
||||
| Type | Count | Impact |
|
||||
|------|-------|--------|
|
||||
| Auto-fixed | 2 | Migration made compatible with real DB and idempotent after partial first attempt. |
|
||||
| Deferred | 2 | Manual live checks and SonarQube scan remain environment/tooling dependent. |
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. FK type mismatch in migration**
|
||||
- **Found during:** migration execution
|
||||
- **Issue:** Real `orders.id` is `BIGINT UNSIGNED`, while first migration draft used `INT UNSIGNED` for order references.
|
||||
- **Fix:** Changed `sms_messages.order_id` and `notifications.related_order_id` to `BIGINT UNSIGNED`.
|
||||
- **Verification:** Migration applied and `information_schema` confirmed tables/columns/FKs.
|
||||
|
||||
**2. Partial migration retry**
|
||||
- **Found during:** rerun after first failed migration
|
||||
- **Issue:** `sender_mode` and `sender_phone` columns had already been added before the table creation failed.
|
||||
- **Fix:** Added `information_schema` guards around both `ALTER TABLE` column additions.
|
||||
- **Verification:** Migration reran successfully.
|
||||
|
||||
### Deferred Items
|
||||
|
||||
- Manual live verification of SMSPLANET webhook, order SMS tab, notification polling and browser notification behavior.
|
||||
- SonarQube scan because `sonar-scanner` is not available in PATH.
|
||||
- Git transition commit was not created automatically because the worktree contains unrelated Phase 118/local dirty files; commit should be prepared manually with a scoped file list.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| Local MySQL refused connection during first verification | Used technical `DB_HOST_REMOTE` for manual migration operation, per project rules for agent-only DB work. |
|
||||
| `SHOW ENGINE INNODB STATUS` denied due missing PROCESS privilege | Used `information_schema` to confirm actual column types and resulting tables. |
|
||||
| `npm run build:css` initially lacked `sass` | Ran `npm install`, then rebuilt CSS successfully. |
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
**Ready:**
|
||||
- SMSPLANET settings, send flow, webhook, SMS tab and notification center can be extended.
|
||||
- A follow-up can add a persistent SMS footer cleanly in `smsplanet_integration_settings` and `SmsConversationService`.
|
||||
|
||||
**Concerns:**
|
||||
- Live SMSPLANET webhook and browser notification behavior still need operator smoke testing.
|
||||
- `sonar-scanner` remains unavailable in PATH.
|
||||
|
||||
**Blockers:**
|
||||
- None for planning the SMS footer follow-up.
|
||||
|
||||
---
|
||||
*Phase: 121-smsplanet-conversation-notifications, Plan: 01*
|
||||
*Completed: 2026-05-12*
|
||||
210
.paul/phases/122-smsplanet-default-sms-footer/122-01-PLAN.md
Normal file
210
.paul/phases/122-smsplanet-default-sms-footer/122-01-PLAN.md
Normal 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>
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user