@cosmicdrift/kumiko-samples 0.391.1 → 0.392.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 (137) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +1 -1
  3. package/packages/bundled-features/src/admin-shell/changes.json +6 -0
  4. package/packages/bundled-features/src/admin-shell/feature.ts +60 -31
  5. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +2 -2
  6. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +2 -2
  7. package/packages/bundled-features/src/cap-overview/changes.json +12 -0
  8. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -0
  9. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +3 -2
  10. package/packages/bundled-features/src/cap-overview/i18n.ts +4 -0
  11. package/packages/bundled-features/src/cap-overview/types.ts +4 -1
  12. package/packages/bundled-features/src/cap-overview/web/cap-amount-format.ts +37 -0
  13. package/packages/bundled-features/src/cap-overview/web/cap-cards-panel.tsx +138 -54
  14. package/packages/bundled-features/src/cap-overview/web/cap-usage-bar.tsx +18 -4
  15. package/packages/bundled-features/src/cap-overview/web/cap-usage-cell.tsx +6 -3
  16. package/packages/bundled-features/src/cap-overview/web/usage-math.ts +5 -1
  17. package/packages/bundled-features/src/channel-email/app-transport.ts +37 -0
  18. package/packages/bundled-features/src/channel-email/changes.json +6 -0
  19. package/packages/bundled-features/src/channel-email/feature.ts +6 -0
  20. package/packages/bundled-features/src/channel-email/index.ts +5 -0
  21. package/packages/bundled-features/src/channel-email/smtp-transport.ts +2 -22
  22. package/packages/bundled-features/src/foundation-shared/changes.json +6 -0
  23. package/packages/bundled-features/src/foundation-shared/index.ts +1 -0
  24. package/packages/bundled-features/src/foundation-shared/mail-display-name.ts +20 -0
  25. package/packages/bundled-features/src/inbound-mail-foundation/account-record.ts +48 -0
  26. package/packages/bundled-features/src/inbound-mail-foundation/changes.json +18 -0
  27. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +1 -1
  28. package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +17 -0
  29. package/packages/bundled-features/src/inbound-mail-foundation/index.ts +18 -0
  30. package/packages/bundled-features/src/inbound-mail-foundation/outbound-mail.ts +66 -0
  31. package/packages/bundled-features/src/inbound-mail-foundation/probe.ts +8 -45
  32. package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +14 -0
  33. package/packages/bundled-features/src/inbound-mail-foundation/send-from-account.ts +118 -0
  34. package/packages/bundled-features/src/inbound-mail-foundation/types.ts +8 -0
  35. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +13 -8
  36. package/packages/bundled-features/src/inbound-provider-imap/changes.json +12 -0
  37. package/packages/bundled-features/src/inbound-provider-imap/connect-mailbox.ts +156 -0
  38. package/packages/bundled-features/src/inbound-provider-imap/constants.ts +42 -0
  39. package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +49 -1
  40. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +12 -35
  41. package/packages/bundled-features/src/inbound-provider-imap/i18n.ts +48 -0
  42. package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +1 -1
  43. package/packages/bundled-features/src/inbound-provider-imap/screens.ts +44 -0
  44. package/packages/bundled-features/src/inbound-provider-imap/send-mail.ts +73 -0
  45. package/packages/bundled-features/src/inbound-provider-imap/sent-folder.ts +49 -0
  46. package/packages/bundled-features/src/inbound-provider-imap/smtp-client.ts +131 -0
  47. package/packages/bundled-features/src/legal-pages/README.md +5 -10
  48. package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
  49. package/packages/bundled-features/src/mail-foundation/i18n.ts +9 -1
  50. package/packages/bundled-features/src/mail-foundation/probe.ts +43 -22
  51. package/packages/bundled-features/src/readiness/built-in-probes.ts +15 -2
  52. package/packages/bundled-features/src/readiness/changes.json +30 -0
  53. package/packages/bundled-features/src/readiness/constants.ts +2 -0
  54. package/packages/bundled-features/src/readiness/i18n.ts +7 -1
  55. package/packages/bundled-features/src/readiness/index.ts +6 -1
  56. package/packages/bundled-features/src/readiness/screens.ts +25 -2
  57. package/packages/bundled-features/src/readiness/visible-results.ts +2 -1
  58. package/packages/bundled-features/src/renderer-foundation/README.md +19 -21
  59. package/packages/bundled-features/src/template-resolver/README.md +144 -165
  60. package/packages/bundled-features/src/tier-engine/changes.json +6 -0
  61. package/packages/bundled-features/src/tier-engine/feature.ts +17 -6
  62. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +3 -3
  63. package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +5 -3
  64. package/packages/bundled-features/src/user-data-rights/token-helpers.ts +5 -4
  65. package/samples/apps/cap-billing-demo/bin/server.ts +7 -7
  66. package/samples/apps/cap-billing-demo/src/feature.ts +38 -38
  67. package/samples/apps/cap-billing-demo/src/run-config.ts +20 -20
  68. package/samples/apps/cap-billing-demo/src/tier-map.ts +14 -14
  69. package/samples/apps/config-demo/src/app/server.ts +4 -4
  70. package/samples/apps/config-demo/src/features/demo/feature.ts +4 -4
  71. package/samples/apps/marketing-demo/playwright.config.ts +3 -3
  72. package/samples/apps/marketing-demo/src/app/client.tsx +2 -2
  73. package/samples/apps/marketing-demo/src/app/seed-data.ts +9 -9
  74. package/samples/apps/marketing-demo/src/app/seed.ts +14 -14
  75. package/samples/apps/marketing-demo/src/app/server.ts +7 -7
  76. package/samples/apps/marketing-demo/src/app/shell.tsx +3 -3
  77. package/samples/apps/marketing-demo/src/features/assets/feature.ts +3 -3
  78. package/samples/apps/marketing-demo/src/features/assets/i18n.ts +7 -7
  79. package/samples/apps/marketing-demo/src/features/assets/web/index.ts +2 -2
  80. package/samples/apps/showcase/src/app/client.tsx +3 -3
  81. package/samples/apps/showcase/src/app/seed-items.ts +14 -14
  82. package/samples/apps/showcase/src/app/server.ts +7 -7
  83. package/samples/apps/showcase/src/features/demos/feature.ts +13 -13
  84. package/samples/apps/showcase/src/features/demos/i18n.ts +2 -2
  85. package/samples/apps/showcase/src/features/demos/web/components/page.tsx +5 -5
  86. package/samples/apps/showcase/src/features/demos/web/index.ts +4 -4
  87. package/samples/apps/showcase/src/features/demos/web/pages/dialog.tsx +1 -1
  88. package/samples/apps/showcase/src/features/demos/web/pages/inputs.tsx +8 -8
  89. package/samples/apps/showcase/src/features/demos/web/pages/layout.tsx +5 -5
  90. package/samples/apps/showcase/src/features/demos/web/pages/toast.tsx +3 -3
  91. package/samples/apps/showcase/src/features/items/feature.ts +8 -8
  92. package/samples/apps/showcase/src/features/items/i18n.ts +3 -3
  93. package/samples/apps/showcase/src/features/items/index.ts +3 -3
  94. package/samples/apps/showcase/src/features/items/schema/index.ts +4 -4
  95. package/samples/apps/showcase/src/features/items/schema/item.ts +27 -27
  96. package/samples/apps/showcase/src/features/items/web/index.ts +6 -6
  97. package/samples/apps/styleguide/src/app/seed.ts +3 -3
  98. package/samples/apps/styleguide/src/app/server.ts +2 -2
  99. package/samples/apps/styleguide/src/app/shell.tsx +4 -4
  100. package/samples/apps/styleguide/src/features/content/web.tsx +6 -6
  101. package/samples/apps/styleguide/src/features/examples/feature.ts +8 -8
  102. package/samples/apps/styleguide/src/features/gallery/feature.ts +9 -9
  103. package/samples/apps/styleguide/src/features/gallery/web/Gallery.tsx +12 -12
  104. package/samples/apps/styleguide/src/features/widgets/feature.ts +2 -2
  105. package/samples/apps/styleguide/src/features/widgets/web/DashboardFilterEcho.tsx +3 -3
  106. package/samples/apps/styleguide/src/features/widgets/web/DashboardKpiIcon.tsx +4 -4
  107. package/samples/apps/ui-walkthrough/playwright.config.ts +6 -6
  108. package/samples/apps/ui-walkthrough/scripts/emit-e2e-data.ts +5 -5
  109. package/samples/apps/ui-walkthrough/src/app/auth-constants.ts +13 -13
  110. package/samples/apps/ui-walkthrough/src/app/client.tsx +2 -2
  111. package/samples/apps/ui-walkthrough/src/app/server.ts +14 -14
  112. package/samples/apps/ui-walkthrough/src/app/shell.tsx +3 -3
  113. package/samples/apps/use-all-bundled/bin/main.ts +5 -5
  114. package/samples/apps/use-all-bundled/feature-manifest.json +10 -4
  115. package/samples/apps/use-all-bundled/kumiko/schema.ts +7 -7
  116. package/samples/apps/use-all-bundled/scripts/check-coverage.ts +20 -20
  117. package/samples/apps/use-all-bundled/src/app/auth-constants.ts +4 -4
  118. package/samples/apps/use-all-bundled/src/app/client.tsx +4 -4
  119. package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +12 -12
  120. package/samples/apps/use-all-bundled/src/app/seed.ts +6 -6
  121. package/samples/apps/user-data-rights-demo/src/feature.ts +23 -23
  122. package/samples/apps/workspaces/playwright.config.ts +5 -5
  123. package/samples/apps/workspaces/src/app/auth-constants.ts +3 -3
  124. package/samples/apps/workspaces/src/app/server.ts +16 -16
  125. package/samples/apps/workspaces/src/app/shell.tsx +2 -2
  126. package/samples/apps/workspaces/src/features/demo/schema/order.ts +4 -4
  127. package/samples/apps/workspaces/src/features/demo-driver/feature.ts +5 -5
  128. package/samples/recipes/apex-surface-auth/src/feature.ts +31 -31
  129. package/samples/recipes/designer-demo/src/feature.ts +6 -6
  130. package/samples/recipes/encrypted-tenant-config/src/feature.ts +20 -20
  131. package/samples/recipes/lane-routing/src/feature.ts +5 -5
  132. package/samples/recipes/legal-pages/src/feature.ts +29 -29
  133. package/samples/recipes/record-detail-layout/src/feature.ts +21 -2
  134. package/samples/recipes/seed-migration/scripts/smoke.ts +20 -20
  135. package/samples/recipes/seed-migration/seeds/2026-01-01-initial-tenants.ts +11 -11
  136. package/samples/recipes/seed-migration/seeds/2026-02-01-fix-admin-roles.ts +13 -13
  137. package/samples/recipes/user-data-rights/src/feature.ts +13 -13
