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>
13 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, delegation
| phase | plan | type | wave | depends_on | files_modified | autonomous | delegation | |||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 121-smsplanet-conversation-notifications | 01 | execute | 1 |
|
true | auto |
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.
- **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.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
## 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-scannerafter implementation, then record any new issues inDOCS/todo.mdaccording to.paul/SPECIAL-FLOWS.md.
<acceptance_criteria>
AC-1: SMSPLANET Sender Mode
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
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
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
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
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
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>
Task 1: Add SMS and notification persistence plus backend services 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 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`. `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. AC-1, AC-2, AC-3 and AC-5 persistence/backend behavior satisfied. Task 2: Add SMS settings UI and order conversation tab 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 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`. `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. AC-1, AC-2 and AC-4 satisfied in UI. Task 3: Add global notification center with polling and browser notifications 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 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. `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. AC-5 and AC-6 satisfied.DO NOT CHANGE
- Do not add runtime usage of
DB_HOST_REMOTE; runtime continues to useDB_HOST. - Do not add native
alert()orconfirm()in views or JS; use existing alert module if confirmation/feedback is needed. - Do not inline CSS in views; use
resources/scss/app.scssand 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.
<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>