fix: install shared packages over git, unbreaking CI
Some checks failed
Architecture Governance / architecture (push) Has been cancelled

The Verdaccio registry introduced earlier is unreachable from CI (listens on
127.0.0.1:4873 behind a firewall allowing only 80/443/SSH), which broke the
architecture-governance workflow - its npm ci step could no longer resolve
@marketplaces/auth.

Packages are now published to git release branches (release/auth,
release/payment in vitanovaPackages) whose root is the package itself, and
installed with git+<repo>#release/auth. No registry, token, tunnel, or CI
secret - anonymous git read is enough.

- package.json: git dependency; .npmrc removed (no scope mapping needed)
- vitanovaPackages release.yml rebuilt to force-push release branches
- ADR-0001 amended with the distribution change and why the registry lost
- BACKEND-HANDOFF: added the multi-tenancy section (hostname -> tenantKey ->
  per-tenant bootstrap config), corrected the install and deploy notes, and
  recorded that no CD pipeline exists
- PACKAGE-EXTRACTION / PACKAGES-USAGE rewritten for the git-branch flow

Verified: npm ci, arch:check:boundaries, ng build, 103/103 tests, all with
no credentials configured.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-08-18 02:08:05 +04:00
parent f6045a07b2
commit 551a22a245
7 changed files with 101 additions and 95 deletions

View File

