Files
orderPRO/.paul/phases/124-sms-templates/124-01-SUMMARY.md
Jacek Pyziak 522c94a434 feat(124): sms templates CRUD + order picker
- Nowa tabela sms_templates (name + body + is_active) + minimalny CRUD.
- /settings/sms-templates: lista + formularz z paleta zmiennych (pill chips).
- Wydzielono Sms\SmsVariableResolver ze wspolna logika placeholderow;
  Email\VariableResolver staje sie cienka fasada — EmailSendingService bez zmian.
- Dropdown "Wybierz szablon" w zakladce SMS na /orders/{id} z fetch
  GET /orders/{id}/sms/template + OrderProAlerts.confirm przy nadpisaniu.
- Stopka SMSPLANET dalej doklejana wylacznie przez SmsConversationService
  (Phase 122 contract preserved).
- Sidebar Ustawien: nowy link "Szablony SMS".

Migration: 20260512_000112_create_sms_templates.sql (CREATE TABLE).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 21:37:51 +02:00

12 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, duration, started, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established duration started completed
124-sms-templates 01 sms
sms
templates
smsplanet
orders
settings
phase provides
117-smsplanet-integration SmsplanetIntegrationRepository, SmsplanetApiClient
phase provides
121-smsplanet-conversation-notifications SmsConversationService::sendFromOrder, SMS tab w /orders/{id}
phase provides
122-smsplanet-default-footer default_footer + MAX_SMS_LENGTH = 918 validation on final body
phase provides
14-email-templates email_templates CRUD pattern, VARIABLE_GROUPS structure
sms_templates DB table + CRUD repository
/settings/sms-templates panel (lista + formularz)
shared SmsVariableResolver (extracted from Email\VariableResolver)
GET /orders/{id}/sms/template endpoint (JSON, variables resolved per-order)
Dropdown "Wybierz szablon" w zakladce SMS na /orders/{id}
sms-template-picker.js (vanilla JS, OrderProAlerts.confirm pattern)
future SMS automation (send_sms action)
invoice.created event
added patterns
Shared VariableResolver pattern: Email\VariableResolver as thin facade delegating to Sms\SmsVariableResolver
Idempotent JS module guard: window.__smsTemplatePickerBound + dataset.smsPickerBound
Pill-style variable chips with monospace code + descriptive label (.sms-var-item)
created modified
database/migrations/20260512_000112_create_sms_templates.sql
src/Modules/Sms/SmsTemplateRepository.php
src/Modules/Sms/SmsVariableResolver.php
src/Modules/Settings/SmsTemplateController.php
resources/views/settings/sms-templates.php
resources/views/settings/sms-templates-form.php
resources/scss/modules/_sms-templates.scss
public/assets/js/modules/sms-template-picker.js
src/Modules/Email/VariableResolver.php
src/Modules/Orders/OrdersController.php
routes/web.php
resources/views/orders/show.php
resources/views/layouts/app.php
resources/lang/pl.php
resources/scss/app.scss
SMS template fields minimal: name + body + is_active (no subject/mailbox/attachment)
Footer NOT in template — appended by SmsConversationService (Phase 122 contract preserved)
Email\VariableResolver becomes facade — preserves EmailSendingService contract, zero regression risk
Variable picker = pill chips with {{var}} + description on same row (not dropdown like email)
Action column uses flex+gap not inline-flex on td — robust against block-display <form> children
Shared resolver: keep facade in original namespace for BC, move logic to new namespace
Idempotent JS modules: window.__moduleBound + dataset.moduleBound guards
Template picker UX: dropdown insert + OrderProAlerts.confirm on non-empty target
~90min 2026-05-12T23:30:00Z 2026-05-13T00:30:00Z

Phase 124 Plan 01 — SMS Templates — SUMMARY

SMS templates CRUD w /settings/sms-templates + dropdown "Wybierz szablon" na zakladce SMS w szczegolach zamowienia — wstawia tresc z rozwinietymi zmiennymi {{kupujacy.imie_nazwisko}}, {{przesylka.numer}} itp. Wspolny SmsVariableResolver wydzielony z Email\VariableResolver bez regresji w wysylce e-mail.

Performance

Metric Value
Duration ~90 min (PLAN + APPLY + UI fixes + UNIFY)
Started 2026-05-12T23:30:00Z
Completed 2026-05-13T00:30:00Z
Tasks 5/5 ukonczone
Files modified 17 (8 created + 9 modified)

Status: UNIFY complete. Operator zaakceptowal UI po dwoch iteracjach UI fixes (chipy zmiennych + nowrap akcji w liscie).

Files modified

