You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
6.8 KiB
Markdown
145 lines
6.8 KiB
Markdown
# Branches in this repo
|
|
|
|
## `main` — the dev workspace
|
|
|
|
Every feature, every client's code, all in one place — this is where you
|
|
work day to day. **`main` is never pushed to a client's GitLab directly** —
|
|
it's the source a client branch gets cut from.
|
|
|
|
## `client/<slug>` — one per client, generated, not edited
|
|
|
|
Produced by:
|
|
|
|
```bash
|
|
scripts/export_client.sh <slug> <FLAG1,FLAG2,...>
|
|
```
|
|
|
|
Flags are the `VITE_ALLOW_ACCESS_<FLAG>` suffixes already used in
|
|
`.env.example`: `EFFICIENCY`, `PFI`, `RELIABILITY`, `RISK_MATRIX`, `LCCA`,
|
|
`RBD`, `OH`, `IRCFA`, `AHM`. Auth, the dashboard shell, admin, and ops-dock
|
|
have no flag and always ship.
|
|
|
|
Each export is `main`, with:
|
|
- `.env.example`'s `VITE_ALLOW_ACCESS_*` defaults set so a plain
|
|
`cp .env.example .env` on the client's side turns on only what they
|
|
licensed,
|
|
- no `Jenkinsfile` (client has their own CI), no `memory/` (dev notes),
|
|
no `ref/` (internal PRD/screenshots), no `scripts/`.
|
|
|
|
**These branches are disposable — never hand-edit them.** The script does
|
|
`git checkout -B client/<slug> main`, so re-running it regenerates the
|
|
branch from scratch every time. If a client needs a hotfix that shouldn't
|
|
wait for the next full export, make the fix on `main` first, then re-run
|
|
the export.
|
|
|
|
Pushing to the client's GitLab is a separate, explicit step (the script
|
|
prints the command, or pass `--push <remote-url>` to do it inline):
|
|
|
|
```bash
|
|
git push <client-remote> client/<slug>:main
|
|
```
|
|
|
|
### What the flags do and don't do — read this before relying on them
|
|
|
|
Unlike the backend, **this does not remove any code from the repo.**
|
|
`src/router/index.tsx` statically imports every page under `src/pages/`
|
|
regardless of flags — they're still individually code-split via `lazy()`
|
|
(so a page nobody licensed isn't in anyone's initial JS payload), but the
|
|
source is still sitting in the export, reachable by anyone with repo access.
|
|
|
|
What a disabled flag *does* block, via `src/router/FeatureGate.tsx`: every
|
|
route under that domain — both the flat `/xxx-app/*` paths and the
|
|
`/unit/:unitId/xxx/*` paths, plus its `/landing/*` teaser page where one
|
|
exists — renders `UnderConstructionPage` instead. `FeatureGate` wraps the
|
|
layout route's `element`, not something inside it, so the real layout
|
|
component (and whatever data-fetching hooks it kicks off on mount) is
|
|
never mounted at all when disabled, and there's no `<Outlet />` in the
|
|
tree for any child route to render into — direct URL navigation to a
|
|
sub-page hits the same placeholder as the domain's root. So a client
|
|
*can't see* a feature they weren't sold, even by guessing/typing the URL.
|
|
They just aren't prevented from finding it in the repo's source if they
|
|
have repo access at all — that's the part that would need the bigger job
|
|
below.
|
|
|
|
If you need the frontend repo itself to not contain another client's page
|
|
source at all (not just block them from seeing it rendered), that's a
|
|
bigger job: `router/index.tsx`'s route tree would need to be filtered per
|
|
export the way `config/urls.py` is on the backend, and every page under
|
|
an unlicensed feature would need to come out of `src/pages/` and
|
|
`src/features/` too. Not done here — flag if you want it built.
|
|
|
|
### Known gap: hardcoded branding
|
|
|
|
`public/Logo_PLN.png`, `Logo_PLN.svg`, `rcfa-app/logo-tjb.png` and similar
|
|
are referenced directly (by that literal filename) from ~16 files —
|
|
nav sidebars, the login page, PDF/Excel report generators. `export_client.sh`
|
|
prints a warning when these are still present in an export, but does not
|
|
attempt to fix it: swapping branding per client needs those references
|
|
replaced with a generic path (e.g. `/branding/logo.png`) on `main` first,
|
|
the same way `config/settings_local.py` only works on the backend because
|
|
`main` already has a hook pointed at it. Until that refactor happens, every
|
|
client export currently ships the same PLN/TJB branding and plant-specific
|
|
copy (see also `src/pages/unit-3`, and `SchematicName`-style hardcoding on
|
|
the backend) regardless of who it's actually for.
|
|
|
|
## `overlay/<slug>` — one per client, permanent, hand-maintained
|
|
|
|
For whatever's unique to one client and genuinely not shared with any
|
|
other. Created with:
|
|
|
|
```bash
|
|
scripts/new_client_overlay.sh <slug>
|
|
```
|
|
|
|
This is an **orphan branch** — no shared history with `main`, no shared
|
|
history with any other client's overlay. Nobody working on
|
|
`overlay/client-b` ever has a reason to check out `overlay/client-a`; the
|
|
two are as separate as if they were different repos.
|
|
|
|
An overlay may only ever *add* files, never edit one that also exists on
|
|
`main`. Three extension points exist, all the same shape — a path that
|
|
doesn't exist on `main`, discovered via `import.meta.glob`, which
|
|
resolves to an empty object when nothing matches, so each is always safe
|
|
to be absent:
|
|
|
|
- **Routes** — `src/router/overlay/<slug>.tsx`, picked up by
|
|
`src/router/index.tsx` via `import.meta.glob("./overlay/*.tsx")`.
|
|
Export `routes: RouteObject[]`. `scripts/new_client_overlay.sh` scaffolds
|
|
this one with an empty array — safe by construction, since an empty
|
|
array adds nothing until you fill it in.
|
|
- **Layout/shell** — `src/shared/components/layouts/overlay/AppLayout.tsx`,
|
|
picked up by `src/shared/components/layouts/AppLayout.tsx` (every
|
|
domain's `*LayoutRoute` imports `AppLayout` from there, never
|
|
`DefaultAppLayout` directly, so this one file swaps the whole shell —
|
|
sidebar, navbar, colors — everywhere at once). Default export, same
|
|
props as `DefaultAppLayout`.
|
|
- **Theme** — `src/styles/overlay/*.css`, loaded by `src/main.tsx` after
|
|
`index.css`, so redefining `:root`/`.dark`'s CSS custom properties
|
|
(`--primary`, `--background`, etc.) there wins the cascade.
|
|
|
|
The layout and theme hooks are **not** scaffolded with a placeholder file
|
|
the way routes are, and that's deliberate: an empty `routes` array has no
|
|
effect, but the layout/theme hooks activate the instant a matching file
|
|
exists at all, regardless of content. Only add one once you have a real
|
|
replacement.
|
|
|
|
Also allowed, same "new path only" rule:
|
|
- New components/pages that an overlay route or layout references.
|
|
- New static assets under a path `main` doesn't already use (see the
|
|
branding gap above for why an *existing* asset path isn't safe to
|
|
override yet).
|
|
|
|
That constraint isn't arbitrary: `client/<slug>` is regenerated from
|
|
scratch on every export, so `.env.example` and every existing file are
|
|
rewritten every single time. An overlay branch has no commit in common
|
|
with whatever `client/<slug>` looks like *this* time, so if it touched a
|
|
file the export also touches, every future export would hit the same
|
|
merge conflict forever. Sticking to new, untouched paths sidesteps that
|
|
entirely — a merge that only adds files can't conflict with content it
|
|
never shared.
|
|
|
|
`export_client.sh` merges `overlay/<slug>` into the freshly-built
|
|
`client/<slug>` automatically, if that branch exists, right before the
|
|
final guard — so overlay content gets the same leak check as everything
|
|
else.
|