Skip to main content

Keystone Business Requirements Document

Version: 1.0. Date: September 2026.
Author: Pete Carroll, Founder — Traxs Group LLC.
Status: Draft (first real BRD. Everything before this document was framing and a spike, not a product plan).
Product: Keystone: Traxs Group Platform Identity Service
URL: identity.traxsgroup.com (proposed — not yet provisioned).


Where this comes from​

Keystone has no BRD/PRD/SAD until now because it didn't need one — it was a decision being framed (keystone-framing.md) and then a spike proving the decision was buildable (keystone-spike-scope.md, keystone-spike-results.md). Both are done. The spike proved all six of its proof items against real evidence, backed by 69 automated tests, at a real, lived cost of ~25 hours. This document is what comes after: turning a proven spike into an actual product plan, scoped to what Keystone needs to become — not just what it was built to prove was possible.

Full production tier, by explicit decision, 2026-09-06. Pete chose to scope this BRD (and the paired PRD/SAD) against the complete production-tier vision — MFA, rate-limiting, audit logging, session revocation, the admin app's identity-administration surface — rather than stopping at the narrower "ready to use" bar. The sequencing already settled in keystone-framing.md §8 (Waypoint and Relay adopt first, RoundTrip migrates last, once there's real production mileage) is unchanged by this — planning for the full tier now doesn't mean building all of it before anything ships.

What changed to make this the right time: Command Center's GET /v1/entitlements is now live, real, and tested (command-center-framing.md §8, done 2026-09-05) — the one dependency Keystone's entitlement delegation needed and didn't have when the spike stubbed it as a hardcoded "yes." That gap is now closeable for real, not just in theory.


Executive Summary​

Keystone is the identity backbone of the Traxs Group platform — a self-hosted, OpenIddict-based service that owns credentials (a password hash or a linked external identity) and a stable person ID, shared across RoundTrip, Waypoint, and Relay. It is not a customer-facing product. It has no UI beyond its own login/registration/account-recovery pages. It is infrastructure, in the same sense Command Center is infrastructure — the thing that makes three independent products share one login instead of three.

Keystone replaces RoundTrip's current dependence on Azure Entra External ID, which has two confirmed, real bugs (TRA-384, TRA-389) rooted in a structural property of Entra's global identity graph, not anything fixable at the application layer alone. Keystone's core architectural principle, proven in the spike: Microsoft's token proves who; Keystone's own data decides what. Entra becomes one optional federation choice ("Sign in with Microsoft"), never the required default path.

Entitlement — which products a person can actually reach — is explicitly not Keystone's own data. Keystone delegates that question to Command Center on every check, per the three-piece split settled in keystone-framing.md §9: Keystone owns who, Command Center owns what they're allowed to reach and what they're paying for.


Problem Statement​

The Cross-Tenant Collision Problem​

Entra External ID is not a standalone product — it's Entra ID wearing a consumer-facing hat, still fundamentally part of Microsoft's broader identity graph. Two real, confirmed bugs follow directly from this:

  • TRA-384 — registration fails outright if a prospect's email already has any Entra identity (a real M365 account under that address), because ProvisionTenantJob used the guest-invitation path.
  • TRA-389 — even a completely fresh email fails differently: if the domain is verified anywhere on a real Microsoft tenant, Entra's Home Realm Discovery redirects the user to authenticate against that tenant's real credentials instead of RoundTrip's own login — a prompt that looks like a legitimate Microsoft login, which makes the failure mode worse than an obvious error.

Both tickets are closed via a near-term fix (CreateMemberUserAsync, verified empirically). That fix protects RoundTrip today. It does not answer whether Entra is the right long-term foundation for a three-product platform, since the underlying cause — Entra's cross-tenant recognition, a genuine feature from Microsoft's perspective — doesn't go away.

The Multi-Product Entitlement Problem​

RoundTrip, Waypoint, and Relay are each independently subscribable. A customer might have RoundTrip alone, RoundTrip and Relay, or all three. "Shared login" therefore cannot mean "one login, same access everywhere" — it has to mean one identity, with per-account, per-product entitlement determining what that identity can actually reach. No existing system does this today; each product would otherwise reinvent it.

The Centralization-Risk Problem​