@@ -1,66 +1,58 @@
# @marketplaces/auth & @marketplaces/payment — build, version, publish, consume
# @marketplaces/auth & @marketplaces/payment — build, version, release, infrastructure
See [ADR-0001](context/adrs/ADR-0001-extract-auth-and-payment-into-shared-marketplaces-packages.md) for why. This doc is the how — build, release, and infrastructure. For *consuming* the packages (install, providers, exported API), see [PACKAGES-USAGE.md](PACKAGES-USAGE.md).
See [ADR-0001](context/adrs/ADR-0001-extract-auth-and-payment-into-shared-marketplaces-packages.md) for why. This doc is the how. For *consuming* the packages (install, DI providers, exported API), see [PACKAGES-USAGE.md](PACKAGES-USAGE.md).
## Current state
Live end to end. `marketplaces` has no local copy of either package — it installs `@marketplaces/auth@0.1.0` from a private Verdaccio registry on the dev server. `packages/` no longer exists in this repo.
Working end to end with no credentials. `marketplaces` has no local copy of either package and no `.npmrc` — it installs `@marketplaces/auth` directly over git. A fresh clone plus `npm install` builds and tests green on any machine or CI runner.
## 1. Source repo
[sources.vitanova.network/sdarbinyan/vitanovaPackages](https://sources.vitanova.network/sdarbinyan/vitanovaPackages.git) — single monorepo (npm workspaces), `packages/auth` + `packages/payment`, `main` branch. This is where the package source lives and where CI publishes from.
[sources.vitanova.network/sdarbinyan/vitanovaPackages](https://sources.vitanova.network/sdarbinyan/vitanovaPackages.git) — npm workspaces monorepo, `packages/auth` + `packages/payment`, source on `main`.
## 2. Registry
## 2. How releases work
Verdaccio, running in Docker on the dev server (`213.21.246.138`, container `verdaccio`, config/storage at `/srv/marketplaces/verdaccio/`). **Not publicly reachable** — the server firewall only allows 80/443/SSH, and opening 4873 or loosening the registry's `$authenticated` access policy are both security-relevant changes that need an explicit decision, not something done silently. Reach it today via SSH tunnel:
npm cannot install a subdirectory of a git repo, so each package is published to its own **release branch** where the repo root *is* the package: `release/auth`, `release/payment`. Each contains only `package.json`, the built `dist/`, and a generated README.
```
"@marketplaces/auth": "git+https://sources.vitanova.network/sdarbinyan/vitanovaPackages.git#release/auth"
```
This was chosen over a registry because it needs **nothing**: no npm registry, no token, no tunnel, no CI secret. Anonymous git read is the only requirement, which is what makes CI and fresh clones work unattended.
`release/*` branches are generated and force-pushed. Never commit to them by hand.
## 3. Versioning
[Changesets](https://github.com/changesets/changesets). A PR that changes a package adds a changeset file (`npx changeset` at the repo root — pick package, bump type, one-line description). `ci.yml` rejects PRs without one.
## 4. CI/CD (vitanovaPackages)
- **`ci.yml`** — on PRs and non-main pushes: install, build, test, require a changeset.
- **`release.yml`** — on push to `main`, two jobs:
- `release-branches` (matrix over `auth`/`payment`): builds each package and force-pushes its output to `release/<pkg>`. Skips cleanly when nothing changed.
- `version-pr`: opens/updates a "Version Packages" PR when unreleased changesets exist. Merging it bumps versions on `main`, which re-triggers the release.
Only the checkout token is needed — no secrets to configure.
Workflows use GitHub Actions syntax; Gitea/Forgejo Actions are compatible. Other CI needs translating (steps are: install, build, test, force-push a branch).
## 5. The Verdaccio registry (superseded, still running)
A private Verdaccio instance runs on the dev server: Docker container `verdaccio`, port 4873, config and storage at `/srv/marketplaces/verdaccio/`, registry user `marketplaces-ci`. It holds `@marketplaces/auth@0.1.0` and `@marketplaces/payment@0.1.0`.
**Nothing uses it.** It was the original plan, but it listens on `127.0.0.1:4873` and the server firewall allows only 80/443/SSH — so no CI runner and no developer could reach it without an SSH tunnel, which defeats the point. The git-release-branch approach (§2) replaced it.
Keep it or remove it; no code or workflow depends on it. To reach it manually:
```bash
ssh -L 4873:127.0.0.1:4873 seto@213.21.246.138
```
Follow-up decision needed before CI can publish/consume without a human at the keyboard: either (a) reverse-proxy `/verdaccio/` or a subdomain through the existing nginx on 443 with TLS, or (b) open 4873 directly (not recommended — plain HTTP with credentials). Neither is done yet.
Making it the primary path again would need a reverse proxy through nginx plus TLS (no certificate exists on that box), or an open port carrying credentials over plain HTTP — neither is done, and neither is necessary now.
`@marketplaces/*` packages require an authenticated user to install (`access: $authenticated` in Verdaccio config) — deliberately not `$all`, since loosening that is itself a security-relevant config change. A registry user `marketplaces-ci` exists; get a token via `npm login --registry=http://127.0.0.1:4873/` (through the tunnel) and set it locally as a user-level `~/.npmrc` `_authToken` line, or export `NPM_TOKEN` and append it to `.npmrc` at CI runtime — never commit a token into this repo's `.npmrc`.
## 6. Migration status
`marketplaces/.npmrc` maps the scope: `@marketplaces:registry=http://127.0.0.1:4873/`update this once the registry has a real public/internal address.
**Auth: done.** `@marketplaces/auth` holds the real implementation — `telegram/` (live QR/session auth, customer + admin) and `ed25519/` (challenge/response admin auth, backend not shipped). Environment coupling was replaced with `AUTH_API_URL`/`TELEGRAM_BOT_USERNAME` injection tokens; `environment.production` became Angular's `isDevMode()`. `AdminPermissionsService` and `requireAdminPermission` stayed in `marketplaces` (`core/admin-auth/`)they read this app's mock Users domain, not a portable auth concern. All ~30 call sites import from the package; the old in-app auth files are deleted. Build, boundary checks, and 103/103 tests pass.
## 3. Versioning
[Changesets](https://github.com/changesets/changesets) — built for "many packages, one repo, independent versions." A PR that changes `packages/auth` adds a changeset file (`npx changeset` from the vitanovaPackages repo root, picks package + bump type + writes a short description) alongside the code change.
## 4. Publishing (CI)
Two workflows in the vitanovaPackages repo:
- `ci.yml` — on PRs and non-main pushes: install, build, test, and reject the PR if it has no changeset.
- `release.yml` — on push to `main`: install, build, test, then `changesets/action` opens/updates a version-bump PR; merging that PR publishes.
`release.yml` needs repo secrets `NPM_REGISTRY_URL` and `NPM_TOKEN`. **Neither is set, because no CI runner can currently reach the registry** (§2). The workflow fails loudly at the auth step rather than silently skipping the publish — that's deliberate, so a broken release is visible instead of looking green.
Until it's resolved, publish manually through the tunnel:
```bash
npm login --registry=http://127.0.0.1:4873/ --scope=@marketplaces
npm run build
cd packages/auth && npm publish --registry http://127.0.0.1:4873/
```
## 5. Consuming from `marketplaces` (and other projects)
```bash
npm install @marketplaces/auth
```
```ts
import { AuthService, AdminAuthService, adminAuthGuard, ... } from '@marketplaces/auth';
```
Pinned to an exact version (`"0.1.0"`, no `^`/`~`) per ADR-0001's consequence about registry-outage blast radius — bump deliberately, not automatically.
[renovate.json](../renovate.json) at repo root opens a grouped PR whenever either package publishes a new version — review and merge it manually (`automerge: false`).
## 6. Migration cutover
**Auth: done.** `@marketplaces/auth@0.1.0` holds the real implementation — two independent modules, `telegram/` (live Telegram QR/session auth, customer + admin) and `ed25519/` (future challenge/response admin auth, backend not shipped). Environment coupling was replaced with `AUTH_API_URL`/`TELEGRAM_BOT_USERNAME` injection tokens, provided from `app.config.ts`; `environment.production` became Angular's `isDevMode()`. `AdminPermissionsService` and `requireAdminPermission` stayed in `marketplaces` (`core/admin-auth/`) since they read this app's mock Users domain, not a portable auth concern. All ~30 call sites import `@marketplaces/auth`. `npm run build`, `npm run arch:check:boundaries`, and `npm test` (103/103) all pass against the registry-installed package.
**Payment: not started.** `core/finance`/`core/pricing` still live in `marketplaces`, same process as above once prioritized. `@marketplaces/payment@0.1.0` is published (scaffold only) but not yet a `marketplaces` dependency.
**Payment: not started.** `core/finance`/`core/pricing` still live in `marketplaces`. `@marketplaces/payment` is published as an empty scaffold and is not a dependency of anything.