ADR: pivot libreshop/shop from runtime image to reference template #10

Open
opened 2026-05-04 19:42:16 +02:00 by libretech · 0 comments
Owner

ADR — Pivot libreshop/shop from runtime image to reference template

Status

Proposed (2026-05-04). Awaiting acceptance + supersedes prior epic #2.

Context

libreshop/shop originated as the white-label Nuxt 3 frontend behind muellerprints-paperwork.com and was planned as a runtime-extendable base image for adapters (with mp being the first adapter). The plan was:

  • libreshop/shop ships brand-neutral, deployable as-is for demos
  • Adapters extend via Nuxt layers (extends: mechanism), Docker FROM libreshop/shop:vX
  • An "override surface" would be defined and semver-protected
  • Tailwind config, composables, components would all be layerable

A feasibility analysis (ref: notebook in mp/dummy/ planning, 2026-05-04) revealed:

  1. 27 files in libreshop/shop hardcode MUELLERPRINTS branding, Stuttgart address, Inhaber email, paperwork-logo
  2. Product schema is notebook-specificProductCover.binding, ProductPages, ProductRuling, ProductPattern types and their Strapi backing tables assume a notebook product. Generalising to a generic "ProductAttribute" requires substantial refactor.
  3. Composables hardcode contentusePageContent.ts (287 lines) contains literal MP legal/contact text that all 11 page files import directly. useProductContent.ts (369 lines) hardcodes notebook feature narratives ("Klassische Fadenheftung", "VIVUS 89 Papier", "FSC® C018175") that would need to move to per-adapter composables.
  4. Nuxt layers don't merge tailwind config or runtimeConfig defaults automatically — adapters would need explicit factory pattern + .env pre-baking
  5. The override surface would need semver discipline — every component rename, every slot signature change, every frontmatter field rename = breaking major. For a 1-adapter use case (mp), this is heavy maintenance.

The mp adapter wants full freedom to add a Druckerei section, an Über uns area, and brand-specific content depth without negotiating upstream.

Decision

Pivot libreshop/shop from "runtime base image" to reference template / starter:

  • libreshop/shop stops shipping a deployable image at the next major release. The repo retains the source as a complete worked example.
  • README is rewritten as a "copy this and modify" guide, not "depend on this".
  • The current production consumer (libretech/mp) forks the source into its own tree (mp/shop/) and owns it from that point forward.
  • Future adapters do the same: degit libreshop/shop my-shop, then customize freely.

What libreshop/shop becomes:

  • A curated public reference for "what a libretech-style Nuxt+Strapi shop looks like"
  • Documentation: README explains the architecture (Nuxt SSR, Strapi v4 CMS, PayPal, mail/pdf services) so newcomers understand the moving parts before they copy
  • Optionally: shared TypeScript types / composables published as a small npm package (@libreshop/types, @libreshop/composables) — only if multiple consumers emerge and ask for it. Default: no.

What libreshop/shop stops being:

  • A registry image consumed by mp's compose.yml
  • A semver-stable override surface
  • A multi-tenant runtime

Consequences

Pros:

  • mp gets full ownership and freedom — no upstream coordination
  • libreshop maintainer (us) drops "support contract" obligation toward adapters
  • Code is easier to evolve without breaking changes against an unknown universe of adapters
  • The reference value is preserved — anyone wanting a libretech-flavoured shop has working code to start from

Cons:

  • Future fork divergence: bug fixes in libreshop/shop don't reach mp automatically. Consumers must manually port. Acceptable cost — we have only 1 consumer (mp) and bug-fix cherry-picking is straightforward when source structure stays close.
  • git.librete.ch/libreshop/shop:v0.1.0 image becomes orphaned (already pinned by mp). Acceptable — mp's own image takes over, libreshop registry image deleted at end of grace period.

Sub-issues to action

  • #X — Last brand-strip pass: ensure repo is the canonical neutral reference (no MUELLERPRINTS hardcoded). Tag v0.x.0 final.
  • #X — Rewrite README as "copy this, customize freely" guide; remove "deploy as-is" language; document architecture
  • #X — Drop CI publishing to registry once mp has cut over to its own image
  • #X — Optional: extract @libreshop/types npm package (only if asked)

Predecessor

Supersedes #2 epic and its sub-issues #3–#9 (close those after this ADR is accepted).