@@ -1,14 +1,14 @@
1
- // Demos-Feature — Server-Side. Registriert custom-Screens für die UI-
2
- // Demo-Pages (Buttons, Inputs, Banner, Text, Layout) und ihre Nav-
3
- // Einträge. Kein Entity, keine Handler — pure Custom-Screen-Showcase.
1
+ // Demos feature — server side. Registers custom screens for the UI
2
+ // demo pages (buttons, inputs, banner, text, layout) and their nav
3
+ // entries. No entity, no handlers — pure custom-screen showcase.
4
4
  //
5
- // FeatureName "showcase-demos" (nicht "showcase"): zwei defineFeature-
6
- // Aufrufe mit gleichem Namen würden in createRegistry mit
7
- // `Duplicate feature` werfen. Der Trennstrich zur items-Feature ist
8
- // also nicht Konvention-Geschmack, sondern technische Notwendigkeit.
5
+ // FeatureName "showcase-demos" (not "showcase"): two defineFeature
6
+ // calls with the same name would throw `Duplicate feature` in
7
+ // createRegistry. The hyphen separating it from the items feature is
8
+ // therefore not a matter of convention taste but a technical necessity.
9
9
  //
10
- // Die React-Components für die custom-Screens leben in pages/ und
11
- // werden client-side via clientFeatures.components zugeordnet (siehe
10
+ // The React components for the custom screens live in pages/ and
11
+ // are assigned client-side via clientFeatures.components (see
12
12
  // client.ts).
