Panel klienta Aphrodi

A twin client panel in Aphrodi's full identity. The same proven core as the VulCode panel, a different brand and palette - proof that our panel architecture is genuinely multi-brand. The client gets a coherent tool without building everything from scratch.

Panel klienta Aphrodi
TL;DR

The Aphrodi client panel on the same proven core as the VulCode panel, but in Aphrodi's full identity: its own palette, typography and mood. One feature set, two brands, zero code duplication. This was the test of whether our panel architecture is genuinely multi-brand, or whether we just say so.

Overview

We built the VulCode client panel for ourselves, and out of it came a core we claimed was multi-brand. Aphrodi was the chance to check that for real. Aphrodi is a separate brand with its own strong identity, so its panel could not look like a repainted VulCode. It had to feel like part of Aphrodi and at the same time stand on the same code as its sister brand's panel.

That is harder than it sounds. Saying "multi-brand" is easy; proving that underneath there is not simply a copied directory with hand-swapped colors is harder. This case study is about how we stress-tested our own architecture and what it means that it passed.

"Multi-brand" is easy to say

The most common fib in projects like this is that multi-brand exists only on the slide. In the code sit two nearly identical directories where someone manually swapped the palette and the logo. It looks like a shared core until the first fix comes in. Then it turns out you have to paste it twice, and by the third version the layout starts to drift.

We wanted the opposite: for the Aphrodi panel and the VulCode panel to be physically the same code, not two copies living side by side. The difference between them is to be a declaration, not a duplicate. If we improve how commissions are counted or how the invoice view looks, both brands are to get that improvement in the same commit, with nothing rewritten.

That was the real test of our architecture. If adding a second brand required branching the code, it would mean the core was not multi-brand at all, we just called it that.

A brand as a set of tokens

The solution is simple to describe and demanding to execute: the core is one, and a brand enters as a set of tokens. Colors, fonts, radii, mood - everything that tells Aphrodi apart from VulCode - is data the core reads and reacts to. The logic, screens and whole flow are shared. Only the visual layer changes, and not by swapping files but by choosing a token set.

Because of that the brands are not two repositories or two directories. They are two entries in one map. The panel knows which brand it renders for and reaches for the right tokens, while the rest of the code need not even know there is more than one brand.

brandThemes.ts · ts
const themes: Record<BrandId, Theme> = {
  vulcode: { accent: '#7c5cff', display: 'Space Grotesk' },
  aphrodi: { accent: '#e0a53f', display: 'Fraunces' },
};
➜
Tip

The whole difference between the panels comes down to a single tokens object, not a separate repository. Adding a third brand later is another entry in that map plus its assets, not another panel to build and maintain from scratch. The cost of a new brand drops from a project to a config.

One fix, two brands

The value of this approach shows best in daily work. When we improve the projects view or the way the panel shows billing, there is no "did we do the same in the other brand" question. The fix lands once and catches both, because it is physically the same code. A whole class of bugs disappears where one brand runs ahead of the other because someone forgot to sync the copies.

A clean split of shared and separate

The split is clean and easy to describe. Shared are the features, screens, logic and API. Separate are only the palette, typography, mood and small details that build a brand's identity. That line runs exactly where it should: the core knows nothing about colors, and the brand layer knows nothing about how commissions are counted.

The same thing, done two ways

LayerSharedVaries per brand
Features and screensyes-
Logic and APIyes-
Palette and typography-yes
Mood and details-yes

What the finished product actually delivers

An Aphrodi client gets a tool that looks and feels like Aphrodi, not like VulCode in other colors. It has the full client-panel feature set, as polished as in the sister brand, because underneath it is exactly the same proven core. Nothing was simplified just because it is the second brand.

On our side the gain is structural. We do not maintain two separate panels, just one core with a brand layer on top. The architecture passed the test the project was about: multi-brand turned out to be real, not declared. The next brand is not another project from scratch, just an entry in the token map and a handful of assets, ready to sit on the same, already polished foundation.

Have a similar project?

Get in touch - a quote is free and comes back within an hour.