@micha.bigler/ui-core-micha 3.14.4 → 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 (341) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +7 -0
  3. package/dist/chat/kitSxRegistry.js +9 -0
  4. package/dist/components/charts/kitSxRegistry.js +6 -0
  5. package/dist/entries/charts.js +6 -0
  6. package/dist/entries/chat.js +8 -0
  7. package/dist/entries/markdown.js +1 -0
  8. package/dist/index.js +0 -14
  9. package/dist/pages/AccountPage.js +1 -2
  10. package/dist/pages/LoginPage.js +1 -2
  11. package/dist/pages/PasswordChangePage.js +1 -2
  12. package/dist/pages/PasswordInvitePage.js +1 -2
  13. package/dist/pages/PasswordResetRequestPage.js +1 -2
  14. package/dist/pages/SignUpPage.js +1 -2
  15. package/dist/pages/SignupConfirmPage.js +1 -2
  16. package/dist/theme/kitSxEntry.js +11 -0
  17. package/dist/theme/kitSxRegistry.js +2 -15
  18. package/package.json +32 -7
  19. package/.github/workflows/ci.yml +0 -35
  20. package/.github/workflows/publish.yml +0 -126
  21. package/DESIGN.md +0 -60
  22. package/WORK_ORDERS.md +0 -150
  23. package/dev/entries.jsx +0 -721
  24. package/dev/fixtures.js +0 -26
  25. package/dev/main.jsx +0 -75
  26. package/dev/mockTransport.jsx +0 -128
  27. package/docs/CHART-LAYOUT.md +0 -157
  28. package/docs/DARK-TOKENS.md +0 -140
  29. package/docs/TYPE-SCALE.md +0 -111
  30. package/docs/messaging-deviations.md +0 -118
  31. package/index.html +0 -12
  32. package/renovate.json +0 -10
  33. package/scripts/chart-api-census.mjs +0 -415
  34. package/src/auth/AuthContext.jsx +0 -158
  35. package/src/auth/ReauthModal.jsx +0 -82
  36. package/src/auth/UserMenu.jsx +0 -121
  37. package/src/auth/apiClient.jsx +0 -232
  38. package/src/auth/authApi.jsx +0 -539
  39. package/src/auth/authConfig.jsx +0 -34
  40. package/src/auth/reauth.js +0 -47
  41. package/src/chat/ChatComposer.jsx +0 -36
  42. package/src/chat/ChatList.jsx +0 -87
  43. package/src/chat/ChatThread.jsx +0 -128
  44. package/src/chat/ChatWorkspace.jsx +0 -244
  45. package/src/chat/MarkdownReply.jsx +0 -22
  46. package/src/chat/ModelPicker.jsx +0 -85
  47. package/src/chat/api.js +0 -18
  48. package/src/chat/useChatSocket.js +0 -32
  49. package/src/chat/wire.js +0 -7
  50. package/src/components/AccessCodeManager.jsx +0 -288
  51. package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
  52. package/src/components/AllowedEmailDomainsManager.jsx +0 -92
  53. package/src/components/AuthFactorRequirementCard.jsx +0 -95
  54. package/src/components/BulkInviteCsvTab.jsx +0 -198
  55. package/src/components/EmptyState.jsx +0 -38
  56. package/src/components/LoginForm.jsx +0 -159
  57. package/src/components/MFAComponent.jsx +0 -350
  58. package/src/components/MfaLoginComponent.jsx +0 -252
  59. package/src/components/MobileBottomNav.jsx +0 -82
  60. package/src/components/PasskeysComponent.jsx +0 -252
  61. package/src/components/PasswordChangeForm.jsx +0 -87
  62. package/src/components/PasswordResetRequestForm.jsx +0 -43
  63. package/src/components/PasswordSetForm.jsx +0 -97
  64. package/src/components/ProfileComponent.jsx +0 -348
  65. package/src/components/QrSignupManager.jsx +0 -404
  66. package/src/components/QrSignupValidityManager.jsx +0 -106
  67. package/src/components/RegistrationMethodsManager.jsx +0 -150
  68. package/src/components/SecurityComponent.jsx +0 -141
  69. package/src/components/SocialLoginButtons.jsx +0 -83
  70. package/src/components/SoftChip.jsx +0 -93
  71. package/src/components/StatTile.jsx +0 -39
  72. package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
  73. package/src/components/TurnstileWidget.jsx +0 -99
  74. package/src/components/UserInviteComponent.jsx +0 -76
  75. package/src/components/UserListComponent.jsx +0 -618
  76. package/src/components/charts/BarChart.jsx +0 -102
  77. package/src/components/charts/ChartFrame.jsx +0 -214
  78. package/src/components/charts/LineChart.jsx +0 -126
  79. package/src/components/charts/ScatterChart.jsx +0 -299
  80. package/src/components/charts/TimeSeriesChart.jsx +0 -300
  81. package/src/components/charts/chartDefaults.js +0 -644
  82. package/src/components/charts/chartLabels.js +0 -36
  83. package/src/components/charts/exportChart.js +0 -258
  84. package/src/components/charts/formatters.js +0 -39
  85. package/src/components/charts/palette.js +0 -33
  86. package/src/components/charts/yearTickInterval.js +0 -7
  87. package/src/i18n/authTranslations.ts +0 -2651
  88. package/src/i18n/chartsTranslations.ts +0 -91
  89. package/src/i18n/chatTranslations.ts +0 -55
  90. package/src/i18n/messagingTranslations.ts +0 -120
  91. package/src/i18n/notificationsTranslations.ts +0 -32
  92. package/src/i18n/onboardingTranslations.ts +0 -29
  93. package/src/i18n/sectionNavTranslations.ts +0 -20
  94. package/src/i18n/uiCoreTranslations.js +0 -29
  95. package/src/i18n/userMenuTranslations.ts +0 -5
  96. package/src/index.js +0 -158
  97. package/src/layout/PageLayout.jsx +0 -36
  98. package/src/layout/SectionNav.jsx +0 -320
  99. package/src/messaging/AttachmentList.jsx +0 -145
  100. package/src/messaging/Composer.jsx +0 -197
  101. package/src/messaging/ConversationLaunchers.jsx +0 -51
  102. package/src/messaging/ConversationList.jsx +0 -109
  103. package/src/messaging/DirectMessageLauncher.jsx +0 -112
  104. package/src/messaging/MessageBubble.jsx +0 -183
  105. package/src/messaging/MessagingProvider.jsx +0 -0
  106. package/src/messaging/MessagingScopeConfig.jsx +0 -24
  107. package/src/messaging/PollCard.jsx +0 -163
  108. package/src/messaging/ReactionBar.jsx +0 -43
  109. package/src/messaging/ReadTicks.jsx +0 -82
  110. package/src/messaging/Thread.jsx +0 -195
  111. package/src/messaging/api.js +0 -48
  112. package/src/messaging/composerImageCompression.js +0 -35
  113. package/src/messaging/linkifyText.jsx +0 -37
  114. package/src/notifications/NotificationBell.jsx +0 -84
  115. package/src/notifications/NotificationSettings.jsx +0 -330
  116. package/src/notifications/NotificationsProvider.jsx +0 -224
  117. package/src/notifications/PopupSurface.jsx +0 -105
  118. package/src/notifications/api.js +0 -55
  119. package/src/notifications/feedApi.js +0 -18
  120. package/src/notifications/realtime.jsx +0 -138
  121. package/src/notifications/serviceWorker/sw.js +0 -50
  122. package/src/onboarding/OnboardingProvider.jsx +0 -326
  123. package/src/onboarding/OnboardingWizard.jsx +0 -61
  124. package/src/onboarding/WizardDialogShell.jsx +0 -51
  125. package/src/onboarding/api.js +0 -13
  126. package/src/onboarding/stepSelection.js +0 -16
  127. package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
  128. package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
  129. package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
  130. package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
  131. package/src/pages/AccountPage.jsx +0 -394
  132. package/src/pages/LoginPage.jsx +0 -343
  133. package/src/pages/PasswordChangePage.jsx +0 -62
  134. package/src/pages/PasswordInvitePage.jsx +0 -177
  135. package/src/pages/PasswordResetRequestPage.jsx +0 -68
  136. package/src/pages/SignUpPage.jsx +0 -268
  137. package/src/pages/SignupConfirmPage.jsx +0 -155
  138. package/src/testing/checkKitIntegration.js +0 -233
  139. package/src/theme/createAppTheme.js +0 -423
  140. package/src/theme/fonts.js +0 -3
  141. package/src/theme/index.js +0 -21
  142. package/src/theme/kitSxRegistry.js +0 -285
  143. package/src/theme/themeCompleteness.js +0 -1045
  144. package/src/theme/tokens.js +0 -478
  145. package/src/utils/auth-errors.js +0 -76
  146. package/src/utils/authService.js +0 -223
  147. package/src/utils/resolveErrorText.js +0 -28
  148. package/src/utils/webauthn.js +0 -51
  149. package/tests/AccountPage.profileStatements.test.jsx +0 -162
  150. package/tests/AccountPage.test.jsx +0 -200
  151. package/tests/AuthContext.test.jsx +0 -129
  152. package/tests/BarChart.test.jsx +0 -112
  153. package/tests/BrowserPushStep.test.jsx +0 -110
  154. package/tests/ChartFrame.test.jsx +0 -336
  155. package/tests/ConversationList.test.jsx +0 -144
  156. package/tests/CookieConsentStep.test.jsx +0 -69
  157. package/tests/EmptyState.test.jsx +0 -62
  158. package/tests/LineChart.test.jsx +0 -80
  159. package/tests/MessagingProvider.test.jsx +0 -50
  160. package/tests/MobileBottomNav.test.jsx +0 -319
  161. package/tests/NotificationBell.test.jsx +0 -60
  162. package/tests/NotificationSettings.test.jsx +0 -276
  163. package/tests/NotificationsProvider.test.jsx +0 -240
  164. package/tests/OnboardingProvider.test.jsx +0 -294
  165. package/tests/OnboardingWizard.test.jsx +0 -143
  166. package/tests/PasswordChangeForm.test.jsx +0 -70
  167. package/tests/PasswordInvitePage.test.jsx +0 -142
  168. package/tests/PasswordSetForm.test.jsx +0 -70
  169. package/tests/PopupSurface.test.jsx +0 -142
  170. package/tests/ProfileComponent.refresh.test.jsx +0 -194
  171. package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
  172. package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
  173. package/tests/ScatterChart.test.jsx +0 -270
  174. package/tests/SectionNav.test.jsx +0 -363
  175. package/tests/SignUpPage.test.jsx +0 -208
  176. package/tests/SoftChip.test.jsx +0 -105
  177. package/tests/StatTile.test.jsx +0 -57
  178. package/tests/Thread.test.jsx +0 -151
  179. package/tests/TimeSeriesChart.test.jsx +0 -367
  180. package/tests/UserListComponent.test.jsx +0 -192
  181. package/tests/UserMenu.test.jsx +0 -171
  182. package/tests/apiClientLanguage.test.js +0 -33
  183. package/tests/apiClientPublicPaths.test.js +0 -178
  184. package/tests/authApiLogin.test.js +0 -42
  185. package/tests/authApiRegistration.test.js +0 -31
  186. package/tests/authErrorCodeRendering.test.jsx +0 -77
  187. package/tests/authErrors.test.js +0 -74
  188. package/tests/authTranslations.test.js +0 -74
  189. package/tests/chart-api-census.test.js +0 -366
  190. package/tests/chartAxisTickBand.test.jsx +0 -95
  191. package/tests/chartDefaults.test.js +0 -902
  192. package/tests/chartLabels.test.js +0 -50
  193. package/tests/chartsPalette.test.js +0 -99
  194. package/tests/chatApi.test.js +0 -48
  195. package/tests/chatDriverNames.test.jsx +0 -71
  196. package/tests/chatExports.test.js +0 -3
  197. package/tests/chatList.test.jsx +0 -84
  198. package/tests/chatPicker.test.jsx +0 -82
  199. package/tests/chatSocket.test.jsx +0 -26
  200. package/tests/chatThread.test.jsx +0 -116
  201. package/tests/chatTranslations.test.js +0 -47
  202. package/tests/chatWorkspace.test.jsx +0 -234
  203. package/tests/checkKitIntegration.test.jsx +0 -219
  204. package/tests/createAppTheme.test.js +0 -132
  205. package/tests/createAppThemeDark.test.js +0 -127
  206. package/tests/createAppThemeLightGuard.test.js +0 -40
  207. package/tests/createAppThemePageContrast.test.js +0 -108
  208. package/tests/createAppThemeTypography.test.js +0 -53
  209. package/tests/errorCallSiteGuard.test.js +0 -32
  210. package/tests/exportChart.test.js +0 -313
  211. package/tests/feedApi.test.js +0 -46
  212. package/tests/fixtures/light-theme-baseline.json +0 -2234
  213. package/tests/i18nAggregate.test.js +0 -120
  214. package/tests/i18nGermanVariant.test.js +0 -65
  215. package/tests/loginPageErrorResolution.test.jsx +0 -102
  216. package/tests/messagingApi.test.js +0 -32
  217. package/tests/messagingChunk6.test.jsx +0 -116
  218. package/tests/messagingCompactBubble.test.jsx +0 -64
  219. package/tests/messagingComposer.test.jsx +0 -136
  220. package/tests/messagingComposerChunk5.test.jsx +0 -113
  221. package/tests/messagingContractConformance.test.js +0 -69
  222. package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
  223. package/tests/messagingExports.test.js +0 -21
  224. package/tests/messagingInteractions.test.jsx +0 -136
  225. package/tests/messagingLastMessagePreview.test.jsx +0 -93
  226. package/tests/messagingLinkify.test.jsx +0 -51
  227. package/tests/messagingMessageActions.test.jsx +0 -163
  228. package/tests/messagingMsg6.test.jsx +0 -105
  229. package/tests/messagingMsg6f.test.jsx +0 -155
  230. package/tests/messagingMsg6g.test.jsx +0 -166
  231. package/tests/messagingMsg6h.test.jsx +0 -136
  232. package/tests/messagingMsg6i.test.jsx +0 -129
  233. package/tests/messagingPollRendering.test.jsx +0 -142
  234. package/tests/messagingReactionMerge.test.jsx +0 -77
  235. package/tests/messagingReadTicksTooltip.test.jsx +0 -36
  236. package/tests/messagingThreadReceipts.test.jsx +0 -178
  237. package/tests/messagingThreadingQuoting.test.jsx +0 -87
  238. package/tests/messagingUnreadLifecycle.test.jsx +0 -78
  239. package/tests/notificationsApi.test.js +0 -41
  240. package/tests/notificationsExports.test.js +0 -34
  241. package/tests/onboardingDescriptors.test.js +0 -132
  242. package/tests/packageTreeShaking.test.js +0 -126
  243. package/tests/realtime.test.jsx +0 -219
  244. package/tests/resolveErrorText.test.js +0 -72
  245. package/tests/stepSelection.test.js +0 -53
  246. package/tests/themeCompleteness.test.js +0 -626
  247. package/tests/timeSeriesLegend.test.js +0 -99
  248. package/tests/userScreenTranslations.test.jsx +0 -218
  249. package/tsconfig.build.json +0 -18
  250. package/vite.config.mjs +0 -6
  251. package/work-orders/AUTH-1.md +0 -74
  252. package/work-orders/AUTH-2.md +0 -74
  253. package/work-orders/AUTH-4.md +0 -183
  254. package/work-orders/AUTH-5.md +0 -154
  255. package/work-orders/AUTH-7.md +0 -181
  256. package/work-orders/AUTH-8.md +0 -184
  257. package/work-orders/CHART-1.md +0 -285
  258. package/work-orders/CHART-2.md +0 -222
  259. package/work-orders/CHART-3.md +0 -163
  260. package/work-orders/CHART-4.md +0 -203
  261. package/work-orders/CHART-5.md +0 -226
  262. package/work-orders/CHART-6.md +0 -428
  263. package/work-orders/CHART-7.md +0 -175
  264. package/work-orders/DX-1.md +0 -169
  265. package/work-orders/DX-2.md +0 -188
  266. package/work-orders/DX-3.md +0 -195
  267. package/work-orders/I18N-1.md +0 -254
  268. package/work-orders/I18N-3.md +0 -207
  269. package/work-orders/MSG-3.md +0 -375
  270. package/work-orders/MSG-3b.md +0 -1002
  271. package/work-orders/MSG-3c.md +0 -378
  272. package/work-orders/MSG-3d.md +0 -268
  273. package/work-orders/MSG-3e.md +0 -164
  274. package/work-orders/MSG-3f.md +0 -391
  275. package/work-orders/MSG-6e.md +0 -308
  276. package/work-orders/MSG-6f.md +0 -214
  277. package/work-orders/MSG-6g.md +0 -244
  278. package/work-orders/MSG-6h.md +0 -238
  279. package/work-orders/MSG-6i.md +0 -271
  280. package/work-orders/MSG-6j.md +0 -117
  281. package/work-orders/NOTIF-12.md +0 -214
  282. package/work-orders/NOTIF-13.md +0 -142
  283. package/work-orders/NOTIF-14.md +0 -151
  284. package/work-orders/PRIM-1.md +0 -177
  285. package/work-orders/SHELL-1.md +0 -255
  286. package/work-orders/SHELL-2.md +0 -197
  287. package/work-orders/SHELL-3.md +0 -359
  288. package/work-orders/SHELL-4.md +0 -351
  289. package/work-orders/SHELL-5.md +0 -345
  290. package/work-orders/SHELL-6.md +0 -210
  291. package/work-orders/THEME-1.md +0 -587
  292. package/work-orders/THEME-10.md +0 -303
  293. package/work-orders/THEME-11.md +0 -208
  294. package/work-orders/THEME-2.md +0 -339
  295. package/work-orders/THEME-3.md +0 -210
  296. package/work-orders/THEME-4.md +0 -271
  297. package/work-orders/THEME-5.md +0 -341
  298. package/work-orders/THEME-6.md +0 -247
  299. package/work-orders/THEME-7.md +0 -82
  300. package/work-orders/THEME-8.md +0 -211
  301. package/work-orders/THEME-9.md +0 -194
  302. package/work-orders/UCM-AUTH-10.md +0 -490
  303. package/work-orders/UCM-AUTH-11.md +0 -185
  304. package/work-orders/UCM-AUTH-12.md +0 -98
  305. package/work-orders/UCM-AUTH-13.md +0 -47
  306. package/work-orders/UCM-AUTH-9.md +0 -207
  307. package/work-orders/UCM-CHART-10.md +0 -150
  308. package/work-orders/UCM-CHART-11.md +0 -132
  309. package/work-orders/UCM-CHART-12.md +0 -348
  310. package/work-orders/UCM-CHART-13.md +0 -122
  311. package/work-orders/UCM-CHART-14.md +0 -198
  312. package/work-orders/UCM-CHART-15.md +0 -187
  313. package/work-orders/UCM-CHART-16.md +0 -169
  314. package/work-orders/UCM-CHART-17.md +0 -195
  315. package/work-orders/UCM-CHART-18.md +0 -200
  316. package/work-orders/UCM-CHART-8.md +0 -147
  317. package/work-orders/UCM-CHART-9.md +0 -265
  318. package/work-orders/UCM-CHAT-1.md +0 -190
  319. package/work-orders/UCM-CHAT-2.md +0 -75
  320. package/work-orders/UCM-CI-1.md +0 -65
  321. package/work-orders/UCM-DEP-1.md +0 -63
  322. package/work-orders/UCM-I18N-4.md +0 -226
  323. package/work-orders/UCM-I18N-5.md +0 -211
  324. package/work-orders/UCM-MSG-20.md +0 -192
  325. package/work-orders/UCM-PRIM-2.md +0 -114
  326. package/work-orders/UCM-SHELL-7.md +0 -134
  327. package/work-orders/UCM-SHELL-8.md +0 -125
  328. package/work-orders/UCM-TEST-1.md +0 -304
  329. package/work-orders/UCM-THEME-13.md +0 -69
  330. package/work-orders/UCM-THEME-14.md +0 -312
  331. package/work-orders/UCM-THEME-15.md +0 -356
  332. package/work-orders/UCM-THEME-16.md +0 -80
  333. package/work-orders/UCM-THEME-17.md +0 -111
  334. package/work-orders/UCM-THEME-18.md +0 -184
  335. package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
  336. package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
  337. package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
  338. package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
  339. package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
  340. package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
  341. 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).