13
13
 
14
14
  import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
@@ -95,11 +95,11 @@ export const demosFeature = defineFeature("showcase-demos", (r) => {
95
95
  "Shows the SidebarPanel shell slot as a mail-client inbox: a resizable message list beside the navigation over the full window height, with the selected message read in the content area.",
96
96
  });
97
97
 
98
- // Section "Primitives" — clickbar-collapsible weil parent ohne screen.
98
+ // Section "Primitives" — click-to-collapse because the parent has no screen.
99
99
  //
100
- // Jeder Eintrag traegt ein Icon: auf Icon-Breite ist es das Einzige, was
101
- // von ihm uebrig bleibt. Ohne Icon steht dort nur ein Punkt, und eine Rail
102
- // aus gleichen Punkten sagt nicht, wo man hinklickt.
100
+ // Every entry carries an icon: at icon width it is the only thing that
101
+ // remains of it. Without an icon only a dot shows there, and a rail
102
+ // of identical dots does not say where to click.
103
103
  r.nav({ id: "primitives", label: "showcase-demos:nav.primitives", icon: "layers", order: 10 });
104
104
  r.nav({
105
105
  id: "demo-layout",
@@ -1,5 +1,5 @@
1
- // Demos-Feature i18n-Bundle. Nur die Screen-Titles für die
2
- // Top-Action-Bars der Demo-Pages.
1
+ // Demos feature i18n bundle. Only the screen titles for the
2
+ // top action bars of the demo pages.
3
3
 
4
4
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
5
5
 
@@ -1,6 +1,6 @@
1
- // Shared Page-Layout für die Demo-Custom-Screens. Kein Framework-
2
- // Konzept — reines Sample-Layout, das die Top-Action-Bar Convention
3
- // (h-12, bg-muted/30, border-b) konsistent mit Form/Liste hält.
1
+ // Shared page layout for the demo custom screens. Not a framework
2
+ // concept — pure sample layout that keeps the top action bar convention
3
+ // (h-12, bg-muted/30, border-b) consistent with form/list.
4
4
 
5
5
  import { usePrimitives } from "@cosmicdrift/kumiko-renderer";
6
6
  import type { ReactNode } from "react";
@@ -32,8 +32,8 @@ export function DemoPage({
32
32
  );
33
33
  }
34
34
 
35
- // Section innerhalb einer Demo-Page: Card-Primitive (Standard-Chrome). Samples
36
- // sind Copy-Vorlage für Agenten → dieselbe Card wie überall, kein Sonder-Layout.
35
+ // Section within a demo page: Card primitive (standard chrome). Samples
36
+ // are a copy template for agents → the same card as everywhere, no special layout.
37
37
  export function DemoSection({
38
38
  title,
39
39
  children,
@@ -1,7 +1,7 @@
1
- // Demos-Feature — Web-Plattform-Plugin. ClientFeatureDefinition mit
2
- // den React-DOM-Components für die custom-Screens. createKumikoApp
3
- // merged das in den CustomScreens-Context, KumikoScreen schaut darin
4
- // nach wenn ein Schema-Screen `type: "custom"` hat.
1
+ // Demos feature — web platform plugin. ClientFeatureDefinition with
2
+ // the React DOM components for the custom screens. createKumikoApp
3
+ // merges that into the CustomScreens context, KumikoScreen looks there
4
+ // when a schema screen has `type: "custom"`.
5
5
 
6
6
  import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
7
7
  import { demosTranslations } from "../i18n";
@@ -62,7 +62,7 @@ export function DialogDemo(): ReactNode {
62
62
  </DemoSection>
63
63
 
64
64
  <DemoSection title="Lightbox">
65
- {/* kumiko-lint-ignore primitives-discipline clickable image thumbnail (Lightbox-Trigger) — kein Text-Button, <Button> kann kein Full-Bleed-<img> wrappen */}
65
+ {/* kumiko-lint-ignore primitives-discipline clickable image thumbnail (lightbox trigger) — not a text button, <Button> cannot wrap a full-bleed <img> */}
66
66
  <button
67
67
  type="button"
68
68
  onClick={() => setLightboxOpen(true)}
@@ -2,9 +2,9 @@ import { usePrimitives } from "@cosmicdrift/kumiko-renderer";
2
2
  import { type ReactNode, useMemo, useState } from "react";
3
3
  import { DemoPage, DemoSection } from "../components/page";
4
4
 
5
- // Combobox-Demo-Daten: 3 Items mit unterschiedlichen Anfangsbuchstaben.
6
- // Tippt der User "A", muss "API" als einzige übrig bleiben — Regression-
7
- // Surface für den Bug "Suche filtert alles weg".
5
+ // Combobox demo data: 3 items with different initial letters.
6
+ // If the user types "A", only "API" must remain — regression
7
+ // surface for the bug "search filters everything away".
8
8
  const COMBOBOX_OPTIONS = [
9
9
  { value: "api", label: "API" },
10
10
  { value: "backend", label: "Backend" },
@@ -27,11 +27,11 @@ export function InputsDemo(): ReactNode {
27
27
  const [comboMultiLocal, setComboMultiLocal] = useState<readonly string[]>([]);
28
28
  const [comboSingleRemote, setComboSingleRemote] = useState("");
29
29
  const [comboMultiRemote, setComboMultiRemote] = useState<readonly string[]>([]);
30
- // Remote-Mode-Simulation: Caller erhält den Suchbegriff via
31
- // onSearchChange und filtert die options selbst — Combobox bekommt
32
- // "shouldFilter=false"-Mode (cmdk filtert nicht client-side, Caller
33
- // ist authoritative für Sichtbarkeit). Production-Setup würde den
34
- // Suchbegriff an den Server schicken, hier filtern wir im Memory.
30
+ // Remote-mode simulation: the caller receives the search term via
31
+ // onSearchChange and filters the options itself — Combobox gets
32
+ // "shouldFilter=false" mode (cmdk does not filter client-side, the caller
33
+ // is authoritative for visibility). A production setup would send the
34
+ // search term to the server, here we filter in memory.
35
35
  const [remoteQ, setRemoteQ] = useState("");
36
36
  const remoteOptions = useMemo(() => {
37
37
  if (remoteQ === "") return COMBOBOX_OPTIONS;
@@ -1,9 +1,9 @@
1
- // Layout-Demo: Slot-Visualisierung. Pro Primitive ein Mini-Diagramm
2
- // der Boxen + Slot-Namen drin, plus ein Code-Snippet darunter das
3
- // zeigt wie der Slot aus dem Caller heraus angesprochen wird.
1
+ // Layout demo: slot visualization. One mini diagram per primitive
2
+ // of the boxes + slot names inside, plus a code snippet below that
3
+ // shows how the slot is addressed from the caller.
4
4
  //
5
- // Die Skizzen sind absichtlich Sample-Code mit raw <div> + Tailwind —
6
- // hier geht's um ein Bild, nicht um die Primitives selbst zu zeigen.
5
+ // The sketches are deliberately sample code with raw <div> + Tailwind —
6
+ // the point here is a picture, not showing the primitives themselves.
7
7
 
8
8
  import type { ReactNode } from "react";
9
9
  import { DemoPage, DemoSection } from "../components/page";
@@ -3,9 +3,9 @@ import { useToast } from "@cosmicdrift/kumiko-renderer/web";
3
3
  import { type ReactNode, useState } from "react";
4
4
  import { DemoPage, DemoSection } from "../components/page";
5
5
 
6
- // Toast-Demo. useToast() ist die einzige Public-API — der ToastProvider
7
- // ist im createKumikoApp gemountet, jeder Component innerhalb darf
8
- // toasts pushen ohne sich um State/Mounting zu kümmern.
6
+ // Toast demo. useToast() is the only public API — the ToastProvider
7
+ // is mounted in createKumikoApp, every component inside may
8
+ // push toasts without caring about state/mounting.
9
9
 
10
10
  export function ToastDemo(): ReactNode {
11
11
  const { toast } = useToast();
@@ -1,11 +1,11 @@
1
- // Items-Feature — Server-Side. defineFeature() registriert die Entity,
2
- // die Standard-CRUD-Handler und die Schema-Items aus schema.ts. KEIN
3
- // Custom-Server-Code (keine Hooks/Projections); das Feature ist
4
- // bewusst minimal und zeigt den "kitchen-sink Entity"-Pfad ohne
5
- // Domain-Logik.
1
+ // Items feature — server side. defineFeature() registers the entity,
2
+ // the standard CRUD handlers and the schema items from schema.ts. NO
3
+ // custom server code (no hooks/projections); the feature is
4
+ // deliberately minimal and shows the "kitchen-sink entity" path without
5
+ // domain logic.
6
6
  //
7
- // Beidseitig benutzte Schema-Definitionen leben in schema.ts. Server
8
- // hängt hier die Handler dran und ruft r.screen/r.nav.
7
+ // Schema definitions used on both sides live in schema.ts. The server
8
+ // attaches the handlers here and calls r.screen/r.nav.
9
9
 
10
10
  import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
11
11
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
@@ -65,7 +65,7 @@ export const itemsFeature = defineFeature("showcase", (r) => {
65
65
  r.screen(itemActiveScreen);
66
66
  r.screen(itemQuickAddScreen);
67
67
 
68
- // Section "Data" — clickbar zum Auf/Zuklappen weil parent ohne screen.
68
+ // Section "Data" — click to expand/collapse because the parent has no screen.
69
69
  r.nav({ id: "data", label: "showcase:nav.data", icon: "table", order: 100 });
70
70
  r.nav({
71
71
  id: "item-list",
@@ -1,6 +1,6 @@
1
- // Items-Feature i18n-Bundle. Convention: feature-prefix per
2
- // `showcase:` + `entity:item:field:<name>` für Field-Labels. Plus
3
- // die zwei Nav-Labels die in feature.ts referenziert werden.
1
+ // Items feature i18n bundle. Convention: feature prefix per
2
+ // `showcase:` + `entity:item:field:<name>` for field labels. Plus
3
+ // the two nav labels referenced in feature.ts.
4
4
 
5
5
  import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
6
6
 
@@ -1,6 +1,6 @@
1
- // Public-Surface des Items-Features. Server importiert `itemsFeature`,
2
- // Web-Client importiert `itemsClient`. schema/ ist intern, wird nicht
3
- // re-exported — nur feature.ts und web/index.ts dürfen darauf zugreifen.
1
+ // Public surface of the items feature. The server imports `itemsFeature`,
2
+ // the web client imports `itemsClient`. schema/ is internal, not
3
+ // re-exported — only feature.ts and web/index.ts may access it.
4
4
 
5
5
  export { itemsFeature } from "./feature";
6
6
  export { itemsClient } from "./web";
@@ -1,7 +1,7 @@
1
- // Re-exports — eine Datei pro Entity, Index sammelt sie. So kann
2
- // das Feature später weitere Entities (z.B. tag.ts, comment.ts)
3
- // hinzufügen ohne dass feature.ts oder web/index.ts ihre Imports
4
- // ändern müssen.
1
+ // Re-exports — one file per entity, the index collects them. That way
2
+ // the feature can later add further entities (e.g. tag.ts, comment.ts)
3
+ // without feature.ts or web/index.ts having to change
4
+ // their imports.
5
5
 
6
6
  export {
7
7
  itemActiveScreen,
@@ -69,8 +69,8 @@ export const itemEditScreen: EntityEditScreenDefinition = {
69
69
  title: "References (Tier 2.7e Remote-Combobox-Demo)",
70
70
  columns: 1,
71
71
  fields: [
72
- // Single + Remote — Bug-Test-Surface 1: Click auf Dropdown-Item
73
- // muss onChange feuern (selektiert das Item, schließt das Popup).
72
+ // Single + remote — bug test surface 1: click on a dropdown item
73
+ // must fire onChange (selects the item, closes the popup).
74
74
  "parentId",
75
75
  // Multi + Remote — Bug-Test-Surface 2: Tippen filtert die Liste
76
76
  // serverseitig. Mit ~200 seed-Items echte Search-Last.
@@ -110,18 +110,18 @@ export const itemListScreen: EntityListScreenDefinition = {
110
110
  // auf item:list (limit:200), zeigt parentId als parent.title.
111
111
  { field: "parentId", hideOnNarrow: true },
112
112
  ],
113
- // Server-side Pagination Demo — Showcase seedet ~200 items, der
114
- // Pager hat 4 Seiten zum Durchklicken bei pageSize: 50.
113
+ // Server-side pagination demo — the showcase seeds ~200 items, the
114
+ // pager has 4 pages to click through at pageSize: 50.
115
115
  pagination: "pages",
116
116
  pageSize: 50,
117
117
  defaultSort: { field: "title", dir: "asc" },
118
118
  searchable: true,
119
- // RowActions-Demo. Default-Payload ist `{ id: row.id }` — reicht für
120
- // delete. Confirm-Dialog wegen style="danger" automatisch.
121
- // Tier 2.7e-1 zeigt "navigate"-kind: ein zweiter Action-Button der
122
- // statt Server-Call zu einem actionForm springt + die row.id als
123
- // URL-Param übergibt (das actionForm liest sie via searchParams als
124
- // initial value für ein title-Feld).
119
+ // RowActions demo. The default payload is `{ id: row.id }` — enough for
120
+ // delete. Confirm dialog automatically because of style="danger".
121
+ // Tier 2.7e-1 shows the "navigate" kind: a second action button that
122
+ // jumps to an actionForm instead of making a server call + passes row.id as a
123
+ // URL param (the actionForm reads it via searchParams as an
124
+ // initial value for a title field).
125
125
  rowActions: [
126
126
  { kind: "navigate", id: "edit", label: "showcase:actions.edit", screen: "item-edit" },
127
127
  {
@@ -129,7 +129,7 @@ export const itemListScreen: EntityListScreenDefinition = {
129
129
  id: "duplicate",
130
130
  label: "showcase:actions.duplicate",
131
131
  screen: "item-quick-add",
132
- // DSL-Limit: kein "Copy of"-Prefix darstellbar → server-side im Handler lösen.
132
+ // DSL limit: no "Copy of" prefix expressible → solve server-side in the handler.
133
133
  params: { pick: ["title", "priority"] },
134
134
  },
135
135
  {
@@ -159,7 +159,7 @@ export const itemFeedScreen: EntityListScreenDefinition = {
159
159
  "dueDate",
160
160
  ],
161
161
  pagination: "infinite",
162
- pageSize: 30, // kleinere Pages damit Scroll-Effekt häufiger triggert
162
+ pageSize: 30, // smaller pages so the scroll effect triggers more often
163
163
  defaultSort: { field: "title", dir: "asc" },
164
164
  searchable: true,
165
165
  rowActions: [
@@ -167,10 +167,10 @@ export const itemFeedScreen: EntityListScreenDefinition = {
167
167
  ],
168
168
  };
169
169
 
170
- // Tier 2.7c Demo — Screen-Level Filter. Selbe Entity, gleicher Query-
171
- // Handler wie itemListScreen, aber mit fixem WHERE: nur Items mit
172
- // status="active". Klassisches Bucketing-Pattern (z.B. "Active Tasks"
173
- // vs "All Tasks") ohne Custom-Page schreiben zu müssen.
170
+ // Tier 2.7c demo — screen-level filter. Same entity, same query
171
+ // handler as itemListScreen, but with a fixed WHERE: only items with
172
+ // status="active". Classic bucketing pattern (e.g. "Active Tasks"
173
+ // vs "All Tasks") without having to write a custom page.
174
174
  export const itemActiveScreen: EntityListScreenDefinition = {
175
175
  id: "item-active",
176
176
  type: "entityList",
@@ -186,18 +186,18 @@ export const itemActiveScreen: EntityListScreenDefinition = {
186
186
  ],
187
187
  };
188
188
 
189
- // Tier 2.7d Demo — actionForm Screen-Typ. Non-CRUD Write-Handler-
190
- // driven Form, hier mit dem existing item:create-Handler aber
191
- // reduzierter Field-Auswahl (nur title + priority). Demonstriert dass
192
- // eine actionForm:
193
- // - keine Entity-Reference braucht (fields sind inline)
194
- // - einen beliebigen Write-Handler-QN triggert (hier item:create,
195
- // üblich wäre auch sowas wie item:archive-batch oder
196
- // invoice:approve mit dedizierten Handlern)
197
- // - nach Submit redirecten kann (hier zur Liste)
189
+ // Tier 2.7d demo — actionForm screen type. A non-CRUD write-handler-
190
+ // driven form, here with the existing item:create handler but a
191
+ // reduced field selection (only title + priority). Demonstrates that
192
+ // an actionForm:
193
+ // - needs no entity reference (fields are inline)
194
+ // - triggers any write handler QN (here item:create,
195
+ // something like item:archive-batch or
196
+ // invoice:approve with dedicated handlers would be typical)
197
+ // - can redirect after submit (here to the list)
198
198
  //
199
- // Default-Werte greifen für nicht-Form-Felder: status=draft, isDone=
200
- // false, priority kommt aus dem Form, notes/dueDate optional.
199
+ // Default values apply for non-form fields: status=draft, isDone=
200
+ // false, priority comes from the form, notes/dueDate optional.
201
201
  export const itemQuickAddScreen: ActionFormScreenDefinition = {
202
202
  id: "item-quick-add",
203
203
  type: "actionForm",
@@ -1,10 +1,10 @@
1
- // Items-Feature — Web-Plattform-Plugin. ClientFeatureDefinition mit
2
- // Translations. Items hat heute keine Custom-Screen-Components
3
- // (rendert über Standard-RenderEdit/RenderList), entsprechend keine
4
- // `components`-Map.
1
+ // Items feature — web platform plugin. ClientFeatureDefinition with
2
+ // translations. Items currently has no custom-screen components
3
+ // (renders via the standard RenderEdit/RenderList), accordingly no
4
+ // `components` map.
5
5
  //
6
- // Native-Plattform würde parallel dazu in features/items/native/
7
- // liegen — translations werden geteilt, components/UI nicht.
6
+ // A native platform would live alongside it in features/items/native/
7
+ // — translations are shared, components/UI are not.
8
8
 
9
9
  import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
10
10
  import { itemsTranslations } from "../i18n";
@@ -5,9 +5,9 @@ import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
5
5
 
6
6
  import { demoEntity } from "../features/demo/feature";
7
7
 
8
- // Gibt der List-View echte Rows mit Status-/Flag-Vielfalt. price (money)
9
- // bleibt leer — der Money-Input zeigt sich im Edit-Screen, im Seed lassen wir
10
- // ihn weg um nicht von der money-Payload-Form abzuhängen.
8
+ // Gives the list view real rows with status/flag variety. price (money)
9
+ // stays empty — the money input shows in the edit screen, in the seed we leave
10
+ // it out to avoid depending on the money payload shape.
11
11
  const STATUSES = ["draft", "review", "published", "archived"] as const;
12
12
 
13
13
  // Fixed across boots (unlike the framework-minted ids for every other seed
@@ -39,8 +39,8 @@ await runDevApp({
39
39
  aiSettingsFeature,
40
40
  workboardFeature,
41
41
  ],
42
- // Aktiviert die Upload-Routes (/api/files) + ctx.services.files für den Avatar-
43
- // Stresstest. In-Memory reicht für die Demo (nicht-persistent).
42
+ // Enables the upload routes (/api/files) + ctx.services.files for the avatar
43
+ // stress test. In-memory is enough for the demo (non-persistent).
44
44
  files: { storageProvider: createInMemoryFileProvider() },
45
45
  port: Number.parseInt(process.env["PORT"] ?? "4180", 10),
46
46
  clientEntry: "./src/app/client.tsx",
@@ -18,10 +18,10 @@ export function AppShell({
18
18
  children: ReactNode;
19
19
  schema: AppSchema;
20
20
  }): ReactNode {
21
- // Content-Panel-Switch (= P4-Muster, hier demo-lokal): ist ein target in
22
- // der URL aktiv (Klick auf eine Content-Seite oder das „+"), füllt das
23
- // EditorPanel den Main-Bereich; sonst der normale Screen. „Nichts
24
- // selektiert" → children (kein „Screen not found"-Regress).
21
+ // Content panel switch (= P4 pattern, demo-local): if a target is active in
22
+ // the URL (click on a content page or the "+"), the EditorPanel fills
23
+ // the main area; otherwise the normal screen. "Nothing
24
+ // selected" → children (no "Screen not found" regression).
25
25
  const nav = useNav();
26
26
  const resolvers = useResolvers();
27
27
  const activeTarget = parseTargetFromSearchParams(nav.searchParams);
@@ -1,9 +1,9 @@
1
- // Client-Seite des Content-Stresstests: der navProvider hängt sich an den
2
- // statischen `content`-Nav-Knoten (QN "content:nav:content"), lädt die Seiten
3
- // per /api/query und emittiert sie als Tree-Leaves. navEntities ["page"]
4
- // abonniert die Live-Events → nach einem Create erscheint die neue Seite
5
- // sofort im Sidebar-Tree. Der content:edit-Resolver rendert das Anlege-
6
- // Formular (leeres target) bzw. die Detail-Ansicht (target mit id).
1
+ // Client side of the content stress test: the navProvider attaches to the
2
+ // static `content` nav node (QN "content:nav:content"), loads the pages
3
+ // via /api/query and emits them as tree leaves. navEntities ["page"]
4
+ // subscribes to the live events → after a create the new page appears
5
+ // immediately in the sidebar tree. The content:edit resolver renders the create
6
+ // form (empty target) or the detail view (target with id).
7
7
 
8
8
  import type {
9
9
  TargetRef,
@@ -1,7 +1,7 @@
1
- // Config-Stresstest (server). Die shadcn-Referenz-Designs NICHT handgebaut,
2
- // sondern 1:1 aus dem Schema erzeugt — um zu sehen was die Auto-UI trägt und
3
- // wo sie an Grenzen stößt. Erster Fall: "Shipping Address" (flache Form,
4
- // 2-Felder-Reihen, Custom-Submit-Label).
1
+ // Config stress test (server). The shadcn reference designs are NOT hand-built
2
+ // but generated 1:1 from the schema — to see what the auto-UI supports and
3
+ // where it hits limits. First case: "Shipping Address" (flat form,
4
+ // 2-field rows, custom submit label).
5
5
 
6
6
  import {
7
7
  createBooleanField,
@@ -83,10 +83,10 @@ export const examplesFeature = defineFeature("examples", (r) => {
83
83
  r.translations({ keys: EXAMPLES_I18N });
84
84
  r.crud("shipping", shippingEntity, editFormOnly);
85
85
 
86
- // EINE titellose Section: Card-Titel + Subtitle (aus i18n) tragen den
87
- // Kontext, die Felder fließen direkt darunter. street/apt/saveAsDefault
88
- // spannen beide Spalten (volle Breite), city/state + zip/country teilen
89
- // sich je eine Reihe.
86
+ // ONE untitled section: card title + subtitle (from i18n) carry the
87
+ // context, the fields flow directly below. street/apt/saveAsDefault
88
+ // span both columns (full width), city/state + zip/country share
89
+ // one row each.
90
90
  r.screen({
91
91
  id: "shipping-edit",
92
92
  type: "entityEdit",
@@ -1,17 +1,17 @@
1
- // Gallery-Feature (server). Eine custom-Screen, die die Foundations
2
- // (Colors/Typography/Radius/Elevation/Spacing) + atomare Components
3
- // (Buttons, Cards) zeigt — das was die Entity-Auto-Screens nicht abdecken.
4
- // React-Component client-seitig via clientFeatures.components zugeordnet.
1
+ // Gallery feature (server). A custom screen showing the foundations
2
+ // (colors/typography/radius/elevation/spacing) + atomic components
3
+ // (buttons, cards) — what the entity auto-screens do not cover.
4
+ // React component assigned client-side via clientFeatures.components.
5
5
  //
6
- // Eigener FeatureName (nicht "styleguide") — zwei defineFeature mit gleichem
7
- // Namen würden in createRegistry werfen.
6
+ // Own FeatureName (not "styleguide") — two defineFeature calls with the same
7
+ // name would throw in createRegistry.
8
8
 
9
9
  import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
10
10
  import type { LocalizedString } from "../shared-i18n";
11
11
 
12
- // Server-Pendant zu den Nav-Labels — Boot-Validator braucht screen:gallery.title
13
- // serverseitig registriert, auch wenn die custom-Screen selbst keinen
14
- // gerenderten Titel aus i18n zieht.
12
+ // Server counterpart to the nav labels — the boot validator needs screen:gallery.title
13
+ // registered server-side, even if the custom screen itself does not pull a
14
+ // rendered title from i18n.
15
15
  const GALLERY_I18N: Readonly<Record<string, LocalizedString>> = {
16
16
  "screen:gallery.title": { de: "Foundations & Components", en: "Foundations & Components" },
17
17
  "gallery:nav.styleguide": { de: "Styleguide", en: "Styleguide" },
@@ -7,8 +7,8 @@ import {
7
7
  import { Check, ChevronDown, Search, X } from "lucide-react";
8
8
  import type { ReactNode } from "react";
9
9
 
10
- // Literal Tailwind-Klassen (kein `bg-${token}`) — der v4-Scanner generiert nur
11
- // Klassen die wörtlich im Source stehen.
10
+ // Literal Tailwind classes (no `bg-${token}`) — the v4 scanner only generates
11
+ // classes that appear literally in the source.
12
12
  const SWATCHES: ReadonlyArray<readonly [string, string]> = [
13
13
  ["background", "bg-background"],
14
14
  ["foreground", "bg-foreground"],
@@ -114,7 +114,7 @@ interface Dividend {
114
114
  readonly amount: string;
115
115
  readonly bars: readonly Bar[];
116
116
  }
117
- // kumiko-lint-ignore no-logic-in-views demo: inline Chart-Daten-Prep für die Gallery-Fixtures (Lesbarkeit des Demos > Extraktion)
117
+ // kumiko-lint-ignore no-logic-in-views demo: inline chart data prep for the gallery fixtures (demo readability > extraction)
118
118
  function bars(heights: readonly [number, number, number, number]): readonly Bar[] {
119
119
  return heights.map((h, i) => ({ k: "abcd"[i] as string, h }));
120
120
  }
@@ -164,7 +164,7 @@ function Badge({ children }: { children: ReactNode }): ReactNode {
164
164
  );
165
165
  }
166
166
 
167
- // Select-Attrappe (shadcn-Select-Trigger-Look) für statische Showcase-Blöcke.
167
+ // Select stand-in (shadcn select trigger look) for static showcase blocks.
168
168
  function SelectStub({ value }: { value: string }): ReactNode {
169
169
  return (
170
170
  <div className="border-input bg-background flex h-9 items-center justify-between rounded-md border px-3 text-sm">
@@ -359,7 +359,7 @@ export function Gallery(): ReactNode {
359
359
  <div className="flex items-center gap-3 p-2">
360
360
  <div className="relative min-w-0 flex-1">
361
361
  <Search className="text-muted-foreground absolute left-3 top-1/2 size-4 -translate-y-1/2" />
362
- {/* kumiko-lint-ignore primitives-discipline readOnly search-pill visual (rounded-full mit inset Icon) — Muster-Demo, kein Formularfeld */}
362
+ {/* kumiko-lint-ignore primitives-discipline readOnly search-pill visual (rounded-full with inset icon) — pattern demo, not a form field */}
363
363
  <input
364
364
  className="bg-muted/50 placeholder:text-muted-foreground focus-visible:ring-ring h-10 w-full rounded-full border-none pl-9 pr-4 text-sm outline-none focus-visible:ring-2"
365
365
  placeholder="Search holdings or tickers…"
@@ -744,10 +744,10 @@ export function Gallery(): ReactNode {
744
744
  </Block>
745
745
 
746
746
  <Block id="tags" title="Tags — bundled-feature layout">
747
- {/* ponytail: faithful Layout-Nachbau des TagSection (tags/web) mit den
748
- echten Primitiven + statischen Daten — die Live-Version hängt am
749
- Dispatcher. Verifiziert die Inline-Create-Row (Input wächst,
750
- Add-Button bündig daneben). */}
747
+ {/* ponytail: faithful layout replica of the TagSection (tags/web) with the
748
+ real primitives + static data — the live version hangs off the
749
+ dispatcher. Verifies the inline create row (input grows,
750
+ add button flush beside it). */}
751
751
  <div className="flex max-w-md flex-col gap-4">
752
752
  <Field id="tg-select" label="Tags">
753
753
  <Input
@@ -778,9 +778,9 @@ export function Gallery(): ReactNode {
778
778
  </Block>
779
779
 
780
780
  <Block id="nav" title="Navigation">
781
- {/* ponytail: statischer Nachbau des Nav-Standards — die LIVE-Nav ist
782
- die Sidebar links (NavTree), hier isoliert für die Doku. */}
783
- {/* kumiko-lint-ignore primitives-discipline nav-surface demo (Navigations-Fläche, kein Card) */}
781
+ {/* ponytail: static replica of the nav standard — the LIVE nav is
782
+ the sidebar on the left (NavTree), isolated here for the docs. */}
783
+ {/* kumiko-lint-ignore primitives-discipline nav-surface demo (navigation surface, not a card) */}
784
784
  <div className="bg-card w-60 rounded-lg border p-3 text-sm shadow-sm">
785
785
  <div className="text-muted-foreground/70 px-2 pb-1 pt-2 text-[11px] font-medium uppercase tracking-wider">
786
786
  Workspace
@@ -67,8 +67,8 @@ const LOAN_MARKERS = [
67
67
  const SENDERS = ["William Smith", "Alice Smith", "Bob Johnson", "Emily Davis"] as const;
68
68
  const SUBJECTS = ["Meeting Tomorrow", "Re: Project Update", "Weekend Plans", "Re: Budget"] as const;
69
69
 
70
- // Statische Demo-Inbox (18 Nachrichten) für die InfinityList-Demo — genug
71
- // Rows, um über pageSize=6 hinweg mehrere Seiten nachzuladen.
70
+ // Static demo inbox (18 messages) for the InfinityList demo — enough
71
+ // rows to load several pages beyond pageSize=6.
72
72
  const INBOX_MESSAGES = Array.from({ length: 18 }, (_, i) => ({
73
73
  id: `m${i + 1}`,
74
74
  // Cast is sound: `i % SENDERS.length` is always in [0, SENDERS.length) —
@@ -1,6 +1,6 @@
1
- // Demo-Komponente für den `custom`-Dashboard-Panel-Typ: zeigt, dass eine
2
- // eingehängte App-Komponente ihre Daten selbst holt und den aktuell
3
- // gewählten Screen-Filter-Wert über `filterParams` sieht (siehe
1
+ // Demo component for the `custom` dashboard panel type: shows that an
2
+ // attached app component fetches its data itself and sees the currently
3
+ // selected screen filter value via `filterParams` (see
4
4
  // DashboardFilterDefinition in feature.ts).
5
5
 
6
6
  import { type ExtensionSectionProps, useTranslation } from "@cosmicdrift/kumiko-renderer";
@@ -1,7 +1,7 @@
1
- // Demo-Komponente für das statische `icon`-Feld eines Dashboard-stat-Panels:
2
- // über dieselbe extensionSectionComponents-Registry wie custom-Panels
3
- // aufgelöst, ignoriert aber den Entity-/Filter-Kontext (ein reines Icon hat
4
- // keinen Bezug dazu).
1
+ // Demo component for the static `icon` field of a dashboard stat panel:
2
+ // resolved via the same extensionSectionComponents registry as custom panels,
3
+ // but ignores the entity/filter context (a plain icon has
4
+ // no relation to it).
5
5
 
6
6
  import type { ReactNode } from "react";
7
7
 
@@ -1,11 +1,11 @@
1
1
  // @runtime test
2
- // Playwright-Config für den ui-walkthrough-Durchstich. Startet den
3
- // echten dev-server als webServer-Fixture, genau wie `bun dev` — nur
4
- // auf dem Port aus samples/e2e/e2e-ports.ts, damit keine Dev-Session kollidiert.
2
+ // Playwright config for the ui-walkthrough run-through. Starts the
3
+ // real dev server as a webServer fixture, exactly like `bun dev` — only
4
+ // on the port from samples/e2e/e2e-ports.ts so no dev session collides.
5
5
  //
6
- // Der dev-server macht auf PORT-Env basierend das HTTP-Binding. Die
7
- // setupTestStack-Default ist ephemeral (fresh kumiko_test_<random> DB),
8
- // deshalb braucht's keine DB-Reset-Logik hier.
6
+ // The dev server does the HTTP binding based on the PORT env. The
7
+ // setupTestStack default is ephemeral (fresh kumiko_test_<random> DB),
8
+ // so no DB reset logic is needed here.
9
9
 
10
10
  import {
11
11
  defineAppE2eConfig,