# ADR — Pivot libreshop/shop from runtime image to reference template ## Status Proposed (2026-05-04). Awaiting acceptance + supersedes prior epic https://git.librete.ch/libreshop/shop/issues/2. ## Context `libreshop/shop` originated as the white-label Nuxt 3 frontend behind `muellerprints-paperwork.com` and was planned as a runtime-extendable base image for adapters (with `mp` being the first adapter). The plan was: - libreshop/shop ships brand-neutral, deployable as-is for demos - Adapters extend via Nuxt layers (`extends:` mechanism), Docker `FROM libreshop/shop:vX` - An "override surface" would be defined and semver-protected - Tailwind config, composables, components would all be layerable A feasibility analysis (ref: notebook in `mp/dummy/` planning, 2026-05-04) revealed: 1. **27 files** in libreshop/shop hardcode MUELLERPRINTS branding, Stuttgart address, Inhaber email, paperwork-logo 2. **Product schema is notebook-specific** — `ProductCover.binding`, `ProductPages`, `ProductRuling`, `ProductPattern` types and their Strapi backing tables assume a notebook product. Generalising to a generic "ProductAttribute" requires substantial refactor. 3. **Composables hardcode content** — `usePageContent.ts` (287 lines) contains literal MP legal/contact text that all 11 page files import directly. `useProductContent.ts` (369 lines) hardcodes notebook feature narratives ("Klassische Fadenheftung", "VIVUS 89 Papier", "FSC® C018175") that would need to move to per-adapter composables. 4. **Nuxt layers don't merge tailwind config or runtimeConfig defaults** automatically — adapters would need explicit factory pattern + `.env` pre-baking 5. **The override surface would need semver discipline** — every component rename, every slot signature change, every frontmatter field rename = breaking major. For a 1-adapter use case (mp), this is heavy maintenance. The mp adapter wants full freedom to add a Druckerei section, an Über uns area, and brand-specific content depth without negotiating upstream. ## Decision Pivot libreshop/shop from "runtime base image" to **reference template / starter**: - libreshop/shop **stops shipping a deployable image** at the next major release. The repo retains the source as a complete worked example. - README is rewritten as a **"copy this and modify" guide**, not "depend on this". - The current production consumer (`libretech/mp`) **forks** the source into its own tree (`mp/shop/`) and owns it from that point forward. - Future adapters do the same: `degit libreshop/shop my-shop`, then customize freely. What libreshop/shop **becomes**: - A curated public reference for "what a libretech-style Nuxt+Strapi shop looks like" - Documentation: README explains the architecture (Nuxt SSR, Strapi v4 CMS, PayPal, mail/pdf services) so newcomers understand the moving parts before they copy - Optionally: shared TypeScript types / composables published as a small npm package (`@libreshop/types`, `@libreshop/composables`) — only if multiple consumers emerge and ask for it. Default: no. What libreshop/shop **stops being**: - A registry image consumed by mp's `compose.yml` - A semver-stable override surface - A multi-tenant runtime ## Consequences **Pros:** - mp gets full ownership and freedom — no upstream coordination - libreshop maintainer (us) drops "support contract" obligation toward adapters - Code is easier to evolve without breaking changes against an unknown universe of adapters - The reference value is preserved — anyone wanting a libretech-flavoured shop has working code to start from **Cons:** - Future fork divergence: bug fixes in libreshop/shop don't reach mp automatically. Consumers must manually port. Acceptable cost — we have only 1 consumer (mp) and bug-fix cherry-picking is straightforward when source structure stays close. - `git.librete.ch/libreshop/shop:v0.1.0` image becomes orphaned (already pinned by mp). Acceptable — mp's own image takes over, libreshop registry image deleted at end of grace period. ## Sub-issues to action - [ ] #X — Last brand-strip pass: ensure repo is the canonical neutral reference (no MUELLERPRINTS hardcoded). Tag v0.x.0 final. - [ ] #X — Rewrite README as "copy this, customize freely" guide; remove "deploy as-is" language; document architecture - [ ] #X — Drop CI publishing to registry once mp has cut over to its own image - [ ] #X — Optional: extract `@libreshop/types` npm package (only if asked) ## Predecessor Supersedes https://git.librete.ch/libreshop/shop/issues/2 epic and its sub-issues #3–#9 (close those after this ADR is accepted).
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: libreshop/shop#10
No description provided.