Notes / Article
Four apps, one CSS layer, copied verbatim
The shared marketing kit is duplicated into four repositories instead of published as a package. A byte comparison makes that rule checkable.
AppAvio’s four apps run in separate repositories. Their public pages still use one marketing CSS layer. The file is copied into each repository and kept byte-identical.
That sounds less sophisticated than a package. For a small static layer, the constraint is useful. Each app can build and deploy its public route without a package registry, release dependency, or runtime asset host. The cost is explicit: every shared change must be applied and verified in every copy.
A shared layer is only shared when the repository copies are proven identical. Similar-looking files are separate implementations.
Why copy a file instead of publishing a package
A package creates a different operating model. Each consuming repository needs a declared version, an install step, and a process for deciding when to upgrade. That is valuable when the shared code has releases, compatibility ranges, or a large consumer set.
The AppAvio marketing layer is a bounded CSS contract:
- It contains the common
.av-*components and design tokens. - It has no runtime JavaScript.
- It has no remote assets.
- It is loaded locally by each app.
- App-specific content remains outside the shared file.
The duplication keeps each deployment self-contained. It also prevents a registry outage or an accidental floating version from changing a public page.
| Approach | Deployment property | Change cost |
|---|---|---|
| Remote stylesheet | One central asset request | Runtime dependency and cache coordination |
| Published package | Versioned build dependency | Release and upgrade work per consumer |
| Git submodule | Pinned repository dependency | Extra checkout and update workflow |
| Verbatim copy | Fully local build input | Update and compare every repository |
The current choice optimises for local builds and visible drift. It does not eliminate maintenance.
One source change, four deliberate copies
A token change begins in the authoritative design source. The change is reviewed there, then copied to each app repository. No consumer edits the shared file independently.
The verification can be plain shell:
shasum -a 256 design/appavio-marketing.css \
app/styles/appavio-marketing.css
Matching hashes show byte identity for that pair. A complete check compares the authoritative file with all four destinations and fails when any result differs.
The useful property is not the hash algorithm. It is the binary outcome: same or different. A visual review cannot prove that a focus rule, reduced-motion branch, or media query stayed intact.
What a token change costs
Changing one token may affect buttons, borders, tables, metadata, and focus states. Under the copy rule, the work has three parts:
- Change the authoritative file.
- Propagate the exact bytes to every repository.
- Build and check each public surface that consumes it.
The copy step is mechanical. The review step is not. Even identical CSS can interact with different page markup.
authoritative CSS
-> GPSR public page
-> Product AI public page
-> Duplicate Merger public page
-> AI Cart public page when it ships
AI Cart is still in development and has no install URL. Including its intended consumer in the check list does not make it installable. It makes the future boundary explicit.
Keep product differences outside the layer
The shared file defines behaviour and geometry. It should not contain a product name, app URL, listing URL, pricing statement, or launch status. Those values belong to app data and page content.
This split prevents three kinds of drift:
- A domain migration does not require a CSS release.
- An unlisted app does not inherit another app’s install link.
- A product-specific section can be omitted without adding a disabled shared component.
The CSS copy answers “how does this interface behave?” The app record answers “what can this product truthfully offer?”
Checks that make the rule real
Byte comparison is the first gate. It catches content drift. The remaining checks cover integration:
- Build every consuming site without fetching the stylesheet remotely.
- Confirm the stylesheet import order remains shared layer first, local additions second.
- Search the shared file for product-specific domains and names.
- Exercise keyboard focus and reduced-motion rules on each public page.
- Review representative widths because identical CSS can meet different markup.
The rule stays intentionally small: edit once, copy exactly, compare every destination, then render the consumers. When the number of apps or the rate of change makes that sequence unreliable, a versioned package may become the better tool. Until then, the copied file keeps every repository deployable on its own and makes drift measurable.
Related app
AI Cart
Cart-stage suggestions built from catalogue relationships, not from browsing history. No listing or install link exists yet.