includio-cms 0.36.9 → 0.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/API.md +178 -3
  2. package/CHANGELOG.md +77 -0
  3. package/DOCS.md +28 -3
  4. package/ROADMAP.md +32 -0
  5. package/dist/admin/client/booking/booking-dashboard.svelte +40 -0
  6. package/dist/admin/client/booking/booking-dashboard.svelte.d.ts +3 -0
  7. package/dist/admin/client/booking/customer-panel.svelte +102 -0
  8. package/dist/admin/client/booking/customer-panel.svelte.d.ts +11 -0
  9. package/dist/admin/client/booking/customer-view.d.ts +52 -0
  10. package/dist/admin/client/booking/customer-view.js +134 -0
  11. package/dist/admin/client/booking/participant-data-panel.svelte +330 -0
  12. package/dist/admin/client/booking/participant-data-panel.svelte.d.ts +22 -0
  13. package/dist/admin/client/booking/reservation-detail-page.svelte +637 -0
  14. package/dist/admin/client/booking/reservation-detail-page.svelte.d.ts +3 -0
  15. package/dist/admin/client/booking/reservations-page.svelte +221 -0
  16. package/dist/admin/client/booking/reservations-page.svelte.d.ts +3 -0
  17. package/dist/admin/client/collection/collection-entries.svelte +1 -1
  18. package/dist/admin/client/collection/entry-link.svelte +6 -4
  19. package/dist/admin/client/collection/entry-link.svelte.d.ts +3 -1
  20. package/dist/admin/client/collection/status-badge.svelte +39 -3
  21. package/dist/admin/client/collection/status-badge.svelte.d.ts +5 -3
  22. package/dist/admin/client/entry/entry.svelte +26 -9
  23. package/dist/admin/client/entry/hybrid/hybrid-preview.svelte +73 -10
  24. package/dist/admin/client/entry/hybrid/hybrid-preview.svelte.d.ts +6 -5
  25. package/dist/admin/client/entry/preview-views-context.svelte.d.ts +22 -0
  26. package/dist/admin/client/entry/preview-views-context.svelte.js +58 -0
  27. package/dist/admin/client/entry/preview-views.d.ts +27 -0
  28. package/dist/admin/client/entry/preview-views.js +33 -0
  29. package/dist/admin/client/index.d.ts +3 -0
  30. package/dist/admin/client/index.js +3 -0
  31. package/dist/admin/client/modules/dashboard-registry.d.ts +7 -0
  32. package/dist/admin/client/modules/dashboard-registry.js +11 -0
  33. package/dist/admin/client/modules/module-dashboard-page.svelte +26 -0
  34. package/dist/admin/client/modules/module-dashboard-page.svelte.d.ts +6 -0
  35. package/dist/admin/client/modules/stat-card.svelte +22 -0
  36. package/dist/admin/client/modules/stat-card.svelte.d.ts +10 -0
  37. package/dist/admin/client/shop/shop-dashboard.svelte +29 -0
  38. package/dist/admin/client/shop/shop-dashboard.svelte.d.ts +3 -0
  39. package/dist/admin/components/fields/relation-field.svelte +11 -2
  40. package/dist/admin/components/icons/icon-map.js +8 -0
  41. package/dist/admin/components/layout/app-sidebar.svelte +45 -14
  42. package/dist/admin/components/layout/context-switcher.svelte +90 -0
  43. package/dist/admin/components/layout/context-switcher.svelte.d.ts +3 -0
  44. package/dist/admin/components/layout/lang.d.ts +4 -0
  45. package/dist/admin/components/layout/lang.js +8 -0
  46. package/dist/admin/components/layout/layout-renderer.svelte +2 -1
  47. package/dist/admin/components/layout/layout-tabs.svelte +14 -0
  48. package/dist/admin/components/layout/layout-tabs.svelte.d.ts +2 -0
  49. package/dist/admin/components/layout/nav-collections.svelte +16 -9
  50. package/dist/admin/components/layout/nav-collections.svelte.d.ts +5 -1
  51. package/dist/admin/components/layout/nav-global.svelte +45 -0
  52. package/dist/admin/components/layout/nav-global.svelte.d.ts +3 -0
  53. package/dist/admin/components/layout/nav-main.svelte +8 -32
  54. package/dist/admin/components/layout/nav-main.svelte.d.ts +6 -1
  55. package/dist/admin/components/layout/nav-module.svelte +57 -0
  56. package/dist/admin/components/layout/nav-module.svelte.d.ts +7 -0
  57. package/dist/admin/components/layout/nav-section.svelte +1 -1
  58. package/dist/admin/components/layout/nav-section.svelte.d.ts +1 -1
  59. package/dist/admin/components/layout/nav-singletons.svelte +14 -7
  60. package/dist/admin/components/layout/nav-singletons.svelte.d.ts +5 -1
  61. package/dist/admin/remote/booking.remote.d.ts +247 -0
  62. package/dist/admin/remote/booking.remote.js +286 -0
  63. package/dist/admin/remote/index.d.ts +2 -0
  64. package/dist/admin/remote/index.js +2 -0
  65. package/dist/admin/remote/modules.remote.d.ts +10 -0
  66. package/dist/admin/remote/modules.remote.js +14 -0
  67. package/dist/admin/state/active-context-resolve.d.ts +37 -0
  68. package/dist/admin/state/active-context-resolve.js +66 -0
  69. package/dist/admin/state/active-context.svelte.d.ts +8 -0
  70. package/dist/admin/state/active-context.svelte.js +27 -0
  71. package/dist/booking/adjustments.d.ts +33 -0
  72. package/dist/booking/adjustments.js +26 -0
  73. package/dist/booking/capacity.d.ts +12 -0
  74. package/dist/booking/capacity.js +10 -0
  75. package/dist/booking/client/index.d.ts +42 -0
  76. package/dist/booking/client/index.js +48 -0
  77. package/dist/booking/client/use-booking.svelte.d.ts +24 -0
  78. package/dist/booking/client/use-booking.svelte.js +56 -0
  79. package/dist/booking/config.d.ts +176 -0
  80. package/dist/booking/config.js +37 -0
  81. package/dist/booking/draft.d.ts +96 -0
  82. package/dist/booking/draft.js +67 -0
  83. package/dist/booking/expiry-logic.d.ts +30 -0
  84. package/dist/booking/expiry-logic.js +33 -0
  85. package/dist/booking/index.d.ts +18 -0
  86. package/dist/booking/index.js +52 -0
  87. package/dist/booking/ledger.d.ts +46 -0
  88. package/dist/booking/ledger.js +60 -0
  89. package/dist/booking/number.d.ts +2 -0
  90. package/dist/booking/number.js +11 -0
  91. package/dist/booking/participant-fields/access.d.ts +10 -0
  92. package/dist/booking/participant-fields/access.js +14 -0
  93. package/dist/booking/participant-fields/age.d.ts +12 -0
  94. package/dist/booking/participant-fields/age.js +28 -0
  95. package/dist/booking/participant-fields/completeness.d.ts +8 -0
  96. package/dist/booking/participant-fields/completeness.js +13 -0
  97. package/dist/booking/participant-fields/group.d.ts +6 -0
  98. package/dist/booking/participant-fields/group.js +15 -0
  99. package/dist/booking/participant-fields/index.d.ts +6 -0
  100. package/dist/booking/participant-fields/index.js +6 -0
  101. package/dist/booking/participant-fields/types.d.ts +50 -0
  102. package/dist/booking/participant-fields/types.js +5 -0
  103. package/dist/booking/participant-fields/validate.d.ts +7 -0
  104. package/dist/booking/participant-fields/validate.js +44 -0
  105. package/dist/booking/participant-pricing.d.ts +93 -0
  106. package/dist/booking/participant-pricing.js +91 -0
  107. package/dist/booking/participants-view.d.ts +32 -0
  108. package/dist/booking/participants-view.js +22 -0
  109. package/dist/booking/payment-context.d.ts +19 -0
  110. package/dist/booking/payment-context.js +29 -0
  111. package/dist/booking/pricing-inputs.d.ts +28 -0
  112. package/dist/booking/pricing-inputs.js +35 -0
  113. package/dist/booking/pricing.d.ts +86 -0
  114. package/dist/booking/pricing.js +125 -0
  115. package/dist/booking/recompute.d.ts +22 -0
  116. package/dist/booking/recompute.js +31 -0
  117. package/dist/booking/reminders-schedule.d.ts +11 -0
  118. package/dist/booking/reminders-schedule.js +28 -0
  119. package/dist/booking/server/adjustments.d.ts +27 -0
  120. package/dist/booking/server/adjustments.js +139 -0
  121. package/dist/booking/server/bookings.d.ts +51 -0
  122. package/dist/booking/server/bookings.js +336 -0
  123. package/dist/booking/server/catalog.d.ts +9 -0
  124. package/dist/booking/server/catalog.js +20 -0
  125. package/dist/booking/server/db.d.ts +7 -0
  126. package/dist/booking/server/db.js +18 -0
  127. package/dist/booking/server/email.d.ts +23 -0
  128. package/dist/booking/server/email.js +59 -0
  129. package/dist/booking/server/emailTemplateRegistry.d.ts +29 -0
  130. package/dist/booking/server/emailTemplateRegistry.js +125 -0
  131. package/dist/booking/server/http/create-handler.d.ts +5 -0
  132. package/dist/booking/server/http/create-handler.js +70 -0
  133. package/dist/booking/server/http/index.d.ts +4 -0
  134. package/dist/booking/server/http/index.js +4 -0
  135. package/dist/booking/server/http/maintenance-handler.d.ts +9 -0
  136. package/dist/booking/server/http/maintenance-handler.js +36 -0
  137. package/dist/booking/server/http/portal-handler.d.ts +13 -0
  138. package/dist/booking/server/http/portal-handler.js +103 -0
  139. package/dist/booking/server/http/webhook-handler.d.ts +9 -0
  140. package/dist/booking/server/http/webhook-handler.js +39 -0
  141. package/dist/booking/server/index.d.ts +12 -0
  142. package/dist/booking/server/index.js +14 -0
  143. package/dist/booking/server/maintenance.d.ts +28 -0
  144. package/dist/booking/server/maintenance.js +134 -0
  145. package/dist/booking/server/participants.d.ts +26 -0
  146. package/dist/booking/server/participants.js +92 -0
  147. package/dist/booking/server/payments.d.ts +34 -0
  148. package/dist/booking/server/payments.js +207 -0
  149. package/dist/booking/server/portal-session.d.ts +16 -0
  150. package/dist/booking/server/portal-session.js +42 -0
  151. package/dist/booking/server/portal.d.ts +206 -0
  152. package/dist/booking/server/portal.js +236 -0
  153. package/dist/booking/server/price-source.d.ts +73 -0
  154. package/dist/booking/server/price-source.js +94 -0
  155. package/dist/booking/server/refunds.d.ts +7 -0
  156. package/dist/booking/server/refunds.js +58 -0
  157. package/dist/booking/server/reminders.d.ts +9 -0
  158. package/dist/booking/server/reminders.js +24 -0
  159. package/dist/booking/server/validation.d.ts +17 -0
  160. package/dist/booking/server/validation.js +55 -0
  161. package/dist/booking/state-machine.d.ts +41 -0
  162. package/dist/booking/state-machine.js +73 -0
  163. package/dist/booking/templates/_partials/footer.en.html +4 -0
  164. package/dist/booking/templates/_partials/footer.pl.html +4 -0
  165. package/dist/booking/templates/_partials/header.en.html +4 -0
  166. package/dist/booking/templates/_partials/header.pl.html +4 -0
  167. package/dist/booking/templates/balance-due.en.html +10 -0
  168. package/dist/booking/templates/balance-due.pl.html +10 -0
  169. package/dist/booking/templates/balance-overdue-cancelled.en.html +5 -0
  170. package/dist/booking/templates/balance-overdue-cancelled.pl.html +5 -0
  171. package/dist/booking/templates/booking-received.en.html +9 -0
  172. package/dist/booking/templates/booking-received.pl.html +9 -0
  173. package/dist/booking/templates/deposit-paid.en.html +6 -0
  174. package/dist/booking/templates/deposit-paid.pl.html +6 -0
  175. package/dist/booking/templates/payment-link.en.html +5 -0
  176. package/dist/booking/templates/payment-link.pl.html +5 -0
  177. package/dist/booking/templates/payment-received.en.html +10 -0
  178. package/dist/booking/templates/payment-received.pl.html +10 -0
  179. package/dist/booking/totals.d.ts +38 -0
  180. package/dist/booking/totals.js +61 -0
  181. package/dist/booking/webhook-logic.d.ts +28 -0
  182. package/dist/booking/webhook-logic.js +50 -0
  183. package/dist/cli/create-user.d.ts +7 -1
  184. package/dist/cli/create-user.js +23 -15
  185. package/dist/cli/index.js +55 -7
  186. package/dist/cli/scaffold/admin.d.ts +6 -0
  187. package/dist/cli/scaffold/admin.js +5 -3
  188. package/dist/cli/scaffold/booking.d.ts +12 -0
  189. package/dist/cli/scaffold/booking.js +103 -0
  190. package/dist/core/cms.d.ts +24 -9
  191. package/dist/core/cms.js +72 -34
  192. package/dist/core/config/validatePreviews.d.ts +12 -0
  193. package/dist/core/config/validatePreviews.js +90 -0
  194. package/dist/core/fields/slugPath.d.ts +9 -1
  195. package/dist/core/fields/slugPath.js +16 -2
  196. package/dist/core/server/fields/resolveRelationFields.d.ts +11 -2
  197. package/dist/core/server/fields/resolveRelationFields.js +12 -3
  198. package/dist/core/server/generator/generator.js +7 -2
  199. package/dist/db-postgres/schema/booking/bookingAdjustments.d.ts +186 -0
  200. package/dist/db-postgres/schema/booking/bookingAdjustments.js +22 -0
  201. package/dist/db-postgres/schema/booking/bookingItemPersons.d.ts +117 -0
  202. package/dist/db-postgres/schema/booking/bookingItemPersons.js +22 -0
  203. package/dist/db-postgres/schema/booking/bookingItems.d.ts +181 -0
  204. package/dist/db-postgres/schema/booking/bookingItems.js +22 -0
  205. package/dist/db-postgres/schema/booking/bookingPayments.d.ts +204 -0
  206. package/dist/db-postgres/schema/booking/bookingPayments.js +25 -0
  207. package/dist/db-postgres/schema/booking/bookingPersons.d.ts +99 -0
  208. package/dist/db-postgres/schema/booking/bookingPersons.js +17 -0
  209. package/dist/db-postgres/schema/booking/bookingReminders.d.ts +131 -0
  210. package/dist/db-postgres/schema/booking/bookingReminders.js +18 -0
  211. package/dist/db-postgres/schema/booking/bookings.d.ts +324 -0
  212. package/dist/db-postgres/schema/booking/bookings.js +52 -0
  213. package/dist/db-postgres/schema/booking/index.d.ts +7 -0
  214. package/dist/db-postgres/schema/booking/index.js +7 -0
  215. package/dist/db-postgres/schema/index.d.ts +1 -0
  216. package/dist/db-postgres/schema/index.js +1 -0
  217. package/dist/db-postgres/schema-booking.d.ts +1 -0
  218. package/dist/db-postgres/schema-booking.js +1 -0
  219. package/dist/server/security/rate-limit-handler.d.ts +19 -0
  220. package/dist/server/security/rate-limit-handler.js +34 -0
  221. package/dist/shop/adapters/payu/client.js +3 -1
  222. package/dist/shop/adapters/payu/index.js +37 -17
  223. package/dist/shop/adapters/payu/payload.d.ts +6 -0
  224. package/dist/shop/adapters/payu/payload.js +1 -1
  225. package/dist/shop/adapters/stripe/index.js +36 -21
  226. package/dist/shop/index.d.ts +11 -2
  227. package/dist/shop/index.js +43 -1
  228. package/dist/shop/rate-limit.d.ts +1 -9
  229. package/dist/shop/rate-limit.js +3 -28
  230. package/dist/shop/types.d.ts +19 -0
  231. package/dist/sveltekit/config.d.ts +4 -0
  232. package/dist/sveltekit/config.js +6 -0
  233. package/dist/types/cms.d.ts +15 -1
  234. package/dist/types/cms.schema.d.ts +96 -2
  235. package/dist/types/cms.schema.js +84 -1
  236. package/dist/types/config.d.ts +33 -0
  237. package/dist/types/layout.d.ts +6 -0
  238. package/dist/types/modules.d.ts +133 -0
  239. package/dist/types/modules.js +27 -0
  240. package/dist/updates/0.37.0/index.d.ts +2 -0
  241. package/dist/updates/0.37.0/index.js +52 -0
  242. package/dist/updates/0.37.1/index.d.ts +2 -0
  243. package/dist/updates/0.37.1/index.js +24 -0
  244. package/dist/updates/index.js +5 -1
  245. package/package.json +19 -1
  246. package/dist/admin/components/layout/nav-shop.svelte +0 -33
  247. package/dist/admin/components/layout/nav-shop.svelte.d.ts +0 -3
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Module system — shop, booking, and future "overlays" on the CMS core.
3
+ *
4
+ * A module is registered via `defineConfig({ modules: [...] })`. It is split
5
+ * into a **serializable descriptor** (id/label/icon/context — safe to send to
6
+ * the admin client via a remote query) and **server-only `serverHooks`**
7
+ * (init logic that must never cross the wire). The module's dashboard
8
+ * component lives in a separate client-side registry keyed by `id`, never in
9
+ * the config — Svelte components are not serializable and the config is also
10
+ * validated server-side with Zod.
11
+ *
12
+ * @see {@link CMSModule}
13
+ */
14
+ /**
15
+ * Strips a {@link CMSModule} down to its serializable {@link CMSModuleDescriptor}
16
+ * for transport to the admin client. Drops `config` and `serverHooks`.
17
+ *
18
+ * @public
19
+ */
20
+ export function toModuleDescriptor(module) {
21
+ return {
22
+ id: module.id,
23
+ label: module.label,
24
+ icon: module.icon,
25
+ context: module.context
26
+ };
27
+ }
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,52 @@
1
+ export const update = {
2
+ version: '0.37.0',
3
+ date: '2026-06-17',
4
+ description: 'Moduły-nakładki + context switcher: shop i booking jako równorzędne, opcjonalne moduły rozszerzające rdzeń CMS (model „WooCommerce na WordPressie"). Zunifikowany rejestr `config.modules`, przełącznik kontekstu w adminie (Treści / Sklep / Rezerwacje) dla czytelniejszego UI, per-moduł dashboard. Shop przepięty na nowy kontrakt `CMSModule` (dowód generyczności #1), booking dodany jako drugi moduł biblioteki z pełnym rdzeniem domenowym (wycena/state machine/księga płatności) — dowód #2. Booking write-flow + portal self-service domknięte: tworzenie (public+staff), zadatek + webhook idempotentny, pełna edycja self-service (recompute/pojemność/„nie poniżej wpłaconego”), maile + przypomnienia, cron bez-infra (in-process loop + secured endpoint), strefa obsługi w adminie, scaffold `--booking`. Plan: `docs/superpowers/plans/2026-06-18-booking-write-flow-portal.md`, spec: `docs/superpowers/specs/2026-06-18-booking-write-flow-portal-design.md`.',
5
+ features: [
6
+ '`CMSModule` (`includio-cms` — `$lib/types/modules.ts`, `@public`) — kontrakt modułu-nakładki w 3 warstwach: serializowalny deskryptor (id/label/icon-string/context z nav sections + surfaced collections), server-only `serverHooks` (init), oraz client-side dashboard rejestrowany po `id`. Nav = dane (ikony jako nazwy z icon-map), nie komponenty.',
7
+ '`config.modules: CMSModule[]` — zunifikowany rejestr modułów w `defineConfig`. CMS dostaje `getModule(id)` / `getModuleConfig<T>(id)` / `hasModule(id)` + `modules` Map. `initCMS` odpala `serverHooks.init` każdego modułu (idempotentnie, fire-and-forget).',
8
+ '`moduleSchema` w `cms.schema.ts` — walidacja Zod modułów (unikalny `id`, wymagane icon/sections, `surfacedCollections`/`surfacedSingles` muszą referować zadeklarowane kolekcje/single).',
9
+ 'Context switcher (`context-switcher.svelte` w `site-header`) — przełącznik widoku admina: Treści (rdzeń CMS) / Sklep / Rezerwacje. Renderuje się tylko gdy ≥1 moduł; zero zmian wizualnych dla projektów bez modułów. Aktywny kontekst rozstrzygany przez `resolveActiveContext` (`?ctx` query > PersistedState sticky > ścieżka), ścieżki modułowe i content-core mają pierwszeństwo (poprawny deep-linking).',
10
+ 'Generyczny sidebar wg kontekstu (`nav-module.svelte`) — kontekst modułu pokazuje jego sekcje + „wciągnięte" kolekcje/single rdzenia (prop `filterSlugs` + `?ctx` w linkach na `nav-collections`/`nav-singletons`). Opcjonalne reaktywne badge przez `countSource`.',
11
+ 'Per-kontekst dashboard (`ModuleDashboardPage` + `dashboard-registry` po `id`, `@public` przez `includio-cms/admin/client`) — landing `/admin/shop` i `/admin/booking`. `shop-dashboard` (liczba zamówień + skróty), `booking-dashboard` (aktywne rezerwacje / zaległe salda / do potwierdzenia).',
12
+ '`defineShop()` zwraca teraz `CMSModule` (id `shop`, ikona `building-store`, sekcje Produkty/Zamówienia/Wysyłka/Kupony). Pełna warstwa server/http/remote shopa nietknięta (363 testy zielone).',
13
+ '`defineBooking(config): CMSModule` (`includio-cms/booking`, `@public`) — moduł rezerwacji. Config: `currency`, `catalogCollection` (surfaced), `depositAmount`, `pricing` (rabaty), `payment`, `adminEmail`.',
14
+ 'Booking rdzeń domenowy (pure, w pełni testowalny): `price()` — silnik wyceny (rabat ilościowy + early-bird, kompozycja largest-wins/sumowanie); `deriveStatus()` + `assertTransition()` — state machine `draft→reserved→partially_paid→paid→completed/cancelled` (status liczony z salda); `ledger` — saldo = gross − Σpaid, guard „nie poniżej wpłaconego". 37 testów.',
15
+ '5 tabel Drizzle bookingu (`bookings`/`booking_items`/`booking_participants`/`booking_payments`/`booking_reminders`) + eksport `includio-cms/db-postgres/schema-booking`. Kwoty w groszach, soft-delete, jsonb totals/customer/participants.',
16
+ '`includio-cms/booking` + `includio-cms/db-postgres/schema-booking` — nowe entry points w `package.json` exports.',
17
+ 'Admin: lista Rezerwacje (`/admin/booking/reservations`) + remote `listBookings`/`getBookingEnabled`.',
18
+ 'Booking write-flow: `createBooking()` (public self-serve + staff, walidacja pojemności + seam `validateBooking`, snapshot ceny, harmonogram przypomnień), `createDepositPayment()` (link zadatku przez wstrzyknięty adapter), public handler `POST /api/booking`. Status zawsze liczony z księgi (`deriveStatus`).',
19
+ 'Webhook płatności (`POST /api/booking/webhook/[provider]`) — `applyWebhookPayment()` idempotentny przez row-lock (`SELECT … FOR UPDATE` po `providerRef`), przeliczenie salda + statusu, czyszczenie holdu zadatku, mail `deposit-paid`/`payment-received`. Czysta logika `applyPaymentEvent` testowana jednostkowo.',
20
+ 'Edycja rezerwacji (`editBooking()`, wspólna dla obsługi i portalu): recompute ceny, guardy wg actora, `portal` blokuje zejście poniżej wpłaconego (`LedgerError` → HTTP 409 „skontaktuj się z obsługą”), reschedule przypomnień przy zmianie wylotu. Refundy = ręczna akcja obsługi przez adapter (`refundPayment`, przeliczenie salda).',
21
+ 'Portal self-service (`GET|POST /api/booking/portal/[token]`, `?action=edit|pay`) + SDK `createBookingClient` i reaktywny `useBooking` (`includio-cms/booking/client`). `toPortalView` whitelistuje pola (brak `staffNotes`). Strony storefront/portalu buduje repo klienta na SDK.',
22
+ 'Maile bookingu: lokalny Handlebars registry (override projektem → package default → fallback lang) + 6 szablonów PL/EN (`booking-received`/`deposit-paid`/`payment-received`/`payment-link`/`balance-due`/`balance-overdue-cancelled`).',
23
+ 'Cron bez-infra: czyste `processDueReminders`/`processDueExpirations` (draft-expiry + balance-due forfeiture z przepadkiem zadatku) napędzane in-process loopem (`serverHooks.init`, interwał z configu, domyślnie 15 min) ORAZ secured endpointem `POST /api/booking/maintenance` (Bearer token) jako trigger wymienny.',
24
+ 'Strefa obsługi w adminie: detal rezerwacji `/admin/booking/reservations/[id]` (księga, pozycje, uczestnicy, akcje) + remote mutacje (`createBookingStaff`/`editBookingStaff`/`addPaymentLink`/`recordCashPayment`/`refundBookingPayment`/`changeBookingStatus`/`cancelBooking`/`sendBookingEmailCmd`).',
25
+ '`includio-cms/booking/client` (SDK + `useBooking`) i `includio-cms/booking/server` (serwisy + HTTP handlery, node-only — kod serwerowy poza bundlem klienta) — nowe entry points.',
26
+ '`defineBooking` config rozszerzony: `depositTtlMinutes` (TTL porzuconego draftu, def. 60), `balanceDueDaysBefore` (termin dopłaty), `capacityField` (pojemność z wpisu katalogu), `reminders[]`, `validateBooking(ctx)` (seam client-specific), `maintenance` (autoRun/intervalMinutes), `maintenanceToken`. Kolumny `bookings`: `balanceDueAt`/`holdExpiresAt`/`cancelReason`.',
27
+ 'Scaffold: `includio scaffold admin` emituje też trasy bookingu (api/booking/*, strony admina, portal `rezerwacja/[token]`) gdy wykryje `defineBooking(` — flagi `--booking`/`--no-booking`. Generyczny helper rate-limit podniesiony do core (`$lib/server/security/rate-limit-handler`, współdzielony shop+booking).',
28
+ 'Redesign kontekstów (admin context workspaces): context switcher przeniesiony do nagłówka sidebara obok loga (inline pill, w trybie zwiniętym sama ikona kontekstu), nawigacja scoped per kontekst — każdy kontekst pokazuje wyłącznie swoje sekcje + własny „Pulpit" (Treści→`/admin`, moduł→`landingUrl` z ikoną modułu). Globalne narzędzia (Biblioteka mediów + admin: Użytkownicy/Konserwacja) przyklejone do dołu sidebara w każdym kontekście. Trasy neutralne (`/admin/media|users|maintenance|account`) zachowują aktywny kontekst zamiast wracać do Treści. Tożsamość kontekstu przez ikonę, Plum jednolity (`data-context` na korzeniu sidebara jako forward-compat hook pod ewentualne akcenty). Spec: `docs/superpowers/specs/2026-06-18-admin-context-workspaces-design.md`.',
29
+ 'Silnik reguł rabatowych bookingu (`price()` przepisany, `includio-cms/booking`): rabaty jako serializowalne reguły `when`→`then` z grupami wykluczającymi (w grupie wygrywa największy rabat, między grupami sumują się). Zastępuje `quantityDiscounts`/`earlyBird`/`combine`. Nowe efekty: `percentOffCheapestLine` (100 = najtańsza pozycja gratis) + `grantPerk` (prezent — notka dla obsługi). `PriceResult.perks` + per-linia `appliedDiscounts` (targetRef). Typy: `DiscountRule`/`Condition`/`Effect`/`Perk`/`PricingLine`. Silnik czysty, bez sprzężenia z domeną (gotowy pod współdzielenie z shop).',
30
+ 'Generyczny seam wyceny per linia: `PricingLine.subtotal?` — gdy podany, jest grossem linii (zamiast `unitPrice×quantity`), używany też przez „najtańsza pozycja gratis" (cheapest wg subtotalu). Snapshot na `booking_items.subtotalSnapshot` (nullable) zapewnia wierny recompute przy edycji. Wstecznie kompatybilne (brak subtotalu = zachowanie bez zmian). Pozwala klientowi naliczać dowolną nie-płaską cenę linii (np. cena wg wieku uczestników, stawki grupowe) bez logiki klienta w rdzeniu — wartości/obliczenia po stronie projektu. Spec: `docs/superpowers/specs/2026-06-18-booking-participants-fields-child-pricing-design.md`.',
31
+ 'Booking + PayU (i każdy adapter shopu) bez modułu shop: `PaymentCreateContext` zyskuje `continueUrl` (pełny absolutny URL powrotu) + `buyer` ({firstName,lastName,phone}). Adapter PayU `createPayment` preferuje ctx i pomija `requireShopConfig`/`getOrderById` gdy `continueUrl` podane (ścieżka shop bez zmian, wstecznie zgodna). `defineBooking` zyskuje `portalUrlTemplate` (placeholder `{token}` → `accessToken`); `createDepositPayment`/`createInstallmentPayment` budują ctx przez czysty `buildPaymentContext` i przekazują do adaptera. Pozwala wpiąć realny PayU w booking bez shopu. Spec: `docs/superpowers/specs/2026-06-19-booking-payu.md` (repo klienta).',
32
+ 'Treść maili transakcyjnych bookingu dopracowana (PL/EN, wszystkie 6 rodzajów) we wspólnym layoucie — nowe partials `_partials/{header,footer}` (rejestrowane przed każdym renderem, kolizyjnie-bezpieczne wobec identycznych nazw w module shop), styling AriaCMS + przycisk do panelu rezerwacji (`portalUrl` z `accessToken`+`portalUrlTemplate`). `balance-due` podaje termin dopłaty z datą i przybliżoną liczbą dni oraz ostrzega o przepadku zadatku; nowe helpery Handlebars `date`/`daysUntil`. Link do płatności wysyłany mailem do bookera po akcji obsługi `addPaymentLink`. Nowe pole `defineBooking({ brand })` — nazwa firmy w stopce maila (override per-projekt nadal przez `src/emails/booking/`). Spec/plan: `docs/superpowers/specs/2026-06-19-booking-email-content-design.md`.',
33
+ 'Widoki podglądu (`previews[]` w kolekcji/singlu, `@public`) — jedno entry może mieć kilka celów podglądu (pełny wpis, zajawka/karta w liście). Przełącznik „Widok" w pasku podglądu (ukryty przy jednym widoku), a `preview: \'<nazwa>\'` na tabie przełącza widok automatycznie przy wejściu na ten tab; tab bez powiązania nie rusza podglądu, a ręcznie wybrany widok jest zapamiętywany per tab. Podgląd ładuje `{url}?preview={id}&view={name}` — projekt może mieć route per widok albo jeden route rozgałęziający się na `view`. Stary `previewUrl` działa bez zmian (normalizowany do jednego widoku). `defineConfig` waliduje spójność: unikalne nazwy, max jeden `default`, `previewUrl`/`previews` wykluczają się, każde `tab.preview` musi wskazywać istniejący widok (literówka wywala build). Spec: `docs/superpowers/specs/2026-07-13-preview-views-design.md`.',
34
+ 'Admin bookingu — lista rezerwacji na wspólnym `DataTable`: wyszukiwanie po numerze oraz po danych klienta, filtr statusu, paginacja serwerowa (`listBookings({status, search, limit, offset})` → `{items, total}`; było: `SELECT *` bez limitu, czyli cała baza rezerwacji do przeglądarki). Statystyki pulpitu liczy nowy `getBookingStats()` — agregat SQL, bo sumowanie stronicowanej listy pokazywałoby po cichu liczby z pierwszej strony.',
35
+ 'Admin bookingu — czytelne statusy (`StatusBadge variant="booking"`): „Czeka na zaliczkę", „Zarezerwowane", „Częściowo opłacone", … zamiast surowych wartości technicznych (`draft`, `partially_paid`) na liście i w detalu.',
36
+ 'Admin bookingu — pozycje rezerwacji pokazują NAZWĘ wycieczki, nie jej uuid. `getBooking` rozwiązuje wpis katalogu zawsze, gdy katalog jest skonfigurowany (wcześniej tylko gdy `participantFields` było funkcją) i wystawia `tripTitle`; picker pozycji i detal używają jednego helpera `catalogTitle`, więc nazywają wycieczkę tak samo.',
37
+ '`defineBooking({ customerFields })` (`@experimental`) — etykiety worka `customer` w panelu admina (`FieldDef[]`: `key`, `label`, opcjonalna `role`). Rdzeń nie zna nazw pól projektu, więc bez tego panel pokazuje uczłowieczone klucze („Referral source"). Klucze zagnieżdżone adresuje się kropką (`people.birthDate`). Wyłącznie prezentacja — nie waliduje i nie zmienia danych.',
38
+ 'Admin bookingu — data urodzenia uczestnika pokazuje skończone lata w nawiasie („1990-05-05 (36 l.)"). Rozpoznanie po ROLI pola (`role: \'birthDate\'`), nie po nazwie — z samej wartości nie odróżnisz daty urodzenia od daty przylotu.',
39
+ '`defineBooking({ surfacedCollections })` (`@experimental`) — dodatkowe kolekcje wciągane do kontekstu „Rezerwacje" w adminie obok katalogu (np. kolekcja definiująca typy wypraw i pola uczestnika). Bez tego mieszkają w kontekście „Treści" i wyglądają jak doszyta kolekcja CMS-a, choć obsługują rezerwacje.',
40
+ 'Admin bookingu — nowa sekcja „Klient" w detalu rezerwacji. Wcześniej dane osoby rezerwującej (imię, e-mail, telefon, okno pobytu, odpowiedzi z formularza) były zapisywane, ale **nigdzie nie pokazywane** — obsługa nie mogła oddzwonić do klienta z panelu. Renderer jest generyczny: rozpoznaje typ po WARTOŚCI (e-mail → `mailto:`, telefon → `tel:`, data ISO → format lokalny), nie po nazwie pola, więc działa dla dowolnego kształtu `customer` bez zmian w rdzeniu; tablice obiektów (np. manifest uczestników) renderują się tabelką. `getBooking` wystawia `arrivalDateField` z konfiguracji.'
41
+ ],
42
+ fixes: [
43
+ 'Pole `relation` — dwa wpisy o tej samej nazwie przestają się zlewać w jeden. `Command.Item` dostawał `value={label}`, a `value` jest w bits-ui tożsamością pozycji (filtrowanie, nawigacja klawiaturą, podświetlenie), więc identyczne nazwy dawały `aria-selected=true` na obu wierszach naraz. Teraz tożsamość to `id` wpisu, a wyszukiwanie po nazwie zapewnia `keywords` (domyślny scorer skleja `value` + `keywords`). Zaznaczenie (`isSelected`) zawsze szło po `id` — psuło się wyłącznie podświetlenie.',
44
+ 'Ścieżka wpisu (`_url`, lista kolekcji) zawsze bezwzględna, z dokładnie jednym wiodącym slashem. `applyPathTemplate` zwracało szablon 1:1, więc `pathTemplate: \'blog/{slug}\'` dawało `_url: \'blog/x\'` — URL **względny** (z podstrony prowadził w złe miejsce), mimo że docs obiecują `/blog/x`. Projekty pisały więc `pathTemplate: \'/blog/{slug}\'`, a wtedy lista kolekcji w adminie pokazywała `//blog/x`, bo `entry-link` doklejał własny slash. Teraz szablon i slug są składane bez podwojenia (`//` → `/`), obie formy szablonu działają, a URL-e bezwzględne (`https://…`) zostają nietknięte. `EntryLink` przyjmuje `path` (gotowa ścieżka) zamiast `slug`.'
45
+ ],
46
+ breakingChanges: [
47
+ '`config.shop` USUNIĘTY. Shop rejestruje się teraz przez `config.modules`: `defineConfig({ modules: [defineShop({...})] })` zamiast `defineConfig({ shop: defineShop({...}) })`. `defineShop()` zwraca `CMSModule` (nie `ResolvedShopConfig`). Wewnętrznie `getCMS().shopConfig` działa nadal (shim → `getModuleConfig(\'shop\')`), więc warstwa server/http/remote shopa pozostaje kompatybilna.',
48
+ 'Tabela `bookings` ma nowe kolumny (`balance_due_at`, `hold_expires_at`, `cancel_reason`) oraz `booking_items` kolumnę `subtotal_snapshot` (nullable) wymagane przez write-flow. Po aktualizacji uruchom `pnpm db:push` (lub migrację) w projekcie używającym bookingu.',
49
+ '`PricingConfig` bookingu przepisany na `{ rules: DiscountRule[] }` — `quantityDiscounts`/`earlyBird`/`combine` USUNIĘTE. `price(lines, now, config)` ma nową sygnaturę (linie z `ref`/`departureDate` zamiast płaskich `{unitPrice,quantity}` + osobnej daty). `BookingTotals` zyskuje `perks`/`appliedRules` (jsonb `totals` — bez migracji DB). Zaktualizuj `defineBooking({ pricing: { rules: [...] } })`.'
50
+ ],
51
+ notes: 'Pre-1.0: zmiana dozwolona bez okresu deprecacji (jednoosobowy konsument). Migracja: (1) w `cms.config.ts` zamień `shop: defineShop({...})` na `modules: [defineShop({...})]`; (2) jeśli używasz bookingu — `pnpm db:push` (nowe kolumny) i przescaffolduj trasy (`includio scaffold admin` wykryje `defineBooking(`). Provider płatności (Stripe/PayU) konfigurowalny przez `defineBooking({ payment: [...] })` — core adapter-agnostyczny.'
52
+ };
@@ -0,0 +1,2 @@
1
+ import type { CmsUpdate } from '../index.js';
2
+ export declare const update: CmsUpdate;
@@ -0,0 +1,24 @@
1
+ export const update = {
2
+ version: '0.37.1',
3
+ date: '2026-07-14',
4
+ description: 'Dwie łatki cenowe w bookingu. (1) Cena rezerwacji przestaje pochodzić z żądania HTTP — do 0.37.0 publiczne endpointy przyjmowały `unitPrice` prosto z ciała żądania i nikt nie konfrontował go z katalogiem, więc wyprawę dało się zarezerwować za grosz. (2) Data wyceny zostaje zamrożona na rezerwacji — dotąd każde jej dotknięcie (edycja, ale też zaksięgowanie korekty) przeliczało reguły zależne od czasu wg DZISIEJSZEJ daty, przez co early-bird sprzed miesięcy cicho znikał i klient robił się winien pieniądze.',
5
+ fixes: [
6
+ '**Bezpieczeństwo (data wyceny).** Nowa kolumna `bookings.priced_at` zamraża moment wyceny. `editBooking` i `priceFromExistingRows` (ścieżka korekt — `adjustments.ts:65` i `:155`) liczą teraz early-bird na tę datę, nie na `new Date()`. Wcześniej wystarczyło, że obsługa zaksięguje dopłatę ustaloną telefonicznie tydzień przed wylotem, a rabat za wczesną rezerwację przepadał. `priceFromExistingRows` straciło parametr `now` — kompilator nie pozwoli już podać tam zegara.',
7
+ 'Rezerwacje sprzed 0.37.1 mają `priced_at = NULL` i wyceniają się z `created_at` — dokładnie tym, czym było wtedy `now`. Zero migracji danych, zero zmiany zachowania.',
8
+ '**Bezpieczeństwo (ceny).** Trzy publiczne drogi wpuszczały cenę z zewnątrz: tworzenie rezerwacji (`createBookingHandler`), dokładanie wycieczki przez portal (`add-trips`) i portalowa edycja pozycji (`portalEdit` → `editBooking`). Bramka stoi teraz w rdzeniu (`createBooking`/`editBooking`), nie w handlerach, więc każdy przyszły publiczny endpoint jest chroniony domyślnie.',
9
+ 'Cena pozycji już zapisanej w rezerwacji jest brana z jej `unitPriceSnapshot`, a nie przeliczana z katalogu — dotknięcie rezerwacji przez portal nie podniesie klientowi ceny, gdy cennik w międzyczasie poszedł w górę.',
10
+ 'Odczyt katalogu w `editBooking` odbywa się przed otwarciem transakcji: szew klienta robi własne I/O, a wołany pod blokadą `FOR UPDATE` trzymałby wiersz rezerwacji i sięgał po drugie połączenie z tej samej puli.',
11
+ 'Ceny ujemne i niecałkowite (ułamek grosza) są odrzucane — również dla obsługi.'
12
+ ],
13
+ features: [
14
+ '`defineBooking({ resolvePrice })` — serwerowy szew zwracający cenę bazową (dorosłego) pozycji katalogu w groszach. Rdzeń nie zna kształtu katalogu, więc cenę podaje projekt: `resolvePrice: async (tripRef) => Math.round(Number((await resolveEntry({ id: tripRef, status: "published" }))?.price ?? 0) * 100)`.',
15
+ 'Model zaufania oparty na aktorze: `createBooking(input, { actor })` przyjmuje `public | portal | staff`. Domyślny aktor to `public` (niezaufany) — pominięcie parametru nie otwiera dziury. Zalogowana obsługa (`staff`) nadal może podać cenę ręcznie: korekta i rabat negocjowany telefonicznie zostają możliwe.',
16
+ 'Typ `PricedCreateInput` wymusza kolejność: rezerwacji nie da się zbudować z pozycji, której nie wyceniła bramka — pilnuje tego kompilator, nie dyscyplina.'
17
+ ],
18
+ breakingChanges: [
19
+ 'Nowa kolumna `bookings.priced_at` — wymagana migracja (`drizzle-kit push`). Nullable, bez backfillu.',
20
+ '**`defineBooking({ resolvePrice })` jest teraz wymagany, gdy booking wystawia publiczne endpointy** (`createBookingHandler`, portal). Bez niego rdzeń odmawia wyceny (fail-closed) zamiast po cichu zaufać cenie z żądania. Instalacje używające wyłącznie panelu admina działają bez zmian.',
21
+ '`BookingItemInput.unitPrice` jest opcjonalne i **honorowane wyłącznie dla `actor: "staff"`**. Dla klienta końcowego jest ignorowane — cenę ustala katalog.',
22
+ 'Publiczne API klienta: `createBookingClient().addTrips(token, additions)` oraz `useBooking().addTrips(additions)` nie przyjmują już `unitPrice` w pozycjach (`{ tripRef, assignments }`). Storefronty przekazujące cenę muszą ją usunąć z ładunku — była i tak ignorowana po stronie serwera.'
23
+ ]
24
+ };
@@ -75,6 +75,8 @@ import { update as update0365 } from './0.36.5/index.js';
75
75
  import { update as update0367 } from './0.36.7/index.js';
