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:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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 24–48h 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 4–8 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 P1–P16 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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user