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>
237 lines
13 KiB
Markdown
237 lines
13 KiB
Markdown
---
|
|
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>
|