76
76
  import { update as update0368 } from './0.36.8/index.js';
77
77
  import { update as update0369 } from './0.36.9/index.js';
78
+ import { update as update0370 } from './0.37.0/index.js';
79
+ import { update as update0371 } from './0.37.1/index.js';
78
80
  export const updates = [
79
81
  update0065,
80
82
  update0066,
@@ -152,7 +154,9 @@ export const updates = [
152
154
  update0365,
153
155
  update0367,
154
156
  update0368,
155
- update0369
157
+ update0369,
158
+ update0370,
159
+ update0371
156
160
  ];
157
161
  export const getUpdatesFrom = (fromVersion) => {
158
162
  const fromParts = fromVersion.split('.').map(Number);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "includio-cms",
3
- "version": "0.36.9",
3
+ "version": "0.37.1",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",
@@ -111,6 +111,10 @@
111
111
  "types": "./dist/db-postgres/schema-shop.d.ts",
112
112
  "node": "./dist/db-postgres/schema-shop.js"
113
113
  },
114
+ "./db-postgres/schema-booking": {
115
+ "types": "./dist/db-postgres/schema-booking.d.ts",
116
+ "node": "./dist/db-postgres/schema-booking.js"
117
+ },
114
118
  "./auth-schema": {
115
119
  "types": "./dist/server/db/schema/auth-schema.d.ts",
116
120
  "node": "./dist/server/db/schema/auth-schema.js"
@@ -129,6 +133,20 @@
129
133
  "types": "./dist/shop/http/index.d.ts",
130
134
  "node": "./dist/shop/http/index.js"
131
135
  },
136
+ "./booking": {
137
+ "types": "./dist/booking/index.d.ts",
138
+ "svelte": "./dist/booking/index.js",
139
+ "node": "./dist/booking/index.js"
140
+ },
141
+ "./booking/client": {
142
+ "types": "./dist/booking/client/index.d.ts",
143
+ "svelte": "./dist/booking/client/index.js",
144
+ "node": "./dist/booking/client/index.js"
145
+ },
146
+ "./booking/server": {
147
+ "types": "./dist/booking/server/index.d.ts",
148
+ "node": "./dist/booking/server/index.js"
149
+ },
132
150
  "./files-local": {
133
151
  "types": "./dist/files-local/index.d.ts",
134
152
  "node": "./dist/files-local/index.js"
@@ -1,33 +0,0 @@
1
- <script lang="ts">
2
- import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
3
- import { sidebarLang } from './lang.js';
4
- import { getRemotes } from '../../../sveltekit/index.js';
5
- import PackageIcon from '@tabler/icons-svelte/icons/package';
6
- import ShoppingCartIcon from '@tabler/icons-svelte/icons/shopping-cart';
7
- import TruckIcon from '@tabler/icons-svelte/icons/truck';
8
- import TicketIcon from '@tabler/icons-svelte/icons/ticket';
9
- import BuildingStoreIcon from '@tabler/icons-svelte/icons/building-store';
10
- import { page } from '$app/state';
11
- import NavSection, { type NavSectionItem } from './nav-section.svelte';
12
-
13
- const interfaceLanguage = useInterfaceLanguage();
14
- const lang = $derived(sidebarLang[interfaceLanguage.current].shop);
15
- const remotes = getRemotes();
16
- const enabledQuery = $derived(remotes.getShopEnabled());
17
-
18
- function isActive(url: string) {
19
- const pathname = page.url.pathname;
20
- return pathname === url || pathname.startsWith(url + '/');
21
- }
22
-
23
- const items: NavSectionItem[] = $derived([
24
- { title: lang.products, url: '/admin/shop/products', icon: PackageIcon },
25
- { title: lang.orders, url: '/admin/shop/orders', icon: ShoppingCartIcon },
26
- { title: lang.shipping, url: '/admin/shop/shipping-methods', icon: TruckIcon },
27
- { title: lang.coupons, url: '/admin/shop/coupons', icon: TicketIcon }
28
- ]);
29
- </script>
30
-
31
- {#if enabledQuery.ready && enabledQuery.current}
32
- <NavSection {items} label={lang.title} labelIcon={BuildingStoreIcon} {isActive} withTopBorder />
33
- {/if}
@@ -1,3 +0,0 @@
1
- declare const NavShop: import("svelte").Component<Record<string, never>, {}, "">;
2
- type NavShop = ReturnType<typeof NavShop>;
3
- export default NavShop;