Today, if RoundTrip's Entra integration has a problem, Waypoint is completely unaffected — they're independent systems. A single Keystone service becomes a single point of failure for the entire platform at once: an outage or a security flaw doesn't degrade one product, it takes down or exposes all of them simultaneously. This is not a reason to avoid building it — most successful multi-product platforms are built exactly this way — but it means the bar for "done" is materially higher than for any one product's auth today, and that bar needs to be explicit rather than assumed. Section 5 sets it out in tiers for exactly this reason.


Business Objectives​

ObjectiveMetricTarget
Eliminate the Entra cross-tenant collision class of bug platform-wideZero HRD-redirect or guest-collision incidents across any productOngoing, from Keystone's first real cutover
One login across all subscribed productsA customer with 2+ products authenticates once, reaches all of themReady-to-use tier
Real entitlement delegation to Command CenterEvery product access decision reflects live subscription state, not a stubReady-to-use tier — unblocked 2026-09-05
Nobody permanently locked outA working, tested password-reset flowReady-to-use tier
Stable person ID other products can build againstRoundTrip and Waypoint FK-compatible with zero structural changesProven in spike (2026-08-22)
Meaningful defense against credential-stuffing / brute-forceTwo-layer rate limiting — a moderate per-IP limit plus a stricter per-account lockout after repeated failures, regardless of source IP (§8 item 3, confirmed direction, specific numbers still open)Production tier
A real second factor availableMFA via TOTP (authenticator app), confirmed as the method (§8 item 1); enrollment trigger (mandatory/optional/tenant-admin-controlled) still open, flagged for real discussionProduction tier
Every security-relevant action is traceableAudit log covering login, password change, account linking/unlinking, admin actions, retained 1 year minimum (§8 item 2, confirmed)Production tier
A compromised session or token can be killedReal session/token revocation — both self-service ("log out everywhere") and admin-app action (§8 item 5, confirmed)Production tier
The platform's identity layer is administrable without touching a database directlyAdmin app can view/search accounts, unlink external logins, force password reset, view audit logProduction tier
RoundTrip's eventual cutover doesn't cost a single customer their accessTested account-recovery flow, rollback path, user communication ready before cutoverRoundTrip migration gate (keystone-framing.md §8)

Stakeholders​

RolePerson / SystemInterest
Owner / ArchitectPete CarrollAll decisions
COO / CMORobin CarrollAll descisions
Consumer: RoundTripRoundTrip APIMigrates last, per the settled rollout sequencing; carries the only real customer-facing migration risk
Consumer: WaypointWaypoint APIAdopts early — real technical Entra dependency to unwind, but zero paying customers to disrupt
Consumer: RelayRelay API (not yet built)Builds against Keystone from day one — no legacy Entra dependency to migrate away from
Dependency: Command CenterCommand Center APIKeystone calls Command Center's GET /v1/entitlements on every access decision; Keystone owns no entitlement data itself
Consumer: Admin AppThe unified admin app (not yet built)Identity administration (account search, unlink, force-reset, audit log) — authenticated through Keystone itself, per keystone-spike-scope.md §1
External dependency: Microsoft EntraOptional federation provider"Sign in with Microsoft" only — never the required default path

Scope​

Proven in the spike (2026-08-22 through 2026-09-01) — not a plan, already built and tested​

CapabilityStatus
OpenIddict token issuance, full interactive authorization-code flow✅ Proven — genuine encrypted tokens, spec-correct rejection on bad credentials
Email/password registration and login✅ Proven
Optional Entra federation ("Sign in with Microsoft") against a real app registration✅ Proven against real Microsoft infrastructure
ExternalLogins linking — all three cases (already-linked, existing-account conflict, brand-new registration)✅ Proven, with guardrails: verified-email-required linking, no silent auto-merge
Stable person ID, FK-compatible with RoundTrip's TenantUsers/Technician✅ Confirmed against real RoundTrip source, zero structural changes needed
Same FK pattern against Waypoint's WaypointUsers✅ Confirmed against real Waypoint source, genuinely simpler than RoundTrip's case

69 automated tests back this. This is spike-quality code proving mechanics work, not production-hardened infrastructure — see Section 5.2 for what closes that gap.

