Publish the Management API reference, guides and Terraform docs - #393
Merged
Merged
Conversation
Splits the /api section into two APIs and documents the Management API
end to end.
The section now forks at /api into:
Management API the Phase Two control plane. Clusters themselves.
Generated from openapi-management.yaml, a build
artifact of phasetwo-keycloak, into api/management/.
Extensions API Phase Two's additions to the Keycloak Admin REST API,
served from the customer's own realm. Unchanged.
The Extensions API's 84 endpoint pages stay at the top of api/ rather
than moving under api/extensions/. Those URLs are published and indexed,
and relocating them to gain symmetry with the new section would break
every inbound link. The new API gets the nested path instead.
Three hand-written pages carry the framing the generated reference
cannot: /api explains which API a reader wants and that they target
different servers with different credentials, and each section has a
preamble covering its host, its authentication and its conventions. Both
APIs use the word "extension" for different things -- uploaded jars
versus our Keycloak additions -- so that collision is called out
explicitly where the two sit adjacent in one sidebar.
New guide section under docs/management-api:
index what it is, and the control-plane/realm split
api-keys creating a secret, the client-credentials exchange, least
privilege, rotation, and a troubleshooting table
recipes seven worked end-to-end examples
terraform the p2-inc/phasetwo provider
The guides lead with the two-hostname model, since authenticating
against app.phasetwo.io and then calling api.phasetwo.io is the single
most common source of confusion, and they state the asynchronous
provisioning, restart serialization and deferred-delete behaviours up
front rather than leaving them to be discovered.
The Management API's sidebar is generated rather than hand-maintained:
scripts/gen-management-sidebar.mjs converts the plugin's TypeScript
output to CommonJS (this repo has no TypeScript toolchain), maps
lowercase OpenAPI tag names to display labels, strips trailing periods
from summary-derived labels, and retitles the tag landing pages from the
spec's tag descriptions. Wired into regen-api-docs, so a spec refresh
carries all of it.
Also extends the RFC 9727 linkset to all four spec documents and both
reference pages, which the overview page now claims.
Two draft blog posts, dated to publish across one week and marked
draft: true so they stay out of production builds until flipped.
Deploying phasetwo-docs with
|
| Latest commit: |
ba9f33c
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://98169fa8.phasetwo-docs.pages.dev |
| Branch Preview URL: | https://management-api-docs.phasetwo-docs.pages.dev |
Four changes, all consequences of the API host going live.
Re-vendors openapi-management.yaml from phasetwo-keycloak. The spec is
now version 2.0.0 rather than 1.0.0 -- the provider is mounted at /v2, so
the old number contradicted every path in the document -- and lists the
API host first, since it now resolves in both environments. It also
carries a second security scheme for staging, because tokenUrl takes no
server variables and so a staging caller cannot retarget the token
endpoint from the server selector alone.
Fixes the links to the spec files, which 404ed. A plain /openapi.yaml in
MDX is treated as a file asset, rewritten to a hashed /assets/files/...
path, and then given a trailing slash by trailingSlash: true -- and the
slashed form does not exist:
/assets/files/openapi-0796....yaml/ 404
/assets/files/openapi-0796....yaml 200
pathname:// opts out of both the asset pipeline and the router, so the
literal static path survives. This was already broken on the live site,
not introduced here. A comment records why, since the prefix reads like
something to tidy away.
Points the "API" entries in the navbar, the Developers submenu and the
footer at the section root rather than at the Extensions API's generated
introduction, and retitles the submenu to "Phase Two Management and
Extensions APIs". /api/ now forks between two APIs, and the fork page is
what tells a reader which one they want.
Adds a .prettierignore. Prettier rewrites MDX expression comments --
{/* ... */} becomes {/_ ... _/} -- which does not compile, so `pnpm fmt`
breaks the build on any MDX file carrying one. It bit twice while writing
this; now it cannot.
pnzrr
approved these changes
Sep 16, 2026
This was referenced Sep 18, 2026
* Document the Keycloak provider credential handoff The Terraform page told people to point the Keycloak provider at the cluster with client_id = "admin-cli" and a "# ..." where the credentials go, which is not something anyone can act on. Replaces it with the real path: create a per-realm credential with deployment.credential.create, and the response carries every field the Keycloak provider needs. Covers listing and revoking, why a credential per holder is worth the small extra effort, and the fact that the secret lands in terraform.tfstate in plain text -- true of any provider credential, but this one is realm-admin, so the state backend inherits that sensitivity. Depends on the endpoints in p2-inc/phasetwo-keycloak#692. * Require initial_login = false on the Keycloak provider handoff The provider authenticates when Terraform configures it, which happens during plan. A configuration that creates the cluster and configures inside it in one go therefore fails at plan time against a cluster that does not exist yet -- so the example as written only worked if the cluster already existed. Measured against Terraform 1.14.7 and keycloak/keycloak: without the flag, plan fails with "failed to perform initial login to Keycloak: 401"; with it, plan succeeds and the login is deferred to first use. Also notes that the manual credential step is interim. The same flag is what makes a phasetwo_realm_credential resource viable -- a provider configured from a resource created in the same apply, which is normally a dead end, works with the login deferred, destroy ordering included. * Document credential names and role scoping The credential endpoint now takes a name and a set of realm-management roles, so the page needs to say what those are and when to narrow them. Client ids are api-{name}-{uuid} rather than terraform-{uuid}: the endpoint is for any service account on the realm, not only Terraform, and the marker attribute rather than the prefix is what identifies one as ours. Includes the full role table, because "narrow the roles" is not actionable without knowing what the roles are, and a caution that too-narrow surfaces as a 403 partway through an apply rather than up front -- unlike a misspelled role, which is now a 400 at creation. * Stop telling people the credential secret cannot be read back It can. The secret lives in the customer's realm and they hold realm-admin there, so it was always readable from Keycloak directly; #695 adds deployment.credential.secret.read so it is reachable through our API too, and reading does not rotate it. The old wording had a cost. Telling people the create response was their only chance is what pushed the secret into terraform.tfstate, which is exactly the place a realm-admin credential should not be. Now points at fetching it on demand, and at the ephemeral-resource approach that keeps it out of state entirely. * Document the one-apply Terraform handoff phasetwo_realm_credential and its ephemeral secret now exist, so the page can stop describing the curl steps as the way to do it and show the declarative version instead. The curl route stays for people not using our provider. Spells out why both of the odd-looking lines are there, because both are the kind of thing a reader would otherwise delete as noise: ephemeral keeps the secret out of terraform.tfstate, which matters because Terraform writes every resource attribute to state and this credential holds realm-admin. That is also why the resource has no client_secret attribute at all. initial_login = false is needed for two separate reasons, and the subtle one is that the Keycloak provider authenticates at configure time, during plan, against a cluster that does not exist yet.
xgp
added this pull request to stack #406
September 18, 2026 17:35
xgp
added a commit
to p2-inc/terraform-provider-phasetwo
that referenced
this pull request
Sep 18, 2026
* Write a real provider overview for the registry The registry's Overview tab renders docs/index.md, which was tfplugindocs' stock template: the schema description, one example, and the argument list. Someone landing there learned what the arguments are called and nothing about what the provider is for or where to read more. Adds templates/index.md.tmpl, which is how that page is controlled -- the generated docs/ is output, so editing it directly is undone by the next `make docs` and CI's "generated files are up to date" job catches it. Covers what a first-time reader needs and cannot get from the schema: - what Phase Two is, and that this is the Terraform front end to the same OpenAPI document that generates the API reference - how authentication works, and that organization roles are enforced per operation so a view-only secret is real rather than decorative - the realm-credential handoff to the Keycloak provider, which is the one thing here that is not obvious and not generally possible in a single apply - four behaviours that are expensive to discover mid-apply: cluster arguments all force replacement, destroy is deferred and holds the name, config changes restart Keycloak, custom domains need two applies - a link table back to the guide, the API reference, the recipes, the extension docs, the repo and the console Every link checked. phasetwo.io/docs has no index -- /docs/introduction is the entry point. The four /docs/management-api/* and /api/management-api-index links 404 today because those pages are in p2-inc/phasetwo-docs#393, #394 and #405; they are confirmed present in that branch's build. Only docs/index.md changes -- the template leaves the other 16 generated pages untouched. * Mark the provider experimental, test environments only It is 0.1.0, the acceptance tests have never run against it, and the resources it manages are real and billable -- replacing a phasetwo_cluster destroys it and every realm on it, and destroying one keeps billing and holds the name until the end of the billing cycle. Someone reaching for this on a production estate should be told before they apply, not after. Three places, because each has a different first reader: - templates/index.md.tmpl, which renders the registry Overview tab. Uses !> rather than the ~> this repo uses elsewhere: the registry renders that as its strongest callout, and "do not point this at production" earns it. - README.md, for anyone arriving from the source link. - docs/index.md is regenerated, not hand-edited. Matching notices are going into the customer docs and the launch post.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Splits
/apiinto two APIs and documents the Management API end to end — reference, guides, Terraform provider, and two draft launch posts.Depends on p2-inc/phasetwo-keycloak#667, which fixes three spec defects that this surfaced; the vendored spec here already includes them.
The
/apifork/apinow forks into two sections:openapi-management.yaml→api/management/openapi.yaml→api/The Extensions API pages did not move. Those 84 endpoint URLs are published and indexed, and relocating them under
api/extensions/purely for symmetry with the new section would break every inbound link. The new API takes the nested path instead. Spot-checked/api/get-organizations,/api/create-organizationand/api/phase-two-admin-rest-apiin the build output — all unchanged.Three hand-written pages carry the framing a generated reference can't:
/api— which API you want, that they target different servers, and that a token for one is useless to the other/api/management-api-index— host, auth, conventions, and the asynchronous/restart/deferred-delete behaviours/api/extensions-api-index— the previous/apicontent, rehomedOne thing worth a look: both APIs use the word "extension" for different things. In the Management API an
extensionsendpoint manages a jar or theme you upload; in the Extensions API it means our additions to Keycloak. They now sit adjacent in one sidebar, so I named the Management category "Cluster Extensions" and called the collision out explicitly on the overview page.New guide section:
docs/management-api/indexapi-keysrecipesterraformp2-inc/phasetwoproviderThese lead with the two-hostname model — authenticate against
app.phasetwo.io, callapi.phasetwo.io— because that is the single most common source of confusion, and they state the asynchronous provisioning, restart serialization and deferred-delete semantics up front rather than leaving them to be discovered on a Friday.The Management sidebar is generated, not hand-maintained
api-sidebar.jshand-maintains the Extensions API's 12 categories. Doing the same for 73 more entries would rot immediately, soscripts/gen-management-sidebar.mjsderives that half from the spec and is wired intoregen-api-docs. It:api-sidebar.jsis CJS)ip-rules→ IP Rules — with a de-kebab fallback so a new upstream tag degrades gracefully instead of breaking the buildAlso
Extended the RFC 9727 linkset at
/.well-known/api-catalogto all four spec documents and both reference pages — the overview page claims that, so it needed to be true.Blog posts
Two, dated to publish across one week, both
draft: trueso they stay out of production builds until you flip them:I went with two rather than three: API keys don't stand alone as a post (they're only interesting as the way into the API), so they're the second act of post one. The Terraform provider is a genuinely different audience and use case, so it gets its own. Both cross-link, and the second opens by referring back to the first.
Test plan
pnpm build— passes, zero broken links/api, both section preambles,/api/management/clusters,/api/management/org-api-secret-create, and all fourdocs/management-api/*prettier --checkclean on every file I touchedregen-api-docsexercised end to end:clean-api-docs→gen-api-docs→ sidebar conversionTwo things to flag
pnpm fmtwill corrupt MDX comments. Running prettier overapi/index.mdxrewrote{/* … */}into{/_ … _/}— it parsed the*as emphasis — which broke the MDX compile. I hit this and reverted it. The repo is already 781 files away from prettier-clean, sofmtis presumably never run wholesale; worth knowing before someone tries. I formatted only my own files.The spec's default server is still the console host.
openapi-management.yamllistshttps://{environment}.phasetwo.io/auth/realms/self/v2first andhttps://api.phasetwo.io/v2second, because the API host isn't live until p2-inc/phasetwo-infra#350 ships. The prose throughout these docs describesapi.phasetwo.ioas the API base, per the intended end state. Once #350 is deployed, swap the server order upstream and re-vendor — the docs won't need to change.