Gesamte Mono-Repo des Baukastens (alle apps/clients, examples/tests und packages)
Bearbeiten | Blame | Historie | Raw

Baukasten — implementation roadmap

Master checklist for finishing the Baukasten feature. We tackle open items one at a time, each
with its own focused plan
. Status: [x] done · [~] in progress · [ ] open.

Done

  • [x] Monorepo: permissions, config-reader, api facade, config-ui picker, playground
  • [x] AUC "Baukasten" option (sourced in getProjectListData) + picker show/hide + responsive UI
  • [x] #1 Persist selected ordered references to MongoDB (baukastenConfigurations, load-order)
    PrepareSave → main save() → wholesale update; schema field present
    (wants an end-to-end round-trip test; optional "Save As"/"Template As" parity)
  • [x] A — Merge pipeline (N sources). Added LayoutConfigReaderService.readMergedBaukastenConfig(configurations)
    — additive; reuses the existing variadic merge(...) (top = base, bottom wins, no reversal);
    legacy merge / readMergedLayoutConfig untouched.
    (Optional: add a baukasten test-case folder under data/test/json and run npm run debug:json-merge.)

Runtime

  • [x] B. Merged-config endpoint. Additive baukasten branch in WebUIController.readLayoutConfig
    (webuiProject === "baukasten"BaukastenService.readConfigurations(refs)
    readMergedBaukastenConfig(...) → return); reuses the legacy layout.json route (no route
    change). ConfigurationManager.merge now surfaces baukastenConfigurations onto the merged
    config. customMailService: bottom-most defining entry wins, encoded, never raw.
  • [x] C. Client source + build. Buildable Vite source at baukasten-data\client_logic (copy of
    _logic_layout_1, retargeted: projectId "baukasten", outDir ../client, empty source body,
    code-splitting.ts brought in; the global SASS + global locales integrated into client_logic
    (src/style/global/, locales-global/) so it's self-contained — no _logic_global/_global
    siblings; dev-link override paths fixed). Reuses the
    tokenized webui-content serving (t/baukasten/). pnpm install && pnpm run build-prod there
    regenerates baukasten-data\client. (Dev links kept; build is the user's to run.)
  • [x] D. Serve the client. Additive baukasten branches in WebUIController: view serves
    clientDir/index.html when webuiProject === "baukasten"; getReadFilePath resolves
    /webui-content/{token}/t/baukasten/… assets under clientDir (with a traversal guard).
    Reuses the existing routes; path-only style/* + tokenWorker.js unchanged (per-customer).

Supporting

  • [x] E. Real configuration data (starter). Added a real 14243/public/layout1.json (root
    query:"#main"fv-layout recreating the layout_1 body regions + nested fv-webviewer
    slotted into iframe-content), registered via a 14243/fileinfo.json layout1 entry
    (existing base/secret/77001 stubs left untouched). Also closed a step-B gap: added a
    baukasten branch (+ null guard) to WebUIController.readLayoutStylings so config/styles.json
    returns a truthy {styles:[]} — the client's if (layout && styles) render guard now passes.
    Also fixed a theme-mode routing 404: the baukasten dropdown option is now global: true
    (getProjectListData), so webui_theme_mode is saved true and the client's config requests use
    the /webui/t/baukasten/config/... route (was 404-ing on the one-segment /webui/baukasten/...).
    Rationale: baukasten is global logic — the eventual replacement for both getThemePath and
    getModularSystemPath — only transitionally relocated to clientDir.
    (Full render is confirmed in G.)
  • [x] K. fv-layout styleability + layout_1 grid. Finished the generic fv-layout primitive
    (furnview-components): createNodeElement now applies the slot key (and data.class) as region
    classes and mirrors them onto part (so configs target regions via .content/::part(content));
    render parts the container; layout.component.sass gives baseline :host/.layout-container
    sizing + a --fv-layout-* CSS-custom-property API (house pattern). Resolves E's dead-data.class
    and shadow-DOM-fidelity flags. layout1.json now carries the responsive layout_1 grid in customCSS
    (re-homed from _logic_layout_1/layout.sass, regions placed by grid-area) + --fv-layout-height:100vh
    via styleVars. Component stays generic (each layout config supplies its own grid). (Needs a
    furnview-components + client rebuild — user's build.)
  • [x] L. Opt-in light-DOM scaffold (legacy compat). fv-layout.createRenderRoot now returns the
    element itself (light DOM) when the light-dom attribute is present, else shadow (default unchanged).
    In light DOM the region nodes become document-queryable descendants of #main, so legacy configs'
    areas (targeting region classes) resolve. Toggled by a new adapter config
    14243/public/layout1-lightdom-adapter.json (registered in fileinfo.json) that merges onto the base's
    fv-layout (by tag+index, root query:"body"): +properties adds light-dom, -modules drops
    the base's slotted webviewer (slots don't project in light DOM), +areas re-adds it as an
    .iframe-content area (resolves in both modes). layout1.json itself is untouched (standalone use
    stays shadow). Layer order: layout1layout1-lightdom-adapter → legacy content.
    (Needs furnview-components + client rebuild.)
  • [x] L2. Merge: graft a query-mismatched root (legacy compat). LayoutConfigReaderService.updateRoot
    no longer discards a layer whose root query differs from the base's (the old
    updateModuleOrArea bail at 445-446). When source.query is set and differs from the merged root's,
    it now grafts the whole source as an area of the base root
    (updateModuleAreaOrChildren(target, {areas:[source]}, "areas", "query", [])), so at render loadArea
    attaches its content to the element its query matches (#main → the fv-layout scaffold container,
    which exists by then because root modules load before root areas). Same/undefined root query →
    unchanged deep-merge, so legacy modular merging is unaffected. Repeated same-root layers merge into one
    grafted area. Resolves only in light-DOM mode (shadow hides #main). Closes L's open reconciliation
    item. (Server-only JS change — furnplan_web reload, no build.)
  • [x] F. isStoreMember via FurncloudCredential.StoreTree. Replaced the () => false stub in
    BaukastenService with an async resolver: loads the OWNER credential and returns whether the
    requesting customer number appears as a kdnr_dh in owner.StoreTree.Stores (confirmed shape:
    { Stores: [{ kdnr_dh, firma, … }] }, the same data CustomerController.getStoreTree/IStoreTree
    use). The baukasten API pre-awaits it per store-owner, so async/DB is fine; graceful when an owner
    has no StoreTree (→ false); public/private/self/owner/consumer access untouched.
    (Server-only JS — furnplan_web reload, no build.)
  • [x] M. Theme config loaded like layout 1. Added a baukasten branch to
    WebUIController.readThemeConfig: it loads theme.json from the configured clientDir
    (config/theme.json) and _.merges the config's webui_theme_config, returning the merged theme —
    the same merge/return as the legacy path, which getProjectPathName couldn't reach for the synthetic
    baukasten project (so it had been 500-ing). The client already applies it via the shared
    TemplateLoaderService (construction:initialize → fetch themeConfig:root color vars +
    template/config-id options), so no client change. (Server-only JS — furnplan_web reload.)
    (Follow-up implemented in M2. Later superseded for baukasten by T: the runtime theme now rides in
    layout.json via construction:initialize, and readThemeConfig is the AUC-editor source only.)
  • [x] M2. AUC theme editor for baukasten. Restructured article-url-configurator.ts
    onWebUIModeDropDownChanged so the themeConfig fetch + buildWebUIThemeConfig run once for every
    webui project incl. baukasten (removing the baukasten early-return / code duplication). Baukasten now
    shows the theme editor (#webUIThemeOptions), so webui_theme_config is UI-editable and round-trips
    via the existing getWebUIThemeConfigJson/prepareSave path; category filters stay modular-only.
    Together with M this gives baukasten full per-customer theming parity. (AUC rebuild — user's build.)
    (Per-layout theming was explored afterwards; initially shelved, later shipped — see T.)
  • [x] N. Move client_logic into the baukasten monorepo. Relocated the Vite client source into
    baukasten/apps/client (new apps/ workspace glob; package @dh-software/baukasten-client), registered
    in package.json + pnpm-workspace.yaml (added autoInstallPeers + the client's dev-link overrides,
    moved from the old client_logic/pnpm-workspace.yaml and depth-corrected for the monorepo root).
    vite.config.ts outDir builds directly into the served client dir
    (../../../baukasten-data/client = Config.furnview.baukasten.clientDir), so build:prod writes the
    client in place — no separate build-and-copy/deploy step. (User runs pnpm install at the monorepo
    root + pnpm --filter @dh-software/baukasten-client run build:prod, then deletes the old
    baukasten-data/client_logic.)
  • [x] O. fv-layout: omit <slot>s in light-DOM mode. layout.component.ts render() computes
    emitSlots = !this.hasAttribute("light-dom") and threads it through traverseDefinition into the static
    createNodeElement, which now appends the region <slot name=…> only when emitSlots is true. Shadow
    DOM unchanged; region classes + part still applied in both modes. (Needs a furnview-components +
    client rebuild — user's build.)
  • [x] P. Layout 2 support. Added 14243/public/layout2.json — recreates legacy layout_2 via fv-layout
    (top-left logo column, header, 3-part sidebar catalog-header/catalog-content/catalog-footer, and
    content with fv-webviewer slotted directly into .content + toolbar/price/logo overlays;
    3-col desktop grid collapsing to a stacked layout ≤980px) — plus layout2-lightdom-adapter.json (grafts
    the webviewer into .content with prepend, since layout_2 has no .iframe-content). Also renamed the
    layout_1 adapter lightdom-adapterlayout1-lightdom-adapter for symmetry; both registered in
    fileinfo.json. layout2.json's customCSS is a full faithful port of layout_2's layout.sass (all
    region rules, every --var with its default, the .no-logo/.no-catalog-header/… modifier variants,
    and all seven breakpoints). (Data only — furnplan_web reload. CSS pixel-tuning + real-config validation are Q.)
  • [x] P2. Folder restructure → baukasten/{lib, dist}. Consolidated the former sibling folders: the whole
    monorepo now lives under baukasten/lib/, and the runtime data (configurations/ + built client/) under
    baukasten/dist/. Updated furnview.js (configurationsDir/clientDirbaukasten\dist\…),
    lib/apps/client/vite.config.ts outDir../../../dist/client, and the lib/pnpm-workspace.yaml
    dev-link overrides (one level deeper). Path mentions in earlier entries refer to the pre-restructure
    layout — code is now under lib/, data under dist/ (e.g. baukasten-data/client
    baukasten/dist/client; baukasten/apps/clientbaukasten/lib/apps/client).
    furnplan_web's two
    file: deps re-pointed packages/*lib/packages/*. The pre-restructure content (old monorepo +
    baukasten-data/) was archived under baukasten/old/, now deleted after verification. (Done.)
  • [x] Q. Test real layout 1 & 2 configurations & fix bugs. Real layout_1 & layout_2 configs load and
    render correctly on the baukasten base (light-DOM adapter + merge graft, full UI). Verified working.
  • [x] R. fv-layout: rework the component CSS. User-owned — implementing + committing directly.
    Revisit the :host / .layout-container / .node styling, possibly dropping the inner
    .layout-container wrapper so the grid lives directly on the host (simpler tree, fewer wrappers).
  • [x] G. End-to-end verification — pick + order → save → reopen (restored) → open link → client loads,
    fetches merged config, renders. Verified. (Save-As parity broke out as G2 — decided: kept as-is.)
  • [x] G2. Save-As / Template-As parity — decided: keep as-is. Save-As/Template-As
    (onBtnSaveConfigurationAsClick / onBtnSaveTemplateAsClick) POST only the inner .configuration to
    UseCaseConfigurationController.create, which persists only {customerNo, externalConf, configuration, isTemplate, name} — so the top-level baukastenConfigurations (set by
    BaukastenConfigSelection.PrepareSave) is dropped. But the modular fields (modularLayout /
    modularLayoutRootConfigurations / modularLayoutLayoutConfigurations / modularStylings, written
    top-level by WebUiLayoutSelection.PrepareSave) are dropped the same way — so baukasten is
    consistent with the pre-existing modular Save-As, not a regression. Left unchanged. If ever fixed,
    fix both together: carry the top-level fields through the Save-As handlers → UseCaseConfigurationModel.create
    body → the server create template. (Normal Save works — it PUTs the whole openedConfiguration to update.)
  • [x] H. Packaging / release@dh-software/baukasten + @dh-software/baukasten-config-ui (+ types /
    config-reader / permissions) published to npm.furnco.de. Follow-ups that ride on the publish (do
    when needed): swap furnplan_web's two file: deps → published ^ ranges; commit + push the
    furncloud-models baukastenConfigurations schema edit and re-pin furnplan_web to it; mirror the
    furnplan_web/furncloud-models edits + the baukasten client/configs into the _furnview bundle.

Per-layout theme — SHIPPED

  • [x] T. Per-layout theme config. Implemented via the previously-preferred-but-shelved approach (3):
    the theme rides in layout.json and the client applies it. template.service (webui-core) now takes
    the theme from the construction:initialize event payload (the merged config/layout.json, which embeds
    layout.theme) instead of a separate themeConfig fetch, and WebUIController.readLayoutConfig's
    baukasten branch bakes per-customer overrides into it —
    layout.theme = _.merge(layout.theme, JSON.parse(configuration.webui_theme_config)), guarded inside
    if (layout)
    so it never derefs an undefined merge result (empty baukastenConfigurations / service
    not ready → readMergedBaukastenConfig returns undefined), with the JSON.parse in its own try/catch.
    readThemeConfig is now the AUC-editor's source only: its getConfiguration(req, false) moved inside
    a try/catch (fixes the earlier server crash on the no-a theme fetch) and it returns the raw
    layout.theme — the editor merges webui_theme_config client-side in buildWebUIThemeConfig. The empty
    fallback {colors:{},template:{}} is intentional (base theme defaults removed from the dist configs).
    Modular configs (no embedded theme) still fall back to the separate themeConfig fetch, so legacy
    theming is unaffected. Supersedes M's "client fetches themeConfig" note for baukasten.
    (webui-core template.service change = user's build/publish; server JS = furnplan_web reload.)

To do (suggested order)

Future / large

  • [ ] I. Baukasten "configurator" — tool/UI to generate & edit customer fileinfo.json + config
    JSONs (so DAs don't hand-edit files). Direction (concrete sub-tasks TBD together): extract & rework
    the necessary parts of the current AUC into separate packages — consumed by the AUC itself for now —
    that the Baukasten configurator then reuses to configure the existing AUC settings from the Baukasten UI,
    cleaned up to be understandable by an end-user.
  • [ ] J. Retire the old DB-backed 3-layer system once Baukasten fully replaces it (migration/cleanup).
  • [ ] restructure furnview-components into:
    1. legacy-components (components that have been entirely replaced by others)
    2. furnview-components (current components with styleVars and no dh-components internals)
    3. baukasten-components (prefix bk-, fv-components that are reworked to use dh-components and no longer support stylevars, styled using material design 3)
  • [ ] S. Revisit isStoreMember after the global store-system rework. The current resolver reads
    FurncloudCredential.StoreTree.Stores[].kdnr_dh; once the planned global rework of the
    store/membership model lands, re-align it to the new shape/semantics.