Ready-to-use tier (needed now — the actual next work)​

CapabilityWhy it's needed now
Real password reset flowThe spike's own named gap against keystone-framing.md §8's "ready to use" floor — "nobody gets permanently locked out." Not built at all today.
Real entitlement delegation to Command CenterThe spike stubbed this as a hardcoded "yes." Command Center's GET /v1/entitlements is now live and tested — this is a real integration to build, not a design question.
Harden the spike codebase into a deployable serviceThe spike proved mechanics on a demo project. A real service needs real configuration management, real secrets handling (Key Vault, not local appsettings), real logging, and a real deployment pipeline — none of which was in the spike's scope.
Basic input validation and error handling to production standardMatches the pattern already established in Command Center (ValidationBehavior, GlobalExceptionMiddleware) — Keystone should follow the same Clean Architecture conventions RoundTrip and Command Center already use.

Production tier (planned now, built incrementally — per Pete's 2026-09-06 scope decision)​

CapabilityDescription
Multi-factor authenticationTOTP (authenticator-app) as the baseline second factor. See PRD for the specific proposed flow — this is a genuine design proposal, not yet a settled decision.
Rate limiting / brute-force protectionLogin and password-reset endpoints specifically — the endpoints Entra currently protects for free that a self-hosted system has to build itself.
Real audit loggingEvery security-relevant event (login success/failure, password change, external-login link/unlink, admin action) — who, what, when, from where.
Session / token revocationA compromised refresh token or session must be killable on demand, not just left to expire naturally.
Uptime monitoring and alertingGiven Section 2.3's centralization risk — an identity outage takes the whole platform down, so it needs the platform's most aggressive monitoring, not its least.
Tested backup/recovery for the credential storeThe one dataset where "restore from yesterday's backup" is not an acceptable answer to "we lost the database."
Admin app — identity administration surfaceAccount search, view linked external logins, force a password reset, unlink an external login, view a user's audit trail. This is the Keystone-facing half of the admin app named in keystone-spike-scope.md §1 — the Command Center-facing half (ops/financial dashboard) is tracked separately in command-center-framing.md §8.

RoundTrip migration (separate, gated, last — per keystone-framing.md §8)​

Not "ready to use" or "production tier" scope — a distinct, time-sensitive, one-time cutover with its own explicit gate: a tested (not just built) account-recovery flow, a real rollback path, and the "set up your new login" user communication designed and ready. RoundTrip has real customers today; this is the one migration where a mistake costs an actual customer, which is exactly why it's sequenced last, after Waypoint and Relay have given Keystone genuine production mileage under real (if lower-stakes) traffic.

Explicitly out of scope for Keystone itself​

  • Entitlement data. Keystone never stores which products a tenant is entitled to, what tier they're on, or pricing. That's Command Center's data, queried live on every check.
  • Product-specific user data. RoundTrip's TenantUsers/Technician, Waypoint's WaypointUsers — all stay exactly where they are, referencing Keystone's person ID by FK. Keystone never becomes a shared user-profile table.
  • Billing. Not Keystone's concern at any tier — Command Center's, per the three-piece split.

Non-Functional Requirements​

RequirementTargetRationale
Availability99.9% uptime (production tier)Higher than Command Center's 99.5% — Keystone is a harder single point of failure: every product's every request depends on a valid token, not just cross-product data sharing.
Response time< 300ms for token issuance and validationAuth checks happen on effectively every authenticated request across every product — this is the platform's hottest path.
Security — password storagePBKDF2-HMAC-SHA256, 600,000 iterations, per current OWASP guidance — proven in spike, matching the real implementationNo ASP.NET Core Identity is in use (per keystone-external-login-proposal.md's stated constraint), so this is Keystone's own responsibility to get right, not inherited from a framework — and it already has been, tested.
Security — token lifetimeShort-lived access tokens, longer-lived refresh tokens, both revocableStandard OAuth2/OIDC practice; revocability is what Section 5.3's session/token revocation requirement actually depends on.
Security — transportTLS everywhere, no exceptions, including local dev where feasibleThe Entra-federation callback flow already surfaced a real cross-site cookie/HTTP interaction during the spike (keystone-spike-results.md §3) — this is a real, not theoretical, risk class.
Audit log retentionConfirmed: 1 year minimumMatches PCI-DSS's own 1-year minimum — a genuine industry floor, not a compromise. May warrant a per-customer exception later if a future customer's own regulatory obligations require longer retention (§8 item 2).

Constraints​

  • No ASP.NET Core Identity. The spike and the external-login-proposal it's built on both deliberately avoid it, matching RoundTrip's own existing pattern (FastEndpoints, Clean Architecture, no ASP.NET Core Identity). Password hashing, session management, and account linking are Keystone's own code, not inherited from a framework.
  • Same Clean Architecture as RoundTrip and Command Center — Core/UseCases/Infrastructure/Web, FastEndpoints + Cyrus Mediator. Any Traxs developer should be able to navigate this codebase immediately.
  • Solo developer, evenings-and-weekends pace. The spike's own ~25-hour, 11-session cost is the honest baseline for what "one more real feature" costs at this pace — production-tier items should be scoped with that same honesty, not planned as if a team were building them.
  • Never a shared schema with any product. Keystone's own database holds only credentials, external-login links, and the person ID — nothing product-specific, ever.
  • Never silent account merging. Proven in the spike and non-negotiable going forward: linking an external login to an existing account requires a verified email and an explicit confirmation step — never an automatic merge based on matching email alone.
  • RoundTrip's TenantUser/Technician split stays structurally incapable of cross-resolving, even after Keystone is in place — a technician and a tenant user sharing an email must never resolve to each other's record via any login path.

Open Notes — needs Pete's confirmation, not yet settled​

  1. MFA enrollment policy — TOTP confirmed as the method (2026-09-XX). Enrollment trigger still genuinely open: leaning toward tenant-admin-controlled opt-in (a TenantAdmin enables MFA requirement for their own tenant) rather than platform-wide mandatory or fully optional — explicitly flagged by Pete as needing real discussion, not a settled decision. Real architectural dependency this surfaces: Keystone has no tenant concept of its own; a tenant-scoped "require MFA" setting would need to live in Command Center and be communicated to Keystone the same way entitlement claims are, not something Keystone can see directly.

  2. Audit log retention: confirmed at 1 year (2026-09-XX). Matches PCI-DSS's own 1-year minimum standard — a genuine industry floor, not a compromise. Worth revisiting on a per-customer basis if a future customer's own regulatory obligations (healthcare, finance, government) require longer retention — not a platform-wide change, a possible per-tenant exception.

  3. Rate-limiting thresholds — still open, refined. Pete's instinct that Command Center's 10/minute/IP reference point is too lenient for an auth platform is correct, but pure per-IP limiting has a real weakness worth designing around: office networks put many legitimate users behind one shared IP, and a strict IP-only limit risks locking out multiple real employees at once. Proposed direction: a two-layer approach — a moderate per-IP limit (5-8/minute, looser than a pure "high-security" number to tolerate shared-office IPs) combined with a stricter per-account lockout/backoff after repeated failures on that specific account regardless of source IP. Specific numbers still need to be set.

  4. Registration policy: confirmed (2026-09-XX). Self-serve for a brand-new tenant's first user; invitation-only for every subsequent user added to an existing tenant — matching RoundTrip's own real, already-built pattern (ProvisionTenantJob for the first user, CreateMemberUserAsync for team invites) exactly. New open question this surfaces: self-serve tenant registration is really two coordinated operations — a new Keystone User and a new Command Center tenant/subscription (including product/tier selection, which is Command Center's data, not Keystone's, per Section 5.5). Whether Keystone's own bare /account/register page is replaced by a real, RoundTrip-hosted signup experience that orchestrates both calls is a genuine open design question, not yet settled.

  5. Session/token revocation: confirmed (2026-09-XX). Both a self-service "log out everywhere" account action and an admin-app action — not either/or.


Document History​

VersionDateAuthorChanges
1.0September 2026Pete CarrollInitial BRD — Keystone's first, written once the OpenIddict spike proved the approach and Command Center's real entitlement endpoint removed the one hard dependency blocking Keystone's "ready to use" tier. Scoped against the full production tier per Pete's explicit 2026-09-06 decision.