chore(domain): yourplatform.com → breakpilot.com
ci / shared (push) Successful in 4s

Apply platform-domain decision (2026-05-18). No services touched; docs/config only.

Refs: M1.1
This commit was merged in pull request #5.
This commit is contained in:
2026-05-18 20:28:41 +00:00
parent 1ed2dcee57
commit 03a5b4846e
8 changed files with 81 additions and 80 deletions
+4 -4
View File
@@ -11,7 +11,7 @@ jobs:
runs-on: docker
environment:
name: production # Gitea Environments — requires sign-off per branch protection
url: https://yourplatform.com
url: https://breakpilot.com
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
@@ -22,7 +22,7 @@ jobs:
- name: verify stage soak (>= 24h on this image)
run: |
IMG=registry.yourplatform.com/${{ github.event.repository.name }}:env-stage
IMG=registry.breakpilot.com/${{ github.event.repository.name }}:env-stage
SOAK_SECONDS=$(orca image-age --env=stage --image $IMG)
if [ "$SOAK_SECONDS" -lt 86400 ]; then
echo "Stage soak only $SOAK_SECONDS s, < 24h. Aborting."
@@ -34,12 +34,12 @@ jobs:
- name: re-tag image as semver + env-prod
uses: docker/login-action@v3
with:
registry: registry.yourplatform.com
registry: registry.breakpilot.com
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASS }}
- run: |
IMG=registry.yourplatform.com/${{ github.event.repository.name }}
IMG=registry.breakpilot.com/${{ github.event.repository.name }}
docker pull $IMG:env-stage
docker tag $IMG:env-stage $IMG:v${{ steps.v.outputs.version }}
docker tag $IMG:env-stage $IMG:env-prod
+1
View File
@@ -9,6 +9,7 @@ Generated section is appended on release tag via `git-cliff` (see `.gitea/workfl
-
### Changed
- chore(domain): yourplatform.com → breakpilot.com
-
### Fixed
+1 -1
View File
@@ -86,4 +86,4 @@ When reviewing, check in this order:
## Questions
`#engineering` channel · `oncall@yourplatform.com` · or open a PR with a `[WIP]` prefix and ask in the description.
`#engineering` channel · `oncall@breakpilot.com` · or open a PR with a `[WIP]` prefix and ask in the description.
+24 -24
View File
@@ -120,8 +120,8 @@ Three Orca clusters, all on the same hardware until volume justifies separation:
Domain pattern:
- dev: `*.localhost` (mkcert)
- stage: `*.stage.yourplatform.com`
- prod: `*.yourplatform.com`
- stage: `*.stage.breakpilot.com`
- prod: `*.breakpilot.com`
### 1.9 Observability + audit
- **SigNoz** (already running at `signoz.meghsakha.com`) for traces, logs, metrics. Every service ships OTel SDK from day one.
@@ -172,12 +172,12 @@ Every place where a future flag would gate behaviour MUST flow through a single
- **Repos:** `platform/orca-platform`
- **Deliverables:**
- **PowerDNS Authoritative** on `vm-edge` (Orca-managed). PostgreSQL backend on same VM (small; ~100 records).
- At the registrar (Benjamin's account): set `ns1.yourplatform.com` and `ns2.yourplatform.com` glue records pointing at vm-edge public IP; delegate the domain to those NS.
- Zone file committed in `orca-platform/dns/yourplatform.com.zone`; Orca syncs into PowerDNS on apply.
- Records: apex `yourplatform.com`, wildcards `*.yourplatform.com` + `*.stage.yourplatform.com`, plus `auth.`, `erp.`, `mcp.`, `cdn.`, `mail.`, `ns1.`, `ns2.`, SPF/DKIM/DMARC TXT records (for M3.2).
- At the registrar (Benjamin's account): set `ns1.breakpilot.com` and `ns2.breakpilot.com` glue records pointing at vm-edge public IP; delegate the domain to those NS.
- Zone file committed in `orca-platform/dns/breakpilot.com.zone`; Orca syncs into PowerDNS on apply.
- Records: apex `breakpilot.com`, wildcards `*.breakpilot.com` + `*.stage.breakpilot.com`, plus `auth.`, `erp.`, `mcp.`, `cdn.`, `mail.`, `ns1.`, `ns2.`, SPF/DKIM/DMARC TXT records (for M3.2).
- Wildcard TLS via Let's Encrypt **DNS-01 against PowerDNS** (Lego's `--dns=pdns` provider); ACME credentials in Infisical at `/prod/orca-proxy/PDNS_API_KEY`.
- Orca-Proxy reloads the cert via watch on the secret file; renewal cron runs at 02:00 daily.
- **Acceptance:** `dig @1.1.1.1 anything.yourplatform.com` returns an answer; `curl https://anything.yourplatform.com` returns 404 from Orca-Proxy (no TLS error).
- **Acceptance:** `dig @1.1.1.1 anything.breakpilot.com` returns an answer; `curl https://anything.breakpilot.com` returns 404 from Orca-Proxy (no TLS error).
- **Tests:** ACME renewal dry-run; PowerDNS zone-diff check in CI; reach via stage and prod subdomains; cert expiry page wired to SigNoz alert.
- **Gate:** standard + manual DNS-delegation check by both founders (irreversible from registrar side without 2448h propagation)
- **Effort:** M (was S — registrar delegation + PowerDNS adds setup time vs. Cloudflare)
@@ -210,7 +210,7 @@ Every place where a future flag would gate behaviour MUST flow through a single
### M1.3 — Backups, monitoring, on-call
- **Depends on:** M1.2
- **Repos:** `platform/orca-platform`
- **Deliverables:** backup cron per VM per `INFRASTRUCTURE.md §3` (Postgres pg_dump, MinIO bucket replication); SigNoz OTel collector running on every VM; alert routing to `oncall@yourplatform.com`; restore runbook in `platform/docs/runbooks/restore.md`.
- **Deliverables:** backup cron per VM per `INFRASTRUCTURE.md §3` (Postgres pg_dump, MinIO bucket replication); SigNoz OTel collector running on every VM; alert routing to `oncall@breakpilot.com`; restore runbook in `platform/docs/runbooks/restore.md`.
- **Acceptance:** restore drill on stage succeeds (script in `platform/orca-platform/scripts/restore-drill.sh`); SigNoz shows traces from a synthetic request.
- **Tests:** disaster-recovery exercise per failure scenario in `INFRASTRUCTURE.md §10` — at least Scenarios A, B, F validated on stage.
- **Gate:** standard + manual sign-off
@@ -219,7 +219,7 @@ Every place where a future flag would gate behaviour MUST flow through a single
### M2.1 — Keycloak deployment
- **Depends on:** M1.2, M1.3
- **Repos:** `platform/orca-platform`
- **Deliverables:** Keycloak 26 on `vm-identity`, Postgres backing store on `vm-control`, exposed at `auth.yourplatform.com` and `auth.stage.yourplatform.com`. Realm import file in `orca-platform/keycloak/realm-export.json` (committed, source-of-truth).
- **Deliverables:** Keycloak 26 on `vm-identity`, Postgres backing store on `vm-control`, exposed at `auth.breakpilot.com` and `auth.stage.breakpilot.com`. Realm import file in `orca-platform/keycloak/realm-export.json` (committed, source-of-truth).
- **Acceptance:** master admin login works; realm `breakpilot-prod` exists in both envs.
- **Tests:** automated realm-state diff in CI (`kcadm` against checked-in export).
- **Gate:** standard + security checklist
@@ -247,20 +247,20 @@ Every place where a future flag would gate behaviour MUST flow through a single
- **Depends on:** M0.3 (needs DNS records under our control), M3.1
- **Repos:** `platform/orca-platform`
- **Deliverables:**
- **Stalwart** on `vm-control` (Orca-managed); reachable at `mail.yourplatform.com`.
- DNS records added to the zone in M0.3: `mail` A record, MX → mail, SPF (`v=spf1 mx -all`), DKIM (Stalwart-generated public key), DMARC (`p=quarantine; rua=mailto:dmarc@yourplatform.com`), reverse DNS (PTR) configured at the cloud provider for the vm-control public IP — coordinate with vm-edge since outbound mail must egress from a host with a clean PTR.
- **Stalwart** on `vm-control` (Orca-managed); reachable at `mail.breakpilot.com`.
- DNS records added to the zone in M0.3: `mail` A record, MX → mail, SPF (`v=spf1 mx -all`), DKIM (Stalwart-generated public key), DMARC (`p=quarantine; rua=mailto:dmarc@breakpilot.com`), reverse DNS (PTR) configured at the cloud provider for the vm-control public IP — coordinate with vm-edge since outbound mail must egress from a host with a clean PTR.
- SMTP submission service account per platform sender: `noreply@`, `oncall@`, `support@`, `billing@`, `dmarc@`.
- Outbound queue and bounce handler; failed deliveries surface as audit events.
- Webhook receiver at `/inbound/postmaster` for bounce/complaint feedback loops (Gmail FBL, MS SNDS).
- **IP warming plan**: write a `platform/docs/runbooks/email-warming.md` documenting the 48 week ramp from low daily volumes; first 2 weeks of trial nudges (M12.2) explicitly throttled.
- **Acceptance:** test email from `noreply@yourplatform.com` to `parnerkarsharang@gmail.com` lands in inbox (not spam) on day 1; SPF/DKIM/DMARC all "pass" in Gmail's "show original" view; mail-tester.com score ≥ 9/10.
- **Acceptance:** test email from `noreply@breakpilot.com` to `parnerkarsharang@gmail.com` lands in inbox (not spam) on day 1; SPF/DKIM/DMARC all "pass" in Gmail's "show original" view; mail-tester.com score ≥ 9/10.
- **Tests:** automated daily mail-tester check (failure pages on-call); bounce-handling integration test.
- **Gate:** standard + security checklist + manual deliverability sign-off (DKIM keys are load-bearing)
- **Effort:** L (deliverability tuning is the long tail)
**Phase 0 exit criteria:**
- Stage cluster boots cold from cron-driven nightly stop/start using only `INFRASTRUCTURE.md §5` ordering.
- A synthetic HTTPS request to `https://hello.stage.yourplatform.com` reaches a stub container.
- A synthetic HTTPS request to `https://hello.stage.breakpilot.com` reaches a stub container.
- Restore drill on stage Postgres succeeds end-to-end.
---
@@ -300,7 +300,7 @@ Every place where a future flag would gate behaviour MUST flow through a single
- **Depends on:** M2.2, M4.3, M0.3
- **Repos:** `platform/portal`, `platform/design-tokens`
- **Deliverables:** Next.js 15 app on `vm-control`; middleware reads `Host` → extracts slug → calls Tenant Registry `GET /tenants?slug=` → injects tenant context; Keycloak OIDC login; logout; `design-tokens` package consumed by portal.
- **Acceptance:** visiting `https://acme.stage.yourplatform.com` redirects to Keycloak; after login, user lands on `/acme/dashboard` (empty page) with valid session.
- **Acceptance:** visiting `https://acme.stage.breakpilot.com` redirects to Keycloak; after login, user lands on `/acme/dashboard` (empty page) with valid session.
- **Tests:** Playwright e2e: login + logout for an existing test tenant.
- **Gate:** standard
- **Effort:** M
@@ -317,14 +317,14 @@ Every place where a future flag would gate behaviour MUST flow through a single
### M5.3 — Playwright e2e harness
- **Depends on:** M5.2
- **Repos:** `platform/portal`
- **Deliverables:** Playwright config that runs against `stage.yourplatform.com` post-deploy; CI job `e2e-stage` triggered after stage deploy; failure pages on-call.
- **Deliverables:** Playwright config that runs against `stage.breakpilot.com` post-deploy; CI job `e2e-stage` triggered after stage deploy; failure pages on-call.
- **Acceptance:** breaking change to login is caught in CI within 10 min of merge.
- **Tests:** the suite itself.
- **Gate:** standard
- **Effort:** S
**Phase 1 exit criteria:**
- A tenant created via `POST /tenants` results in a working login flow at `<slug>.stage.yourplatform.com`.
- A tenant created via `POST /tenants` results in a working login flow at `<slug>.stage.breakpilot.com`.
- All Phase 1 routes have a passing Playwright spec running on every stage deploy.
---
@@ -354,7 +354,7 @@ Every place where a future flag would gate behaviour MUST flow through a single
### M6.3 — CERTifAI: manifest + integration assets
- **Depends on:** M6.2
- **Repos:** `benjamin_boenisch/certifai`
- **Deliverables:** `product.manifest.yaml` per `PRODUCT_INTEGRATION_SPEC.md §10` published to `cdn.yourplatform.com`; OpenAPI 3.1 spec; `/v1/health`, `/v1/usage`, `/v1/tenants/:id/export`, `DELETE /v1/tenants/:id/data`, `POST /v1/tenants/demo/reset`; web component `certifai-dashboard` per §5.A.
- **Deliverables:** `product.manifest.yaml` per `PRODUCT_INTEGRATION_SPEC.md §10` published to `cdn.breakpilot.com`; OpenAPI 3.1 spec; `/v1/health`, `/v1/usage`, `/v1/tenants/:id/export`, `DELETE /v1/tenants/:id/data`, `POST /v1/tenants/demo/reset`; web component `certifai-dashboard` per §5.A.
- **Acceptance:** CERTifAI appears in the portal catalog; subscribed tenants can open it from the dashboard.
- **Tests:** contract test that manifest validates against schema; web component renders inside portal shadow-DOM host.
- **Gate:** standard
@@ -391,7 +391,7 @@ Every place where a future flag would gate behaviour MUST flow through a single
### M8.1 — ERPNext deployment
- **Depends on:** M1.2, M2.1
- **Repos:** `platform/orca-platform`
- **Deliverables:** Frappe + ERPNext on `vm-control` (separate Postgres database from tenant_registry — see `INFRASTRUCTURE.md` RISK-1); reached at `erp.yourplatform.com`; Keycloak OIDC; IP-restricted at Orca-Proxy.
- **Deliverables:** Frappe + ERPNext on `vm-control` (separate Postgres database from tenant_registry — see `INFRASTRUCTURE.md` RISK-1); reached at `erp.breakpilot.com`; Keycloak OIDC; IP-restricted at Orca-Proxy.
- **Acceptance:** us login works; a Customer record can be created manually.
- **Tests:** smoke test for OIDC; backup of Frappe filestore validated.
- **Gate:** standard + manual sign-off (touches `vm-control` resources)
@@ -489,7 +489,7 @@ Every place where a future flag would gate behaviour MUST flow through a single
### M12.2 — Trial lifecycle cron + emails
- **Depends on:** M12.1, M3.2 (Stalwart must be deliverability-clean)
- **Repos:** `platform/tenant-registry`
- **Deliverables:** scheduler in tenant-registry that runs day-7/12/14 emails; status transitions trial → active (on payment) or trial → frozen → archived; SMTP via Stalwart at `mail.yourplatform.com:587`; sender `noreply@yourplatform.com`; HTML + plaintext templates committed under `tenant-registry/templates/email/`; List-Unsubscribe headers per RFC 8058.
- **Deliverables:** scheduler in tenant-registry that runs day-7/12/14 emails; status transitions trial → active (on payment) or trial → frozen → archived; SMTP via Stalwart at `mail.breakpilot.com:587`; sender `noreply@breakpilot.com`; HTML + plaintext templates committed under `tenant-registry/templates/email/`; List-Unsubscribe headers per RFC 8058.
- **Acceptance:** in a time-warped stage test (script that advances `trial_ends_at`), all transitions fire in order and all three emails land in Gmail inbox.
- **Tests:** integration test with time injection; deliverability spot-check at each release.
- **Gate:** standard
@@ -498,7 +498,7 @@ Every place where a future flag would gate behaviour MUST flow through a single
### M13.1 — Demo tenant seeding
- **Depends on:** M6.3, M7.2
- **Repos:** `platform/seed-data`
- **Deliverables:** per-product fixture archives (`certifai/seed-v1.tar.gz`, `compliance/seed-v1.tar.gz`); publishing pipeline to `cdn.yourplatform.com`; `catalog.demo.seed_data_url` populated in product manifests.
- **Deliverables:** per-product fixture archives (`certifai/seed-v1.tar.gz`, `compliance/seed-v1.tar.gz`); publishing pipeline to `cdn.breakpilot.com`; `catalog.demo.seed_data_url` populated in product manifests.
- **Acceptance:** calling `POST /v1/tenants/demo/reset` on either product restores fixtures.
- **Tests:** integration test asserts fixture state after reset.
- **Gate:** standard
@@ -508,7 +508,7 @@ Every place where a future flag would gate behaviour MUST flow through a single
- **Depends on:** M2.2, M13.1
- **Repos:** `platform/portal`, `platform/tenant-registry`
- **Deliverables:** demo tenant created in stage and prod with `kind=demo, status=demo`; SALES_REP role usable; backstage routes restricted to `/backstage/leads` and `/backstage/demo`; demo tenant audit events tagged `{"demo": true}` and hidden from real-tenant audit views.
- **Acceptance:** sales rep logs in at `demo.yourplatform.com`, walks both products live, [Request Trial] modal creates a CRM Lead with `sales_owner = the rep`.
- **Acceptance:** sales rep logs in at `demo.breakpilot.com`, walks both products live, [Request Trial] modal creates a CRM Lead with `sales_owner = the rep`.
- **Tests:** Playwright e2e for the sales walk-through.
- **Gate:** standard + security checklist (SALES_REP guardrail enforcement is the load-bearing piece)
- **Effort:** M
@@ -543,7 +543,7 @@ Every place where a future flag would gate behaviour MUST flow through a single
**Phase 4 exit criteria:**
- Every flow P1P16 from `PLATFORM_ARCHITECTURE.md` has a passing Playwright spec.
- Stage runs a full lifecycle: sign-up trial → convert → use → cancel → offboard, in an automated nightly job.
- We can hand a prospect a real demo using `demo.yourplatform.com`.
- We can hand a prospect a real demo using `demo.breakpilot.com`.
---
@@ -581,8 +581,8 @@ Every place where a future flag would gate behaviour MUST flow through a single
### M17.1 — MCP servers (Enterprise)
- **Depends on:** M6.3, M7.2
- **Repos:** `benjamin_boenisch/certifai`, `benjamin_boenisch/breakpilot-compliance`
- **Deliverables:** MCP endpoints per `PRODUCT_INTEGRATION_SPEC.md §10` `mcp:` block; gated on `plan == enterprise`; routed via `mcp.yourplatform.com`.
- **Acceptance:** Claude Code can connect to `mcp.yourplatform.com/certifai` with a service token and call `list_ai_agents`.
- **Deliverables:** MCP endpoints per `PRODUCT_INTEGRATION_SPEC.md §10` `mcp:` block; gated on `plan == enterprise`; routed via `mcp.breakpilot.com`.
- **Acceptance:** Claude Code can connect to `mcp.breakpilot.com/certifai` with a service token and call `list_ai_agents`.
- **Tests:** MCP contract test using `mcp-cli`.
- **Gate:** standard + security checklist
- **Effort:** L
@@ -703,7 +703,7 @@ That's 18 milestones. With one full-time agent and standard human review pacing,
- ~~Cloudflare account ownership~~ → not used; DNS is self-hosted via PowerDNS on vm-edge (M0.3). Registrar account (Benjamin's) still needs documented 2FA recovery — see new DR item below.
**Still open:**
- **CDN host** for `cdn.yourplatform.com`: self-hosted MinIO + Caddy on vm-edge is the OSS-aligned default; alternative is BunnyCDN (cheap, EU). Decide before M6.3 (manifest bundles + hero images).
- **CDN host** for `cdn.breakpilot.com`: self-hosted MinIO + Caddy on vm-edge is the OSS-aligned default; alternative is BunnyCDN (cheap, EU). Decide before M6.3 (manifest bundles + hero images).
- **Cloud provider for port 25 outbound.** Stalwart needs unblocked port 25 to send mail. Hetzner blocks by default and requires a request to unblock with proof of intent + abuse contact; OVH and Scaleway unblock on request faster. Confirm with Benjamin which provider vm-control runs on. Block on M3.2 if port 25 is unblockable — fallback is sending via a different provider's IP with reverse DNS.
- **Test data privacy.** The demo tenant must contain ONLY synthetic data — confirm seed pipeline strips real PII even if our test orgs accidentally seed from prod.
- **Registrar + DNS bus-factor.** Document who owns the registrar account, who has 2FA recovery codes, and the procedure to update NS records without that person available. Goes in `platform/docs/runbooks/dr.md` before M0.3 ships.
+13 -13
View File
@@ -41,7 +41,7 @@ Critical isolations preserved even at 4 VMs:
```
vm-edge (prod, m2.small 8 GB, public IP)
├── orca-proxy (Orca-managed; wildcard TLS terminator)
├── powerdns-auth (Orca-managed; authoritative DNS for yourplatform.com)
├── powerdns-auth (Orca-managed; authoritative DNS for breakpilot.com)
├── keycloak-26 (Orca-managed; JVM, ~1.5 GB heap)
├── postgres-keycloak (Orca-managed; dedicated PG instance for Keycloak only)
├── infisical (Orca-managed)
@@ -57,7 +57,7 @@ vm-control (prod, m2.medium 16 GB)
├── frappe-hd (same bench as ERPNext)
├── mariadb (Orca-managed; for ERPNext)
├── redis-erpnext (Orca-managed)
└── stalwart-mail (Orca-managed; SMTP/IMAP/JMAP on mail.yourplatform.com)
└── stalwart-mail (Orca-managed; SMTP/IMAP/JMAP on mail.breakpilot.com)
vm-data (prod, m2.medium 16 GB)
├── certifai-dashboard (Orca-managed)
@@ -84,8 +84,8 @@ stage (stage, m2.small 8 GB, public IP)
└── qdrant-stage (ephemeral, tiny corpus)
Calls OUT to prod:
→ auth.yourplatform.com (Keycloak token issuance, under stage client_id)
→ mail.yourplatform.com (Stalwart SMTP, recipient filter forces +stage@ only)
→ auth.breakpilot.com (Keycloak token issuance, under stage client_id)
→ mail.breakpilot.com (Stalwart SMTP, recipient filter forces +stage@ only)
→ Polar SANDBOX webhook URL (NEVER prod Polar)
→ no calls to prod Postgres-app, MariaDB, MongoDB
```
@@ -107,8 +107,8 @@ stage (stage, m2.small 8 GB, public IP)
```
INTERNET
(yourplatform.com — authoritative on vm-edge PowerDNS;
stage.yourplatform.com — authoritative same zone)
(breakpilot.com — authoritative on vm-edge PowerDNS;
stage.breakpilot.com — authoritative same zone)
┌─────────────┴─────────────┐
│ │
@@ -143,15 +143,15 @@ stage (stage, m2.small 8 GB, public IP)
└──────────────┘
Orca-Proxy routing (vm-edge, by Host header):
auth.yourplatform.com → 127.0.0.1:8443 (Keycloak, local on vm-edge)
erp.yourplatform.com → vm-control:8000 (ERPNext) [allowlist: our IPs only]
git.yourplatform.com → vm-edge:3000 (Gitea, local) [allowlist: our IPs only]
mail.yourplatform.com → vm-control:587 (Stalwart submission) [allowlist: VM internal only]
ns1.yourplatform.com → 127.0.0.1:53 (PowerDNS, local)
*.yourplatform.com → vm-control:3000 (customer portal)
auth.breakpilot.com → 127.0.0.1:8443 (Keycloak, local on vm-edge)
erp.breakpilot.com → vm-control:8000 (ERPNext) [allowlist: our IPs only]
git.breakpilot.com → vm-edge:3000 (Gitea, local) [allowlist: our IPs only]
mail.breakpilot.com → vm-control:587 (Stalwart submission) [allowlist: VM internal only]
ns1.breakpilot.com → 127.0.0.1:53 (PowerDNS, local)
*.breakpilot.com → vm-control:3000 (customer portal)
Orca-Proxy routing (stage, by Host header):
*.stage.yourplatform.com → 127.0.0.1:3000 (stage portal — all subdomains route here)
*.stage.breakpilot.com → 127.0.0.1:3000 (stage portal — all subdomains route here)
```
---
+16 -16
View File
@@ -94,7 +94,7 @@ org_roles — [IT_ADMIN, USER, ...] roles within their org
realm_roles — [customer] | [BREAKPILOT_ADMIN] | [SUPPORT_ENGINEER] | [SALES_REP]
products — [certifai, compliance] entitlements (injected by protocol mapper)
plan — starter | professional | enterprise
iss — https://auth.yourplatform.com/realms/breakpilot-prod
iss — https://auth.breakpilot.com/realms/breakpilot-prod
```
The `products` and `plan` claims are added by a Keycloak **protocol mapper** that reads live entitlements from the Tenant Registry at token issuance. Products do not need to call back to the registry on every request.
@@ -108,12 +108,12 @@ Three distinct services. Clear separation of responsibility.
### 5a. Customer Portal
**Technology:** Next.js 15 (new service)
**Deployed at:** `*.yourplatform.com` via Orca-Proxy wildcard routing
**Deployed at:** `*.breakpilot.com` via Orca-Proxy wildcard routing
The front door for all customers and for us. Owns no business logic — it is a routing, auth, and UI layer.
**Subdomain routing:**
- DNS wildcard `*.yourplatform.com` → Orca-Proxy
- DNS wildcard `*.breakpilot.com` → Orca-Proxy
- Orca-Proxy reads `Host` header → routes all traffic to the portal container
- Portal reads `Host` → extracts tenant slug → looks up Tenant Registry
@@ -190,7 +190,7 @@ The front door for all customers and for us. Owns no business logic — it is a
### 5b. ERPNext
**Technology:** Frappe + ERPNext (self-hosted via Orca)
**Access:** `erp.yourplatform.com` — us only (IP-restricted at Orca-Proxy)
**Access:** `erp.breakpilot.com` — us only (IP-restricted at Orca-Proxy)
**Auth:** Keycloak OIDC — we log in with our existing accounts, no separate password
ERPNext is our **business operations backbone**. We do not build CRM, invoicing, or HR — we configure ERPNext for these.
@@ -262,7 +262,7 @@ api_keys portal-owned. tenant_id, product, scopes, name,
### 5d. Demo Tenant (Shared)
**Slug:** `demo` — reachable at `demo.yourplatform.com`
**Slug:** `demo` — reachable at `demo.breakpilot.com`
**Status:** `demo` (never transitions; never billed)
**Owner:** us (`BREAKPILOT_ADMIN` curates content; `SALES_REP` reads + logs in)
@@ -299,7 +299,7 @@ all real-tenant flows work otherwise same flows, same code paths
**Support flow:**
- Customer submits ticket via `/[slug]/support/` (Frappe HD customer portal, embedded or linked)
- Agent (us) triages in Frappe HD agent UI at `erp.yourplatform.com`
- Agent (us) triages in Frappe HD agent UI at `erp.breakpilot.com`
- If technical: agent clicks "Escalate to Engineering" → Frappe server script creates a Gitea issue in the relevant repo via Gitea REST API → issue URL stored on ticket
- When Gitea issue is closed → Gitea webhook → Frappe HD → ticket marked "Resolved"
@@ -341,11 +341,11 @@ GDPR and AI-Act compliance automation platform. After updates, tenant identity c
```
Orca-Proxy routing table:
auth.yourplatform.com → Keycloak
erp.yourplatform.com → ERPNext + Frappe HD (IP-restricted)
git.yourplatform.com → Gitea
secrets.yourplatform.com → Infisical (IP-restricted)
*.yourplatform.com → customer-portal (wildcard, Host → tenant)
auth.breakpilot.com → Keycloak
erp.breakpilot.com → ERPNext + Frappe HD (IP-restricted)
git.breakpilot.com → Gitea
secrets.breakpilot.com → Infisical (IP-restricted)
*.breakpilot.com → customer-portal (wildcard, Host → tenant)
```
**Services managed by Orca:**
@@ -436,7 +436,7 @@ Data Stores
```
USER ORCA-PROXY PORTAL KEYCLOAK CUSTOMER IdP
│ │ │ │ │
│ acme.yourplatform.com │ │ │ │
│ acme.breakpilot.com │ │ │ │
│───────────────────────►│ │ │ │
│ │ Host=acme.* │ │ │
│ │───────────────►│ │ │
@@ -458,7 +458,7 @@ Data Stores
```
USER PORTAL KEYCLOAK
│ │ │
│ acme.yourplatform│ │
│ acme.breakpilot │ │
│──────────────────►│ │
│ │ redirect + PKCE │
│ │─────────────────►│
@@ -671,7 +671,7 @@ Data Stores
│ │ impersonated_by │ │
│ │ claim) │ │
│ │ │
│ new tab: acme.yourplatform.com │ │
│ new tab: acme.breakpilot.com │ │
│──────────────────────────────────────────────────────────►│
│ │ [orange banner] │
│ │ Impersonating │
@@ -749,7 +749,7 @@ Data Stores
│ │ │ │
│ open Zoom with prospect, share screen │
│ │
│ demo.yourplatform.com │
│ demo.breakpilot.com │
│────────────────────────────────►│ │
│ │ │ Host: demo │
│ │ │ → slug = demo │
@@ -796,7 +796,7 @@ Data Stores
```
PROSPECT PORTAL TENANT REGISTRY ERPNEXT KEYCLOAK
│ │ │ │ │
yourplatform.com/start │ │ │
breakpilot.com/start │ │ │
│──────────────►│ │ │ │
│ form: email, company, password │ │ │
│──────────────►│ │ │ │
+19 -19
View File
@@ -279,7 +279,7 @@ Products that ship custom styling must respect the `theme` attribute and the pre
```
Product publishes a bundle at:
https://cdn.yourplatform.com/products/{name}/{version}/element.js
https://cdn.breakpilot.com/products/{name}/{version}/element.js
Portal loads it lazily via dynamic import when the user navigates to /[tenant]/products/{name}.
Portal caches the bundle URL per product version (declared in tenant_products.config).
@@ -343,12 +343,12 @@ The product ships NO frontend code. The portal renders a generic management UI f
│ CODE SAMPLES │
│ ──────────────────────────────────────────────────── │
│ [curl] [JS] [Python] │
│ curl -X POST https://notetaker-api.yourplatform.com/v1 │
│ curl -X POST https://notetaker-api.breakpilot.com/v1 │
│ -H "Authorization: ApiKey k_xxx" │
│ -H "X-Tenant: acme" │
│ -d '{...}' │
│ │
│ DOCS ► developers.yourplatform.com/products/notetaker │
│ DOCS ► developers.breakpilot.com/products/notetaker │
└──────────────────────────────────────────────────────────┘
```
@@ -394,7 +394,7 @@ An MCP (Model Context Protocol) server exposes the product's capabilities as too
```
1. ONE MCP server per product
Endpoint: https://mcp.{product}.yourplatform.com (or unified mcp.yourplatform.com/{product})
Endpoint: https://mcp.{product}.breakpilot.com (or unified mcp.breakpilot.com/{product})
2. Authentication via SCOPED API KEY
Customer IT Admin generates API key in /[tenant]/settings/api-keys.
@@ -438,7 +438,7 @@ Enterprise customers automatically get MCP enabled. Starter/Pro customers see "A
## 7. Documentation Contract
A product ships five required documents. They are published at `developers.yourplatform.com/products/{name}/`.
A product ships five required documents. They are published at `developers.breakpilot.com/products/{name}/`.
```
1. README What does it do? Value prop in 200 words.
@@ -763,16 +763,16 @@ product:
vendor: breakpilot # we; future third-parties will use their slug
contract_version: "1.0"
product_version: "1.4.2"
repo: git.yourplatform.com/sharang/certifai
repo: git.breakpilot.com/sharang/certifai
catalog:
# Renders in /[tenant]/catalog and /backstage/products
category: "AI Infrastructure" # AI Infrastructure | Compliance | Productivity | Security | Data
tagline: "GDPR-compliant LLMs without leaving the EU"
hero_image: https://cdn.yourplatform.com/products/certifai/hero.png
hero_image: https://cdn.breakpilot.com/products/certifai/hero.png
screenshots:
- https://cdn.yourplatform.com/products/certifai/dashboard.png
- https://cdn.yourplatform.com/products/certifai/agents.png
- https://cdn.breakpilot.com/products/certifai/dashboard.png
- https://cdn.breakpilot.com/products/certifai/agents.png
pricing_summary: "From €X/seat/month — included on Professional and Enterprise plans"
available_on_plans: [trial, professional, enterprise] # 'trial' opt-in for self-serve
trial_days: 14
@@ -784,7 +784,7 @@ catalog:
demo:
supported: true # MUST be true unless explicitly waived
seed_data_url: https://cdn.yourplatform.com/products/certifai/demo/seed-v3.tar.gz
seed_data_url: https://cdn.breakpilot.com/products/certifai/demo/seed-v3.tar.gz
reset_endpoint: /v1/tenants/demo/reset # called nightly by portal cron
persona_hints: # for sales rep talk track
- "GDPR officer at a 200-person SaaS"
@@ -807,7 +807,7 @@ identity:
frontend:
type: interactive # interactive | widget | headless
tag: certifai-dashboard
bundle_url: https://cdn.yourplatform.com/products/certifai/{version}/element.js
bundle_url: https://cdn.breakpilot.com/products/certifai/{version}/element.js
bundle_size_kb: 380
routes:
- path: /
@@ -828,7 +828,7 @@ backend:
mcp:
enabled: true
required_plan: enterprise
endpoint: https://mcp.yourplatform.com/certifai
endpoint: https://mcp.breakpilot.com/certifai
tools:
- name: list_ai_agents
description: "Returns AI agents configured for the tenant"
@@ -864,7 +864,7 @@ backup:
retention_days: 30
infra:
image: registry.yourplatform.com/certifai-dashboard
image: registry.breakpilot.com/certifai-dashboard
vm: vm-certifai
replicas: 1
resource_limits:
@@ -909,7 +909,7 @@ The example above shows an `interactive` product. Headless and widget products d
frontend:
type: widget
tag: status-monitor-widget
bundle_url: https://cdn.yourplatform.com/products/status/{version}/widget.js
bundle_url: https://cdn.breakpilot.com/products/status/{version}/widget.js
bundle_size_kb: 38
dimensions:
width: 400
@@ -954,7 +954,7 @@ frontend:
- language: curl
title: "Create a session"
snippet: |
curl -X POST https://notetaker-api.yourplatform.com/v1/sessions \
curl -X POST https://notetaker-api.breakpilot.com/v1/sessions \
-H "Authorization: ApiKey k_xxx" \
-H "X-Tenant: acme" \
-d '{"audio_url": "...", "language": "en"}'
@@ -963,7 +963,7 @@ frontend:
snippet: |
import requests
requests.post(
"https://notetaker-api.yourplatform.com/v1/sessions",
"https://notetaker-api.breakpilot.com/v1/sessions",
headers={"Authorization": "ApiKey k_xxx", "X-Tenant": "acme"},
json={"audio_url": "...", "language": "en"},
)
@@ -986,7 +986,7 @@ Products can call each other directly. Auth is via short-lived service tokens is
1. Compliance product needs to list AI agents for an AI Act assessment.
2. Compliance backend requests a service token:
POST https://auth.yourplatform.com/realms/breakpilot-prod/protocol/openid-connect/token
POST https://auth.breakpilot.com/realms/breakpilot-prod/protocol/openid-connect/token
Body: grant_type=client_credentials
client_id=compliance-svc
client_secret=<from Infisical>
@@ -1135,7 +1135,7 @@ A product is "ready to ship to a customer" when all boxes are ticked.
☐ All tools tenant-scoped and audited
☐ Documentation
☐ README published at developers.yourplatform.com/products/{name}
☐ README published at developers.breakpilot.com/products/{name}
☐ API reference auto-generated and live
☐ Integration guide for customer IT
☐ Operational runbook for us
@@ -1220,7 +1220,7 @@ Effort estimate: 3-5 weeks of focused work
```
- Design tokens package (@breakpilot/design-tokens) — needs to exist before web components ship
- CDN for product bundles — pick provider (Hetzner Object Storage + Cloudflare?)
- MCP gateway — single mcp.yourplatform.com vs. per-product subdomains
- MCP gateway — single mcp.breakpilot.com vs. per-product subdomains
- Third-party manifest signing — defer until first real third-party conversation
- Inter-product event bus — explicitly deferred; service tokens cover the use cases for now
- Contract testing — automate manifest + openapi validation in Gitea Actions
+3 -3
View File
@@ -39,8 +39,8 @@ For IaC: list the make targets.}}
| Env | URL | How |
|---|---|---|
| dev | `http://localhost:3000` | `make dev` |
| stage | `https://docs.stage.yourplatform.com` | auto on merge to `main` |
| prod | `https://docs.yourplatform.com` | manual: tag `vX.Y.Z` + sign-off |
| stage | `https://docs.stage.breakpilot.com` | auto on merge to `main` |
| prod | `https://docs.breakpilot.com` | manual: tag `vX.Y.Z` + sign-off |
Rollback: `orca rollout undo docs --env={{env}}`.
@@ -48,7 +48,7 @@ Rollback: `orca rollout undo docs --env={{env}}`.
- Traces, logs, metrics: [SigNoz](https://signoz.meghsakha.com) — service name `docs`
- Audit events: Tenant Registry `/audit` (Retraced-shape schema)
- On-call: `oncall@yourplatform.com` · runbook at `platform/docs/runbooks/docs.md`
- On-call: `oncall@breakpilot.com` · runbook at `platform/docs/runbooks/docs.md`
## Contributing