@micha.bigler/ui-core-micha 3.14.3 → 4.0.0

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 (367) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +7 -0
  3. package/dist/auth/UserMenu.js +1 -1
  4. package/dist/auth/apiClient.js +7 -6
  5. package/dist/chat/ChatList.js +1 -1
  6. package/dist/chat/ChatThread.js +2 -1
  7. package/dist/chat/ChatWorkspace.js +1 -1
  8. package/dist/chat/ModelPicker.js +2 -5
  9. package/dist/chat/kitSxRegistry.js +9 -0
  10. package/dist/chat/useChatSocket.js +1 -1
  11. package/dist/components/LoginForm.js +1 -1
  12. package/dist/components/SecurityComponent.js +1 -1
  13. package/dist/components/UserListComponent.js +2 -8
  14. package/dist/components/charts/ChartFrame.js +1 -1
  15. package/dist/components/charts/ScatterChart.js +2 -1
  16. package/dist/components/charts/kitSxRegistry.js +6 -0
  17. package/dist/entries/charts.js +6 -0
  18. package/dist/entries/chat.js +8 -0
  19. package/dist/entries/markdown.js +1 -0
  20. package/dist/index.js +0 -14
  21. package/dist/layout/SectionNav.js +1 -1
  22. package/dist/messaging/AttachmentList.js +2 -2
  23. package/dist/messaging/Composer.js +2 -1
  24. package/dist/messaging/ConversationLaunchers.js +1 -4
  25. package/dist/messaging/ConversationList.js +1 -1
  26. package/dist/messaging/DirectMessageLauncher.js +1 -1
  27. package/dist/messaging/MessagingProvider.js +0 -0
  28. package/dist/messaging/PollCard.js +7 -5
  29. package/dist/messaging/ReadTicks.js +2 -2
  30. package/dist/messaging/Thread.js +5 -3
  31. package/dist/notifications/NotificationBell.js +4 -7
  32. package/dist/notifications/NotificationSettings.js +1 -1
  33. package/dist/onboarding/OnboardingProvider.js +3 -6
  34. package/dist/pages/AccountPage.js +1 -2
  35. package/dist/pages/LoginPage.js +2 -3
  36. package/dist/pages/PasswordChangePage.js +2 -3
  37. package/dist/pages/PasswordInvitePage.js +2 -3
  38. package/dist/pages/PasswordResetRequestPage.js +2 -3
  39. package/dist/pages/SignUpPage.js +2 -3
  40. package/dist/pages/SignupConfirmPage.js +2 -3
  41. package/dist/theme/createAppTheme.js +5 -4
  42. package/dist/theme/kitSxEntry.js +11 -0
  43. package/dist/theme/kitSxRegistry.js +2 -15
  44. package/dist/theme/themeCompleteness.js +3 -12
  45. package/dist/utils/auth-errors.js +4 -3
  46. package/package.json +41 -16
  47. package/.github/workflows/publish.yml +0 -126
  48. package/DESIGN.md +0 -60
  49. package/WORK_ORDERS.md +0 -148
  50. package/dev/entries.jsx +0 -721
  51. package/dev/fixtures.js +0 -26
  52. package/dev/main.jsx +0 -75
  53. package/dev/mockTransport.jsx +0 -128
  54. package/docs/CHART-LAYOUT.md +0 -157
  55. package/docs/DARK-TOKENS.md +0 -140
  56. package/docs/TYPE-SCALE.md +0 -111
  57. package/docs/messaging-deviations.md +0 -118
  58. package/index.html +0 -12
  59. package/renovate.json +0 -10
  60. package/scripts/chart-api-census.mjs +0 -415
  61. package/src/auth/AuthContext.jsx +0 -158
  62. package/src/auth/ReauthModal.jsx +0 -82
  63. package/src/auth/UserMenu.jsx +0 -121
  64. package/src/auth/apiClient.jsx +0 -232
  65. package/src/auth/authApi.jsx +0 -539
  66. package/src/auth/authConfig.jsx +0 -34
  67. package/src/auth/reauth.js +0 -47
  68. package/src/chat/ChatComposer.jsx +0 -36
  69. package/src/chat/ChatList.jsx +0 -87
  70. package/src/chat/ChatThread.jsx +0 -128
  71. package/src/chat/ChatWorkspace.jsx +0 -244
  72. package/src/chat/MarkdownReply.jsx +0 -22
  73. package/src/chat/ModelPicker.jsx +0 -85
  74. package/src/chat/api.js +0 -18
  75. package/src/chat/useChatSocket.js +0 -32
  76. package/src/chat/wire.js +0 -7
  77. package/src/components/AccessCodeManager.jsx +0 -288
  78. package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
  79. package/src/components/AllowedEmailDomainsManager.jsx +0 -92
  80. package/src/components/AuthFactorRequirementCard.jsx +0 -95
  81. package/src/components/BulkInviteCsvTab.jsx +0 -198
  82. package/src/components/EmptyState.jsx +0 -38
  83. package/src/components/LoginForm.jsx +0 -159
  84. package/src/components/MFAComponent.jsx +0 -350
  85. package/src/components/MfaLoginComponent.jsx +0 -252
  86. package/src/components/MobileBottomNav.jsx +0 -82
  87. package/src/components/PasskeysComponent.jsx +0 -252
  88. package/src/components/PasswordChangeForm.jsx +0 -87
  89. package/src/components/PasswordResetRequestForm.jsx +0 -43
  90. package/src/components/PasswordSetForm.jsx +0 -97
  91. package/src/components/ProfileComponent.jsx +0 -348
  92. package/src/components/QrSignupManager.jsx +0 -404
  93. package/src/components/QrSignupValidityManager.jsx +0 -106
  94. package/src/components/RegistrationMethodsManager.jsx +0 -150
  95. package/src/components/SecurityComponent.jsx +0 -141
  96. package/src/components/SocialLoginButtons.jsx +0 -83
  97. package/src/components/SoftChip.jsx +0 -93
  98. package/src/components/StatTile.jsx +0 -39
  99. package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
  100. package/src/components/TurnstileWidget.jsx +0 -99
  101. package/src/components/UserInviteComponent.jsx +0 -76
  102. package/src/components/UserListComponent.jsx +0 -618
  103. package/src/components/charts/BarChart.jsx +0 -102
  104. package/src/components/charts/ChartFrame.jsx +0 -214
  105. package/src/components/charts/LineChart.jsx +0 -126
  106. package/src/components/charts/ScatterChart.jsx +0 -299
  107. package/src/components/charts/TimeSeriesChart.jsx +0 -300
  108. package/src/components/charts/chartDefaults.js +0 -644
  109. package/src/components/charts/chartLabels.js +0 -36
  110. package/src/components/charts/exportChart.js +0 -258
  111. package/src/components/charts/formatters.js +0 -39
  112. package/src/components/charts/palette.js +0 -33
  113. package/src/components/charts/yearTickInterval.js +0 -7
  114. package/src/i18n/authTranslations.ts +0 -2651
  115. package/src/i18n/chartsTranslations.ts +0 -91
  116. package/src/i18n/chatTranslations.ts +0 -55
  117. package/src/i18n/messagingTranslations.ts +0 -120
  118. package/src/i18n/notificationsTranslations.ts +0 -32
  119. package/src/i18n/onboardingTranslations.ts +0 -29
  120. package/src/i18n/sectionNavTranslations.ts +0 -20
  121. package/src/i18n/uiCoreTranslations.js +0 -29
  122. package/src/i18n/userMenuTranslations.ts +0 -5
  123. package/src/index.js +0 -158
  124. package/src/layout/PageLayout.jsx +0 -36
  125. package/src/layout/SectionNav.jsx +0 -320
  126. package/src/messaging/AttachmentList.jsx +0 -145
  127. package/src/messaging/Composer.jsx +0 -197
  128. package/src/messaging/ConversationLaunchers.jsx +0 -51
  129. package/src/messaging/ConversationList.jsx +0 -109
  130. package/src/messaging/DirectMessageLauncher.jsx +0 -112
  131. package/src/messaging/MessageBubble.jsx +0 -183
  132. package/src/messaging/MessagingProvider.jsx +0 -0
  133. package/src/messaging/MessagingScopeConfig.jsx +0 -24
  134. package/src/messaging/PollCard.jsx +0 -163
  135. package/src/messaging/ReactionBar.jsx +0 -43
  136. package/src/messaging/ReadTicks.jsx +0 -82
  137. package/src/messaging/Thread.jsx +0 -195
  138. package/src/messaging/api.js +0 -48
  139. package/src/messaging/composerImageCompression.js +0 -35
  140. package/src/messaging/linkifyText.jsx +0 -37
  141. package/src/notifications/NotificationBell.jsx +0 -84
  142. package/src/notifications/NotificationSettings.jsx +0 -330
  143. package/src/notifications/NotificationsProvider.jsx +0 -224
  144. package/src/notifications/PopupSurface.jsx +0 -105
  145. package/src/notifications/api.js +0 -55
  146. package/src/notifications/feedApi.js +0 -18
  147. package/src/notifications/realtime.jsx +0 -138
  148. package/src/notifications/serviceWorker/sw.js +0 -50
  149. package/src/onboarding/OnboardingProvider.jsx +0 -326
  150. package/src/onboarding/OnboardingWizard.jsx +0 -61
  151. package/src/onboarding/WizardDialogShell.jsx +0 -51
  152. package/src/onboarding/api.js +0 -13
  153. package/src/onboarding/stepSelection.js +0 -16
  154. package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
  155. package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
  156. package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
  157. package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
  158. package/src/pages/AccountPage.jsx +0 -394
  159. package/src/pages/LoginPage.jsx +0 -343
  160. package/src/pages/PasswordChangePage.jsx +0 -62
  161. package/src/pages/PasswordInvitePage.jsx +0 -177
  162. package/src/pages/PasswordResetRequestPage.jsx +0 -68
  163. package/src/pages/SignUpPage.jsx +0 -268
  164. package/src/pages/SignupConfirmPage.jsx +0 -155
  165. package/src/testing/checkKitIntegration.js +0 -233
  166. package/src/theme/createAppTheme.js +0 -423
  167. package/src/theme/fonts.js +0 -3
  168. package/src/theme/index.js +0 -21
  169. package/src/theme/kitSxRegistry.js +0 -285
  170. package/src/theme/themeCompleteness.js +0 -1045
  171. package/src/theme/tokens.js +0 -478
  172. package/src/utils/auth-errors.js +0 -76
  173. package/src/utils/authService.js +0 -223
  174. package/src/utils/resolveErrorText.js +0 -28
  175. package/src/utils/webauthn.js +0 -51
  176. package/tests/AccountPage.profileStatements.test.jsx +0 -162
  177. package/tests/AccountPage.test.jsx +0 -200
  178. package/tests/AuthContext.test.jsx +0 -129
  179. package/tests/BarChart.test.jsx +0 -112
  180. package/tests/BrowserPushStep.test.jsx +0 -110
  181. package/tests/ChartFrame.test.jsx +0 -336
  182. package/tests/ConversationList.test.jsx +0 -144
  183. package/tests/CookieConsentStep.test.jsx +0 -69
  184. package/tests/EmptyState.test.jsx +0 -62
  185. package/tests/LineChart.test.jsx +0 -80
  186. package/tests/MessagingProvider.test.jsx +0 -50
  187. package/tests/MobileBottomNav.test.jsx +0 -319
  188. package/tests/NotificationBell.test.jsx +0 -60
  189. package/tests/NotificationSettings.test.jsx +0 -276
  190. package/tests/NotificationsProvider.test.jsx +0 -240
  191. package/tests/OnboardingProvider.test.jsx +0 -294
  192. package/tests/OnboardingWizard.test.jsx +0 -143
  193. package/tests/PasswordChangeForm.test.jsx +0 -70
  194. package/tests/PasswordInvitePage.test.jsx +0 -142
  195. package/tests/PasswordSetForm.test.jsx +0 -70
  196. package/tests/PopupSurface.test.jsx +0 -142
  197. package/tests/ProfileComponent.refresh.test.jsx +0 -194
  198. package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
  199. package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
  200. package/tests/ScatterChart.test.jsx +0 -270
  201. package/tests/SectionNav.test.jsx +0 -363
  202. package/tests/SignUpPage.test.jsx +0 -208
  203. package/tests/SoftChip.test.jsx +0 -105
  204. package/tests/StatTile.test.jsx +0 -57
  205. package/tests/Thread.test.jsx +0 -151
  206. package/tests/TimeSeriesChart.test.jsx +0 -367
  207. package/tests/UserListComponent.test.jsx +0 -192
  208. package/tests/UserMenu.test.jsx +0 -171
  209. package/tests/apiClientLanguage.test.js +0 -33
  210. package/tests/apiClientPublicPaths.test.js +0 -178
  211. package/tests/authApiLogin.test.js +0 -42
  212. package/tests/authApiRegistration.test.js +0 -31
  213. package/tests/authErrorCodeRendering.test.jsx +0 -77
  214. package/tests/authErrors.test.js +0 -74
  215. package/tests/authTranslations.test.js +0 -74
  216. package/tests/chart-api-census.test.js +0 -366
  217. package/tests/chartAxisTickBand.test.jsx +0 -95
  218. package/tests/chartDefaults.test.js +0 -902
  219. package/tests/chartLabels.test.js +0 -50
  220. package/tests/chartsPalette.test.js +0 -99
  221. package/tests/chatApi.test.js +0 -48
  222. package/tests/chatDriverNames.test.jsx +0 -71
  223. package/tests/chatExports.test.js +0 -3
  224. package/tests/chatList.test.jsx +0 -84
  225. package/tests/chatPicker.test.jsx +0 -82
  226. package/tests/chatSocket.test.jsx +0 -26
  227. package/tests/chatThread.test.jsx +0 -116
  228. package/tests/chatTranslations.test.js +0 -47
  229. package/tests/chatWorkspace.test.jsx +0 -234
  230. package/tests/checkKitIntegration.test.jsx +0 -219
  231. package/tests/createAppTheme.test.js +0 -132
  232. package/tests/createAppThemeDark.test.js +0 -127
  233. package/tests/createAppThemeLightGuard.test.js +0 -40
  234. package/tests/createAppThemePageContrast.test.js +0 -108
  235. package/tests/createAppThemeTypography.test.js +0 -53
  236. package/tests/errorCallSiteGuard.test.js +0 -32
  237. package/tests/exportChart.test.js +0 -313
  238. package/tests/feedApi.test.js +0 -46
  239. package/tests/fixtures/light-theme-baseline.json +0 -2234
  240. package/tests/i18nAggregate.test.js +0 -120
  241. package/tests/i18nGermanVariant.test.js +0 -65
  242. package/tests/loginPageErrorResolution.test.jsx +0 -102
  243. package/tests/messagingApi.test.js +0 -32
  244. package/tests/messagingChunk6.test.jsx +0 -116
  245. package/tests/messagingCompactBubble.test.jsx +0 -64
  246. package/tests/messagingComposer.test.jsx +0 -136
  247. package/tests/messagingComposerChunk5.test.jsx +0 -113
  248. package/tests/messagingContractConformance.test.js +0 -69
  249. package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
  250. package/tests/messagingExports.test.js +0 -21
  251. package/tests/messagingInteractions.test.jsx +0 -136
  252. package/tests/messagingLastMessagePreview.test.jsx +0 -93
  253. package/tests/messagingLinkify.test.jsx +0 -51
  254. package/tests/messagingMessageActions.test.jsx +0 -163
  255. package/tests/messagingMsg6.test.jsx +0 -105
  256. package/tests/messagingMsg6f.test.jsx +0 -155
  257. package/tests/messagingMsg6g.test.jsx +0 -166
  258. package/tests/messagingMsg6h.test.jsx +0 -136
  259. package/tests/messagingMsg6i.test.jsx +0 -129
  260. package/tests/messagingPollRendering.test.jsx +0 -142
  261. package/tests/messagingReactionMerge.test.jsx +0 -77
  262. package/tests/messagingReadTicksTooltip.test.jsx +0 -36
  263. package/tests/messagingThreadReceipts.test.jsx +0 -178
  264. package/tests/messagingThreadingQuoting.test.jsx +0 -87
  265. package/tests/messagingUnreadLifecycle.test.jsx +0 -78
  266. package/tests/notificationsApi.test.js +0 -41
  267. package/tests/notificationsExports.test.js +0 -34
  268. package/tests/onboardingDescriptors.test.js +0 -132
  269. package/tests/packageTreeShaking.test.js +0 -126
  270. package/tests/realtime.test.jsx +0 -219
  271. package/tests/resolveErrorText.test.js +0 -72
  272. package/tests/stepSelection.test.js +0 -53
  273. package/tests/themeCompleteness.test.js +0 -626
  274. package/tests/timeSeriesLegend.test.js +0 -99
  275. package/tests/userScreenTranslations.test.jsx +0 -218
  276. package/tsconfig.build.json +0 -18
  277. package/vite.config.mjs +0 -6
  278. package/work-orders/AUTH-1.md +0 -74
  279. package/work-orders/AUTH-2.md +0 -74
  280. package/work-orders/AUTH-4.md +0 -183
  281. package/work-orders/AUTH-5.md +0 -154
  282. package/work-orders/AUTH-7.md +0 -181
  283. package/work-orders/AUTH-8.md +0 -184
  284. package/work-orders/CHART-1.md +0 -285
  285. package/work-orders/CHART-2.md +0 -222
  286. package/work-orders/CHART-3.md +0 -163
  287. package/work-orders/CHART-4.md +0 -203
  288. package/work-orders/CHART-5.md +0 -226
  289. package/work-orders/CHART-6.md +0 -428
  290. package/work-orders/CHART-7.md +0 -175
  291. package/work-orders/DX-1.md +0 -169
  292. package/work-orders/DX-2.md +0 -188
  293. package/work-orders/DX-3.md +0 -195
  294. package/work-orders/I18N-1.md +0 -254
  295. package/work-orders/I18N-3.md +0 -207
  296. package/work-orders/MSG-3.md +0 -375
  297. package/work-orders/MSG-3b.md +0 -1002
  298. package/work-orders/MSG-3c.md +0 -378
  299. package/work-orders/MSG-3d.md +0 -268
  300. package/work-orders/MSG-3e.md +0 -164
  301. package/work-orders/MSG-3f.md +0 -391
  302. package/work-orders/MSG-6e.md +0 -308
  303. package/work-orders/MSG-6f.md +0 -214
  304. package/work-orders/MSG-6g.md +0 -244
  305. package/work-orders/MSG-6h.md +0 -238
  306. package/work-orders/MSG-6i.md +0 -271
  307. package/work-orders/MSG-6j.md +0 -117
  308. package/work-orders/NOTIF-12.md +0 -214
  309. package/work-orders/NOTIF-13.md +0 -142
  310. package/work-orders/NOTIF-14.md +0 -151
  311. package/work-orders/PRIM-1.md +0 -177
  312. package/work-orders/SHELL-1.md +0 -255
  313. package/work-orders/SHELL-2.md +0 -197
  314. package/work-orders/SHELL-3.md +0 -359
  315. package/work-orders/SHELL-4.md +0 -351
  316. package/work-orders/SHELL-5.md +0 -345
  317. package/work-orders/SHELL-6.md +0 -210
  318. package/work-orders/THEME-1.md +0 -587
  319. package/work-orders/THEME-10.md +0 -303
  320. package/work-orders/THEME-11.md +0 -208
  321. package/work-orders/THEME-2.md +0 -339
  322. package/work-orders/THEME-3.md +0 -210
  323. package/work-orders/THEME-4.md +0 -271
  324. package/work-orders/THEME-5.md +0 -341
  325. package/work-orders/THEME-6.md +0 -247
  326. package/work-orders/THEME-7.md +0 -82
  327. package/work-orders/THEME-8.md +0 -211
  328. package/work-orders/THEME-9.md +0 -194
  329. package/work-orders/UCM-AUTH-10.md +0 -490
  330. package/work-orders/UCM-AUTH-11.md +0 -185
  331. package/work-orders/UCM-AUTH-12.md +0 -98
  332. package/work-orders/UCM-AUTH-13.md +0 -47
  333. package/work-orders/UCM-AUTH-9.md +0 -207
  334. package/work-orders/UCM-CHART-10.md +0 -150
  335. package/work-orders/UCM-CHART-11.md +0 -132
  336. package/work-orders/UCM-CHART-12.md +0 -348
  337. package/work-orders/UCM-CHART-13.md +0 -122
  338. package/work-orders/UCM-CHART-14.md +0 -198
  339. package/work-orders/UCM-CHART-15.md +0 -187
  340. package/work-orders/UCM-CHART-16.md +0 -169
  341. package/work-orders/UCM-CHART-17.md +0 -195
  342. package/work-orders/UCM-CHART-18.md +0 -200
  343. package/work-orders/UCM-CHART-8.md +0 -147
  344. package/work-orders/UCM-CHART-9.md +0 -265
  345. package/work-orders/UCM-CHAT-1.md +0 -190
  346. package/work-orders/UCM-CHAT-2.md +0 -75
  347. package/work-orders/UCM-DEP-1.md +0 -63
  348. package/work-orders/UCM-I18N-4.md +0 -226
  349. package/work-orders/UCM-I18N-5.md +0 -211
  350. package/work-orders/UCM-MSG-20.md +0 -192
  351. package/work-orders/UCM-PRIM-2.md +0 -114
  352. package/work-orders/UCM-SHELL-7.md +0 -134
  353. package/work-orders/UCM-SHELL-8.md +0 -125
  354. package/work-orders/UCM-TEST-1.md +0 -304
  355. package/work-orders/UCM-THEME-13.md +0 -69
  356. package/work-orders/UCM-THEME-14.md +0 -312
  357. package/work-orders/UCM-THEME-15.md +0 -356
  358. package/work-orders/UCM-THEME-16.md +0 -80
  359. package/work-orders/UCM-THEME-17.md +0 -111
  360. package/work-orders/UCM-THEME-18.md +0 -184
  361. package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
  362. package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
  363. package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
  364. package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
  365. package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
  366. package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
  367. package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