File Change
database/migrations/20260512_000112_create_sms_templates.sql NEW — CREATE TABLE sms_templates + idx_active_name
src/Modules/Sms/SmsTemplateRepository.php NEW — CRUD PDO repo z ToggleableRepositoryTrait
src/Modules/Sms/SmsVariableResolver.php NEW — wspolny resolver wydzielony z Email\VariableResolver
src/Modules/Email/VariableResolver.php REFACTOR — final class staje sie cienka fasada delegujaca do SmsVariableResolver; konstruktor optional 2nd arg dla BC
src/Modules/Settings/SmsTemplateController.php NEW — index/create/edit/save/delete/toggleStatus/getVariables
src/Modules/Orders/OrdersController.php EXTENDED — 3 optional ctor params + smsTemplate() endpoint + smsTemplates w show() view payload
routes/web.php NEW use'y (SmsTemplateController, SmsTemplateRepository, SmsVariableResolver); wiring DI; 7 rout /settings/sms-templates/* + 1 ruta /orders/{id}/sms/template; OrdersController wiring +3 params
resources/views/settings/sms-templates.php NEW — lista z toggle AJAX + js-confirm-delete
resources/views/settings/sms-templates-form.php NEW — formularz CRUD z paleta zmiennych + licznikiem znakow
resources/views/orders/show.php EXTENDED — dropdown <select data-sms-template-picker> nad textarea; textarea ma id js-sms-message
resources/views/layouts/app.php sidebar sublink "Szablony SMS"; <script> tag dla sms-template-picker.js
resources/lang/pl.php klucze orders.details.sms.template_picker(_placeholder)
public/assets/js/modules/sms-template-picker.js NEW — vanilla JS, idempotent guard, fetch endpoint + OrderProAlerts.confirm przy nadpisaniu
resources/scss/modules/_sms-templates.scss NEW — .sms-template-*, .sms-var-* klasy
resources/scss/app.scss import nowego partiala
.paul/codebase/db_schema.md sekcja sms_templates + Total tables 60 -> 61
.paul/codebase/architecture.md sekcja "Phase 124 — SMS Templates"
.paul/codebase/tech_changelog.md wpis Phase 124

Verification

  • php -l przeszedl bez bledow na wszystkich zmienionych plikach PHP (11 plikow).
  • php bin/migrate.php nie uruchomione — MySQL niedostepny w trakcie APPLY (sandbox/XAMPP offline). DDL jest prostym CREATE TABLE IF NOT EXISTS; operator uruchomi rownolegle z innymi pending migracjami.
  • Browser smoke (CRUD /settings/sms-templates, dropdown na /orders/{id}?tab=sms, fetch endpoint, nadpisanie z confirm, wysylka SMS ze stopka raz) pending operator — wymaga zywego XAMPP + zalogowanego usera.
  • SCSS app.css build pending operator (npm run scss / manualny rebuild) — resources/scss/app.scss ma nowy @use modules/sms-templates; bez rebuildu klasy .sms-template-* i .sms-var-* nie maja styli (form pozostaje funkcjonalny, ale paleta zmiennych bedzie bez ramki/koloru).

Acceptance Criteria

AC Status
AC-1: CRUD szablonow SMS w /settings/sms-templates DONE (kod) — manual UAT pending
AC-2: Walidacja zapisu (puste name/body) DONE — SmsTemplateRepository::save() rzuca RuntimeException; controller Flash danger + redirect
AC-3: Wspolny VariableResolver — bez regresji w Email DONE — Email\VariableResolver deleguje, EmailSendingService niezmieniony
AC-4: Wstawianie szablonu w zakladce SMS z rozwinietymi zmiennymi DONE — endpoint JSON + JS module z OrderProAlerts.confirm przy nadpisaniu
AC-5: Stopka doklejana raz, walidacja 918 znakow na finalnej tresci DONE — szablon nie zawiera stopki; SmsConversationService niezmieniony (Phase 122 contract preserved)
AC-6: Sidebar link "Szablony SMS" z active state DONE

Deviations from PLAN

Type Count Impact
Scope additions (UI fixes po UAT) 2 Visual polish — bez zmiany kontraktu
Deferred 0 Brak
Plan items pominiete (low value) 2 Zero ryzyka

