Architecture¶
Packages¶
.
├── packages/
│ ├── api/ # Backend API (Express + TypeScript) — the management API and the
│ │ # emulated OIDC/pi.flow engine
│ ├── admin-ui/ # Admin Portal (React + Vite) — manage organizations platform-wide
│ ├── org-ui/ # Organization Portal (React + Vite) — an organization manages its own
│ │ # environments
│ ├── mcp/ # Read-only MCP server exposing the API to Claude Code / Claude Desktop
│ ├── agent/ # Mastra-based conversational CLI built on packages/mcp
│ └── pf-signon-ui/ # A PingFederate-style / PingOne-style sign-on demo UI
packages/api is a Postgres + Prisma backend. Some migrations are hand-written SQL rather than
Prisma-generated: the dev database is shared with other services, so a schema-diffing Prisma command
can propose dropping tables that don't belong to this project at all.
Two API surfaces¶
The management API (/v1/...) — environments, applications, populations, sign-on policies,
identity providers, DaVinci flows, schemas, gateways, and more. Shaped to match the
PingOne Terraform provider
so real pingone_* Terraform resources work against it unmodified — this is what every
terraform/* module in this repo provisions against.
The emulated OIDC/authorize surface (/:environmentId/as/authorize, /:environmentId/flows/:id,
/:environmentId/token, etc.) — the actual sign-on experience: pi.flow interactive authentication,
token issuance, and OAuth2 client authentication. See The pi.flow Protocol.
Pluggable auth-flow providers¶
Every environment picks which engine handles its own authorize/flows/token calls, via
metadata.authProvider on the pingone_environment resource (packages/api/src/lib/authFlow/):
emulated(the default) — a fully in-house implementation of thepi.flowprotocol (emulatedProvider.ts): username/password, self-registration, MFA, and WebAuthn/passkey ceremonies, all real working state machines rather than static mocks.pingfederate— delegates to a real PingFederate instance (pingFederateProvider.ts) running in this environment's own Docker setup, for cases where the real product's behavior matters more than a fast, dependency-free emulation.
Both implement the same AuthorizationFlowProvider interface
(packages/api/src/lib/authFlow/types.ts), so callers (routes/v1/token.ts, routes/v1/flows.ts)
never branch on which engine is active — getAuthorizationFlowProvider(environmentId) resolves it
once per call and both are transparently wrapped with audit logging
(packages/api/src/lib/auditStore/).
Real backing services, not just mocks¶
Where the real product's own behavior is what matters, this repo runs the real thing rather than
reimplementing it: PingFederate and PingDirectory containers back specific environments and
capabilities (see .pingfederate/, .pingdirectory/ — both gitignored, local container
provisioning state). This is why some setup docs talk about "server profiles" and container
provisioning rather than pure application config.
DaVinci flows¶
packages/api/src/lib/davinci/ handles DaVinci-flow-shaped configuration — flows are modeled as a
graph (graphToFlowDefinition.ts) and can be synced against a real flow-execution engine
(authrFlowSync.ts) in the separate atlassian-adf-form-r repo, which hosts the actual DaVinci
Hosted Login experience for flow-driven demos.
MCP server and agent¶
packages/mcp is a read-only MCP server exposing the management
API as tools (environments, applications, users, sign-on policies, DaVinci flows, token
introspection, a monitoring summary, and a generic api_get escape hatch), intended for
conversational dev/ops introspection from Claude Code or Claude Desktop. packages/agent is a
Mastra-based CLI that talks to a running instance through those same MCP tools.
Both are read-only by construction: only read tools exist, the underlying HTTP client has no write
method, and the recommended credential is a seeded viewer account the API's own
organizationAdminMiddleware would 403 on any write regardless.