@@ -1,375 +0,0 @@
1
- # MSG-3 — ucm messaging surfaces (full parity)
2
-
3
- Status: planned · Tier 2 · Target repo: `ui-core-micha` (main)
4
- **Binding spec:** `django-core-micha/docs/design/messaging-platform.md` — especially §ucm surface,
5
- §REST contract, §Realtime, §Notification contract. On any conflict the design doc wins; deviations
6
- from it are an operator scope change, never a silent edit.
7
-
8
- Canonical register row: `django-core-micha/WORK_ORDERS.md` (the `MSG-*` workstream register). This
9
- repo carries the ucm-side mirror row.
10
-
11
- ---
12
-
13
- ## Part A — Envelope (Expertenchat, 2026-07-31)
14
-
15
- ### Goal
16
-
17
- Build the shared messaging surfaces in ucm against the dcm messaging domain published in 2.36.1, so
18
- that a consuming app gets a complete chat UI by mounting a provider and a few components, and supplies
19
- only routing, display placement and scope pickers itself — never a forked state machine.
20
-
21
- ### Two operator decisions that shape this WO (2026-07-31)
22
-
23
- **1. Redesign is permitted — but no feature may be lost.** jg's current messaging UI is *not* a
24
- verbatim visual target: where it grew organically across MSG-B1..B4, MSG-UX and MSG-DIALOG-1, MSG-3
25
- may lay it out and structure the interaction better. The licence covers **layout, composition,
26
- visual language and interaction flow**. It does **not** cover the feature set: the design's paper
27
- test ("No jg feature is lost") stays binding, and dropping or degrading a capability is a scope
28
- change back to the operator, not a design choice.
29
-
30
- Because "redesign allowed" is easy to over-read, the WO carries a hard deliverable:
31
- **a written deviation list** — every behavioural difference from jg's current messaging UI, with a
32
- one-line rationale each, committed alongside the code (`docs/messaging-deviations.md` or an appendix
33
- in this file). "We changed nothing behaviourally" is an acceptable list; an absent list is not.
34
- Consequence to record now: **MSG-5 therefore becomes a visible change for jg users**, not a silent
35
- migration, and needs its own UX review at adoption.
36
-
37
- **2. Validation runs through the DX-1 dev harness.** ucm had no way to render anything; DX-1 adds a
38
- Vite dev page. MSG-3 is expected to **use** it: every surface gets a harness entry, and the redesign
39
- is iterated there rather than asserted in jsdom.
40
-
41
- ### Expected outcome
42
-
43
- Per design §ucm surface, a new `src/messaging/` subpackage mirroring the layout and conventions of the
44
- existing `src/notifications/` subpackage (module layout, `src/i18n/<domain>Translations.ts`, flat
45
- `tests/*.test.jsx`, additive barrel exports in `src/index.js` with an exports regression test):
46
-
47
- - `MessagingProvider` + hook, an API adapter over the dcm REST contract, and a normalized cache.
48
- - Realtime on **Layer 1**: `const { subscribe } = useRealtime()` — destructure it and depend on
49
- `subscribe`, never on the recreated context object (design §Realtime states this explicitly; it is
50
- a known footgun). Handle every frame the design lists, deduplicate by `event_id`, and refetch REST
51
- state and cursors on reconnect. **No second socket, no client→server WS.**
52
- - `ConversationList`, `Thread`, `Composer`, `ReadTicks`, `ReactionBar`, `PollCard`, `AttachmentList`,
53
- config and per-conversation preference surfaces, and conversation launchers.
54
- - Cursor pagination with infinite reverse scroll on thread history, from day one — the dcm contract
55
- is opaque signed cursors, **not** offset paging.
56
- - Optimistic send: the composer writes a local row keyed by `client_request_id`, reconciles the REST
57
- response and the WS confirmation into exactly one row, and surfaces retry/error without duplicates.
58
- - Labels, status text and validation messages in **de/en/fr**.
59
- - Host apps supply routing, display placement and scope pickers; ucm supplies the state machine.
60
-
61
- ### Parity inventory — the files that define "no feature lost"
62
-
63
- The deviation list must be built against **all** of these, not just the obvious component folder:
64
-
65
- | jg file | LOC | Note |
66
- |---|---|---|
67
- | `frontend/src/components/Messaging/Thread.jsx` | 2470 | the bulk: timeline, composer, replies, reactions, edit/delete, image upload, poll UI |
68
- | `frontend/src/components/Messaging/ConversationList.jsx` | 166 | |
69
- | `frontend/src/context/MessagingContext.jsx` | 184 | Layer-1 subscription + list/unread state |
70
- | `frontend/src/components/Messaging/AnnouncementDialog.jsx` | 147 | broadcast/announcement composer incl. `link_target` deep-link |
71
- | `frontend/src/components/Messaging/MessagingConfig.jsx` | 131 | per-scope config surface |
72
- | `frontend/src/components/Messaging/NewDirectMessageDialog.jsx` | 103 | DM launcher — **the first-contact case MSG-2b unblocked** |
73
- | `frontend/src/api/messagingApi.js` | 102 | |
74
- | `frontend/src/components/Messaging/EmojiPickerButton.jsx` | 44 | |
75
- | `frontend/src/components/Messaging/conversationHelpers.js` | 22 | |
76
- | **`frontend/src/pages/MessagesPage.jsx`** | **310** | **easy to miss and NOT purely host-app routing** — see below |
77
-
78
- ~3700 LOC excluding tests.
79
-
80
- **`MessagesPage.jsx` needs an explicit split.** It is nominally jg's page, but it embeds behaviour that
81
- belongs to this WO's "conversation launchers": the unified conversation+group list that surfaces
82
- *unopened* groups as clickable launch items, and broadcast-conversation auto-surfacing/auto-open via
83
- the `?tab=broadcast` query parameter. The page shell (routing, placement, master-detail layout) stays
84
- with the host app per design §ucm surface; **the launcher behaviour it currently embeds is ucm scope**
85
- and must appear in the deviation list either as reproduced or as an explicitly surfaced deviation.
86
- This file was missing from the first parity inventory and is exactly the shape of gap through which a
87
- feature disappears with nobody deciding to drop it.
88
-
89
- ### Decomposition is a requirement, not a preference
90
-
91
- jg's messaging UI is one 2470-LOC component with a 2173-LOC test file. **Reproducing that shape in ucm
92
- is a scope violation, even if every feature is present.** The component list above is a set of binding
93
- boundaries, not a suggested file layout. Concretely:
94
-
95
- - **Each named component is a separately exported, independently mountable, independently testable
96
- unit** — not an internal helper reachable only through `Thread`. `Composer`, `ReactionBar`,
97
- `PollCard`, `AttachmentList` and `ReadTicks` must each stand on their own.
98
- - **Domain state lives in the provider and its normalized cache; components read it through the
99
- hook.** Design §ucm surface says host apps get components, "not a forked state machine" — the
100
- corollary inside ucm is that subcomponents do not receive conversation/message state by
101
- prop-drilling through `Thread`. This is the actual cause of a 2470-LOC component, not the feature
102
- count. **This applies to domain state only** — conversations, messages, receipts, unread counts,
103
- poll results. Ephemeral UI state stays local to the component that owns it: composer draft text,
104
- upload progress, scroll and virtualization position, open menus, hover state. Lifting those into
105
- the provider would be a worse design, not a more compliant one.
106
- - **Every component gets its own DX-1 harness entry, mountable standalone.** This is the forcing
107
- function: a monolith cannot be mounted piecewise, so the harness makes accidental re-monolithisation
108
- visible immediately rather than at review time.
109
- - **Soft size trigger:** any single component file above ~400 LOC must be justified explicitly in that
110
- chunk's review. Not a hard cap — a deliberate, argued exception is fine, an unexamined 1500-line
111
- component is not.
112
- - `Thread` itself owns the timeline and its virtualization/scroll behaviour. Composing, reacting,
113
- poll rendering, attachment rendering and receipt display are **collaborators it renders**, not
114
- responsibilities it absorbs.
115
-
116
- The `ui_reviewer` pass at WO end covers this explicitly, alongside design-system consistency.
117
-
118
- ### Proposed chunk plan (staged commits, one independent review per chunk)
119
-
120
- 1. `MessagingProvider` + API adapter + normalized cache + Layer-1 subscription (frames, `event_id`
121
- dedup, reconnect refetch).
122
- 2. `ConversationList` + launchers + unread / archive / mute + list pagination.
123
- 3. `Thread` (timeline + scroll/virtualization only) + message rendering + one-level replies / thread
124
- view + infinite reverse scroll, with `ReadTicks` as a separate collaborator component.
125
- 4. `Composer` (optimistic send, retry/error) + attachment upload + `AttachmentList`.
126
- 5. `ReactionBar` + `PollCard` + config/preferences + i18n sweep + barrel exports + the deviation list.
127
-
128
- The register estimates 3–5 chunks. **Treat that as a floor, not a ceiling** — the jg parity target is
129
- ~3700 LOC excluding tests, with `Thread.jsx` alone at 2470. If the work does not fit, split further
130
- and say so; do not compress by dropping scope.
131
-
132
- ### Required tests to WRITE (scoped per chunk; the reconciliation set is mandatory)
133
-
134
- - **Optimistic send reconciliation:** a REST confirmation and a WS frame for the same
135
- `client_request_id` produce exactly one message row — the classic duplicate-message bug.
136
- - **`event_id` deduplication:** a repeated frame changes nothing.
137
- - **Reconnect:** current list, open thread and unread count are refetched; no stale cursor is reused.
138
- - **Pagination:** opaque cursor paging and reverse infinite scroll; a rejected cursor surfaces as an
139
- error rather than an empty thread.
140
- - **Read ticks:** aggregate state renders; per-recipient detail appears only where permitted and
141
- **never for a direct conversation** — mirror the dcm carve-out on the client so the UI cannot imply
142
- a capability the API refuses.
143
- - **Attachment upload errors** surface as user-visible validation, not a generic failure (the MSG-2
144
- chunk-4 lesson: a rejected upload must read as a rejection).
145
- - **i18n coverage:** every new key exists in all three languages; no hardcoded user-facing string.
146
- - **Exports regression:** the barrel exposes the new public surface, mirroring
147
- `tests/notificationsExports.test.js`. This doubles as the decomposition check — every named
148
- component must be individually exported and individually renderable in its own test, which a
149
- monolith cannot satisfy.
150
- - Existing ucm suites (notifications, onboarding, auth, charts) stay green — this WO is additive.
151
-
152
- Per AGENTS.md "Test scope", per-chunk runs stay scoped to that chunk; the WO-end gate is the
153
- affected-area set (messaging + notifications, since both share the Layer-1 transport).
154
-
155
- ### Reviews
156
-
157
- Beyond the standard independent `reviewer` per chunk, this WO explicitly carries **`ui_reviewer`** at
158
- WO end — design-system consistency, reuse of existing ucm primitives, responsive behaviour, dark mode
159
- and translation coverage. With a redesign licence in play, that pass is not optional.
160
-
161
- ### Non-goals / do-not-touch
162
-
163
- dcm changes (small sibling contract fixes are in scope per the design's release plan, but a
164
- behavioural change to the dcm domain is not); any app-side code; jg's existing messaging UI (untouched
165
- until MSG-5); the jg data migration; search; typing indicators; client→server WebSocket; scanner
166
- infrastructure; `src/notifications/` behaviour beyond additive reuse — the Layer-1 primitive is
167
- consumed, not modified.
168
-
169
- ### Risks
170
-
171
- - **Largest v1 block, built without a consumer.** MSG-5 is the first mount. The DX-1 harness is the
172
- only feedback loop until then, and a mock adapter can drift from the real contract — shape fixtures
173
- from the design doc's REST/realtime sections, not from imagination.
174
- - **Redesign licence is the main scope risk.** Without the deviation list it silently becomes
175
- "reimplement approximately", and jg loses features nobody decided to drop.
176
- - **Optimistic send** is where duplicate/ghost messages come from; it has a mandatory test above.
177
- - **`useRealtime` misuse** re-subscribes on every render if the context object is a dependency — a
178
- documented footgun, called out in expected outcome.
179
- - Estimate risk: see the chunk plan note.
180
-
181
- ### Preconditions
182
-
183
- dcm messaging published (2.36.1, incl. MSG-2b) · **DX-1 done** (the harness this WO validates
184
- against) · Approval Gate #1 for MSG-3 = operator go on this envelope.
185
-
186
- ### Release
187
-
188
- One version bump + npm publish at WO end. No consumer pins are bumped here; MSG-5 picks the release
189
- up via its own registry live-check before pinning.
190
-
191
- ### Execution directive
192
-
193
- Implement through `codex exec` in the background — invoked **directly via Bash** (never the
194
- `debugger`/`*_coder` Agent wrappers) with **both** flags `--skip-git-repo-check` and
195
- `--dangerously-bypass-approvals-and-sandbox`, prompt passed as a positional argument from a file;
196
- fall back to direct Claude implementation only on Codex quota / rate-limit / non-zero exit. One
197
- invocation per chunk, each chunk left uncommitted for the orchestrator's independent review.
198
-
199
- ### Mini-handover (pastable)
200
-
201
- Orchestrator: implement `work-orders/MSG-3.md` in `ui-core-micha` (main), chunk by chunk starting at
202
- chunk 1. `git pull` first, read the WO + `django-core-micha/docs/design/messaging-platform.md`
203
- (§ucm surface, §REST contract, §Realtime), then follow `orchestrate-codex` (Codex-first per chunk,
204
- own review per chunk, `ui_reviewer` at WO end, one publish at WO end).
205
-
206
- ---
207
-
208
- ## Part B — Implementation map (Orchestrator)
209
-
210
- ### Target repo / working directory
211
-
212
- `C:\Users\biglmi\Documents\webapps\ui-core-micha` (repo root; package `@micha.bigler/ui-core-micha`,
213
- current published version 2.15.0). **Precondition: DX-1 must be landed and committed first** — do
214
- not start this WO's chunk 1 until DX-1's commit exists on `main`.
215
-
216
- ### Operator-approved exception: additive Layer-1 reconnect signal (2026-07-31)
217
-
218
- Chunk 1's first dispatch found a real blocker: the design's "Reconnect refetches REST state/cursors"
219
- (§Realtime) cannot be implemented against the existing Layer-1 primitive. `useRealtimeCore`
220
- (`src/notifications/realtime.jsx`) tracks connect/backoff/reconnect internally but exposes only
221
- `{ subscribe }` — no consumer, including `NotificationsProvider`'s own `RealtimeContext.Provider`
222
- value, can observe a reconnect happening. This is confirmed by direct inspection, not assumed.
223
-
224
- **Operator decision:** extend `src/notifications/realtime.jsx` and (if needed to thread the value
225
- through) `src/notifications/NotificationsProvider.jsx` **additively** — e.g. an `onReconnect(callback)`
226
- registration or a `connected` boolean added to the object `useRealtimeCore` returns and the
227
- `RealtimeContext` value. This is the ONE approved exception to this WO's "consumed, not modified"
228
- boundary for `src/notifications/`; do not use it as license to touch anything else there. Requirements
229
- for the extension itself:
230
- - Purely additive — existing consumers destructuring only `{ subscribe }` must be completely
231
- unaffected (same behavior, same shape for the fields they read).
232
- - No new WS consumer, no change to the connection/backoff logic itself, only exposing a signal that
233
- already exists internally.
234
- - Covered by its own test in the existing `tests/realtime.test.jsx` (or a new adjacent test file
235
- following that convention) proving the reconnect signal actually fires when the internal `connect()`
236
- path re-establishes after a close — not just that the field exists.
237
- - This is chunk 1's first task, before the messaging-specific work; land it as a clearly-separated
238
- part of chunk 1's diff (the reviewer will look at it as its own concern) rather than mixing it
239
- invisibly into `MessagingProvider`'s implementation.
240
-
241
- ### Shared context package (applies to every chunk)
242
-
243
- **New subpackage to create:** `src/messaging/` — mirror `src/notifications/`'s layout and
244
- conventions: flat files (`api.js`, `realtime.jsx` or reuse ucm's existing one — see below,
245
- `MessagingProvider.jsx`, one file per named component), `src/i18n/messagingTranslations.ts` (flat
246
- `{"Key.SUBKEY": {"de":…, "en":…, "fr":…}}` shape, matching `notificationsTranslations.ts`/
247
- `chartsTranslations.ts`), flat `tests/*.test.jsx` (not nested under `tests/messaging/`), additive
248
- barrel exports in `src/index.js` with an exports-regression test extending
249
- `tests/notificationsExports.test.js`'s pattern (new file `tests/messagingExports.test.js` is fine,
250
- or extend the existing one — Codex's call, consistency with existing convention matters more than
251
- which file).
252
-
253
- **Binding spec:** `django-core-micha/docs/design/messaging-platform.md` in full — §ucm surface,
254
- §REST contract (exact endpoint list, payload shapes, cursor pagination), §Realtime (exact frame
255
- names and payload shape — note MSG-2 chunk 3's fix: `message_deleted` carries ONLY
256
- `message_id`/`deleted_at`/`deleted_by`, never content), §Notification contract (for awareness, not
257
- implementation — ucm consumes `Notification`/`feed_visible=False` types via the existing
258
- notifications surface, messaging doesn't re-implement notification delivery).
259
-
260
- **Realtime — reuse, do not reinvent:** `src/notifications/realtime.jsx` already exports
261
- `RealtimeContext`/`useRealtimeCore`/`useRealtime()`; `NotificationsProvider.jsx` is the sole mounter
262
- of `RealtimeContext.Provider` (one WebSocket for the whole app). `MessagingProvider` must be mounted
263
- **inside** an app's existing `NotificationsProvider` tree and call `useRealtime()` (throws if not
264
- wrapped — see `realtime.jsx:13-19`) to get `{ subscribe }`. **Destructure `subscribe` and depend on
265
- it in effects — never depend on the object `useRealtime()` returns**, which is recreated on every
266
- `NotificationsProvider` render including unrelated bell-state changes (documented footgun, design
267
- §Realtime, and jg's own `MessagingContext.jsx:32-35` comment explains exactly this bug). Messaging
268
- does NOT open a second socket and does NOT export its own `RealtimeContext`/provider — it is a second
269
- `subscribe(envelope, handler)` caller on the existing one, envelope key `"messaging"`.
270
-
271
- **jg reference implementation (generalize, do not port verbatim — jg is event-scoped and
272
- monolithic, ucm must be tenant-generic and decomposed per the envelope's decomposition requirement):**
273
- - `../jg-ferien/frontend/src/context/MessagingContext.jsx` (184 lines, already read in full this
274
- session) — provider shape precedent: WS handler switch on `data.type` (`message`,
275
- `message_edited`, `message_deleted`, `poll_updated`) updating a conversation list + unread count;
276
- `activeIdRef` pattern to avoid stale-closure issues in the WS handler; `markConversationRead`
277
- optimistic local update before/alongside the REST call. ucm's version must be scope/tenant-generic
278
- (no `eventId` parameter baked in — host app supplies scope/filter params) and must normalize into
279
- a proper cache (conversations, messages, threads, polls, reactions as separate normalized slices
280
- keyed by id), not just a flat conversation array — chunks 2-5 need to read/write messages and
281
- thread state independently of the conversation list.
282
- - `../jg-ferien/frontend/src/api/messagingApi.js` (102 lines, already read in full) — REST call
283
- shape precedent (axios wrapper over `apiClient`). ucm's adapter targets the NEW dcm paths from the
284
- design doc (`/api/messaging/conversations/`, `/api/messaging/conversations/direct/`, etc.) — these
285
- differ from jg's current paths (jg's own adoption/migration is MSG-5, a separate WO; do not target
286
- jg's current legacy paths, target the published dcm 2.36.1 contract in the design doc).
287
- - `../jg-ferien/frontend/src/context/realtimeEnvelopes.js` — `MESSAGING_ENVELOPE = "messaging"`, the
288
- envelope discriminator string ucm's `subscribe("messaging", handler)` call must use (matches the
289
- dcm design doc's realtime frame `envelope: 'messaging'` field).
290
- - `src/notifications/NotificationsProvider.jsx` (already read in part) — `normalizeNotification`-style
291
- normalization pattern, `useCallback`/`useRef` conventions, how it composes `AuthContext` + realtime
292
- + REST fetch into one provider. Use as the shape precedent for `MessagingProvider`, not as a literal
293
- template (notifications is a flat feed; messaging needs a genuinely normalized multi-entity cache).
294
-
295
- **Invariants (all chunks):**
296
- - No app-specific code — no event/scope assumptions baked into components; scope/filter params are
297
- passed in by the host app (design §ucm surface: "host apps supply routing, display placement and
298
- scope pickers").
299
- - Every named component (`ConversationList`, `Thread`, `Composer`, `ReadTicks`, `ReactionBar`,
300
- `PollCard`, `AttachmentList`) is independently exported and independently mountable — verify via
301
- its own DX-1 harness entry per the envelope's decomposition requirement, not just via `Thread`
302
- rendering it internally.
303
- - Domain state (conversations, messages, receipts, unread counts, poll results) lives in the
304
- provider's normalized cache; components read via the hook. Ephemeral UI state (draft text, upload
305
- progress, scroll position, open menus) stays component-local — do not lift it into the provider.
306
- - Cursor pagination is opaque and signed (matches dcm's `django.core.signing`-based cursor) — never
307
- build an offset/page-number UI; a bad/tampered cursor from the API is a 400, surface it as an
308
- error state, not an empty list.
309
- - `client_request_id`-keyed optimistic send: composer writes a local pending row immediately,
310
- reconciles when the REST response and/or the WS `message` frame for the same id arrives — must
311
- converge to exactly one row, not two.
312
- - i18n: every user-facing string goes through `messagingTranslations.ts` in all three languages; no
313
- hardcoded text.
314
- - No client→server WebSocket path anywhere — every write is REST, even optimistic ones (the socket
315
- is read-only fan-out).
316
-
317
- ### Chunk 1 — this dispatch
318
-
319
- **Scope:** `MessagingProvider` + hook (`useMessaging()`) + API adapter (`src/messaging/api.js`) +
320
- normalized cache + Layer-1 subscription (frame handling for at least `message`, `message_edited`,
321
- `message_deleted`, `conversation_upsert`, `participant_changed`; the remaining frame types
322
- `reaction`/`poll_updated`/`delivered`/`read_state`/`thread_read_state`/`attachment_ready`/
323
- `conversation_archived` can have handler stubs wired now and filled in by the chunk that owns that
324
- feature — e.g. `poll_updated` real handling lands in chunk 5 with `PollCard`, but the dedup/dispatch
325
- plumbing must exist now so later chunks only add a case, not restructure the subscriber). `event_id`
326
- deduplication (a `Set` of recently-seen ids, per design's "handlers deduplicate `event_id`").
327
- Reconnect refetch (on the realtime connection re-establishing, refetch current conversation list +
328
- open thread + unread count — jg has no precedent for this since it never handles reconnect
329
- explicitly; this is a v1 requirement per design §Realtime "Reconnect refetches REST state/cursors").
330
-
331
- **No components in this chunk** — `ConversationList`/`Thread`/etc. are chunks 2-5. This chunk's DX-1
332
- harness entry (if any) is a minimal "provider + raw state dump" page proving the provider mounts,
333
- fetches, and updates on a simulated WS frame — full component harness entries land with their
334
- owning chunks.
335
-
336
- **Required tests for this chunk:**
337
- - `event_id` deduplication: a repeated frame changes nothing (mandatory per envelope).
338
- - Reconnect: refetch is triggered (mock the realtime reconnect signal — check `useRealtimeCore`/DX-1
339
- harness's mock adapter for how a reconnect is simulated; if the mock adapter can't yet simulate a
340
- reconnect, that's a DX-1 gap to note, not something to silently skip).
341
- - API adapter: each REST call targets the correct dcm path/method per the design doc's §REST table
342
- (a scoped unit test per function is fine, doesn't need a live backend).
343
- - Normalized cache: applying a `message` frame updates only the affected conversation's/message's
344
- slice, not the whole cache (proves normalization, not just "state changed").
345
- - Exports regression: `MessagingProvider`/`useMessaging` reachable from the barrel.
346
-
347
- ### Progress contract (every chunk)
348
-
349
- Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
350
- `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (file opened, file
351
- edited, command/test run) and `PROGRESS: [<n>/<total>] done` on step completion, spaced so no gap
352
- exceeds ~2 min, stdout unbuffered, and exactly one final `RESULT: DONE|BLOCKED <reason>` per chunk.
353
-
354
- ### Preamble (append verbatim to every chunk's Codex prompt)
355
-
356
- The text above is the COMPLETE spec for this chunk — read nearest `AGENTS.md`,
357
- `.codex/skills/<role>/SKILL.md` (if present), and this repo's `MEMORY.md` only for conventions; stay
358
- in scope; do not touch anything outside `src/messaging/`, `src/i18n/messagingTranslations.ts`, the
359
- named test files, and additive `src/index.js` barrel exports; do not touch
360
- `peerDependencies`/`dependencies` (only this WO's own runtime needs, if any, and only with the
361
- orchestrator's awareness — flag before adding anything beyond what's already a peer/dev dependency);
362
- do not update `MEMORY.md`; do NOT `git add`/`commit`/`push` — leave the chunk's changes uncommitted
363
- for the orchestrator's independent review. WRITE this chunk's required tests AND RUN them to confirm
364
- they pass — that is your only test run: do NOT run the full ucm suite and do NOT run any review; the
365
- orchestrator runs the affected-area set and the independent review after you finish. Use the DX-1 dev
366
- harness (`dev/` or wherever DX-1 placed it) to visually verify anything you build that renders —
367
- add/update a harness entry for this chunk's surface even if the required tests above don't mention it
368
- explicitly, per the envelope's "every surface gets a harness entry" requirement.
369
-
370
- ### Mini-handover (pastable, per chunk)
371
-
372
- Orchestrator: implement chunk <n> of `work-orders/MSG-3.md` in `ui-core-micha` (main). `git pull`
373
- first, read the WO + `django-core-micha/docs/design/messaging-platform.md`, then follow
374
- `orchestrate-codex` (Codex-first, own independent review per chunk, `ui_reviewer` at WO end, one
375
- publish at WO end).