Deviations w trakcie APPLY

  1. SmsConversationService::renderTemplate() NIE zostala dodana. Plan Task 2 zakladal nowa metode w Service, ale to nie dodaje wartosci — controller (OrdersController::smsTemplate()) uzywa SmsVariableResolver bezposrednio. Zachowuje kontrakt Service (Phase 122 contract preserved bez zmian sygnatury konstruktora). Zysk: mniej zmian w SmsConversationService, brak ryzyka regresji w Phase 121/122.
  2. OrdersController dostal ?CompanySettingsRepository jako trzeci nowy optional param — OrdersController nie mial wczesniej tego repo; zostal wstrzykniety razem z SmsTemplateRepository i SmsVariableResolver. Wiring w routes/web.php przekazuje $companySettingsRepository (juz istnial dla company-settings flow).
  3. Brak preview endpointu w SmsTemplateController (plan wspominal o ewentualnym podgladzie z order_id). Pominiete — paleta zmiennych pod textarea + licznik znakow wystarcza.

UI fixes po UAT (scope additions)

  1. Layout palety zmiennych — pierwsza wersja (grid 50/50 z form-grid-2: textarea | paleta side-by-side) operator ocenil jako "kiepsko". Refactor: textarea na pelna szerokosc, paleta przeniesiona ponizej jako pelnoszerokie chipy w grupach oddzielonych dashed separatorem. Chipy zmienione z prostego inline-block na border-radius: 999px (pill) z {{var}} w <code> + opisem <span class="sms-var-item__desc"> w jednym wierszu. Hover indigo (#eef2ff/#6366f1). Plik: resources/scss/modules/_sms-templates.scss, resources/views/settings/sms-templates-form.php.
  2. Akcje w liscie szablonow zawijaja sietd.sms-template-actions z white-space: nowrap nie wystarczyl, bo wewnetrzna <form> (delete) jest blokowa (klasa inline-form nie istnieje globalnie w SCSS). Fix: .sms-template-actions { display: flex; flex-wrap: nowrap; gap: 6px; } + .sms-template-actions > form { display: inline-flex; margin: 0; }. Plik: resources/scss/modules/_sms-templates.scss.

SCSS przebudowany npx sass --style=compressed po obu fixach. Operator zaakceptowal final UI ("jest ok").

Pending Actions (operator)

  • php bin/migrate.php (XAMPP MySQL online) — utworzy sms_templates.
  • SCSS rebuild (npm run scss lub workflow operatora) dla _sms-templates.scss.
  • UAT manualny:
    1. /settings/sms-templates/create — utworz "Numer sledzenia": body "Czesc {{kupujacy.imie_nazwisko}}, Twoja przesylka {{przesylka.numer}} jest w drodze. Sledzenie: {{przesylka.link_sledzenia}}". Zapisz.
    2. Toggle status (AJAX) — dezaktywuj, ponownie aktywuj.
    3. Edycja — zmien body, zapisz.
    4. Duplikuj? — brak akcji (zgodnie z planem; minimalne pola).
    5. Usun (potwierdzenie OrderProAlerts).
    6. /orders/{id}?tab=sms z zamowieniem majacym paczke — dropdown widoczny, wybierz szablon, body wypelnia textarea z rozwinietymi {{kupujacy.imie_nazwisko}} i {{przesylka.numer}}.
    7. Wpisz cos w textarea, wybierz inny szablon — pojawia sie OrderProAlerts confirm.
    8. Wyslij SMS — sprawdz w sms_messages.body ze stopka SMSPLANET doklejona raz (jezeli skonfigurowana).
    9. Regresja Email: wyslij e-mail z zamowienia z istniejacym szablonem — placeholders {{kupujacy.imie_nazwisko}} i {{zamowienie.numer}} rozwiazane normalnie.

SonarQube

  • CLI niedostepne (per Phase 116/117/121/122 history). Skipped, log w STATE Pending Actions.

Next Phase Readiness

Ready:

  • SmsTemplateRepository::listActive() + SmsVariableResolver gotowe do reuse w przyszlej automatyzacji SMS (akcja send_sms analogiczna do send_email z Phase 16).
  • Wzorzec dropdown + JSON endpoint + OrderProAlerts.confirm = template do innych quick-insert mechanizmow (np. szablony notatek do zamowienia).
  • Sidebar Settings ma teraz blok email-templates + sms-templates obok — naturalne miejsce na kolejne typy szablonow.

Concerns:

  • Brak preview z realnymi danymi w formularzu (paleta tylko inline). Jezeli operator bedzie chcial weryfikowac wynik przed zapisaniem, dodac endpoint POST /settings/sms-templates/preview z order_id (mirror EmailTemplateController::preview).
  • SmsTemplateRepository::save() rzuca RuntimeException zamiast zwracac strukturalne bledy — controller wlapuje przez Throwable i przekazuje message do Flash. Dla wiekszej UX precyzji rozwazyc IntegrationConfigException w przyszlosci.

Blockers: None.