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.)

To do (suggested order)

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.)
  • [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 and shelved — see T under "Shelved / parked".)
  • [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.
  • [ ] R. fv-layout: rework the component CSS. 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.)
  • [ ] H. Packaging / release — publish @dh-software/baukasten + @dh-software/baukasten-config-ui
    to npm.furnco.de (replace the file: deps); propagate the furncloud-models schema change;
    mirror all furnplan_web/furncloud-models edits into the released _furnview bundle.

Future / large

  • [ ] I. Baukasten "configurator" — tool/UI to generate & edit customer fileinfo.json + config
    JSONs (so DAs don't hand-edit files).
  • [ ] J. Retire the old DB-backed 3-layer system once Baukasten fully replaces it (migration/cleanup).
  • [ ] 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.

Shelved / parked

  • [ ] T. Per-layout theme config (SHELVED). The theme schema (theme.json) was per-layout historically
    (bin_layout_1/config vs bin_layout_2/config), but baukasten has one shared client folder, so M's
    shared clientDir/config/theme.json can't serve both. No easy, self-contained approach was found, so
    it's parked. Interim: M stands — runtime + AUC editor both use the single shared theme.json, which
    is fine while layout_1/layout_2 themes are effectively identical (they are today); revisit when they truly
    diverge, or fold into N (moving client_logic into the monorepo may make a client-side approach
    self-contained). Approaches considered & rejected: (1) readThemeConfig re-reads the base config's
    theme — fragile config re-read + base-first assumption; (2) full merge in readThemeConfig + shared
    helper + readLayoutConfig strip + AUC ?a=<id> — too many changes; (3) theme rides in layout.json,
    client applies it — cleanest, but spreads across two published webui-core packages (webui-api:
    event/events.ts, service/template.service.ts; webui-configuration-parser:
    types/construction.types.ts, service/construction.service.ts) + a webui_theme_config bake-in in
    readLayoutConfig, needing a webui-core build/publish + client rebuild. Key facts for the revisit: the
    merge preserves an embedded top-level theme; getConfiguration needs ?a= (the AUC theme fetch lacks
    it); the AUC editor merges webui_theme_config client-side while the runtime does it server-side;
    client_logic consumes webui-core as versioned deps.