feat: ask for the login design in the setup wizard - #750
Conversation
The wizard's final question offers the five starter designs with the built-in template preselected; picking one ejects it into .zitadel/branding/ and publishes branding revision 1 during setup, matching the existing --design flag (which now skips the question). The choice lands in the summary box, the JSON envelope (data.design, null for built-in), telemetry, and the retry hint, and next_actions now point at the branding workflow in both cases. Adds a docs page presenting the starter designs, per-design asset usage, and the eject -> edit -> plan/apply loop (#676).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 5277d23 The changes in this PR will be included in the next version bump. This PR includes changesets to release 20 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Pull request overview
This PR extends the zitadel setup wizard to capture an optional starter login design choice (or keep the built-in template), then threads that choice through setup output surfaces (summary box, JSON envelope, telemetry, retry guidance) and docs so agents/users can discover and continue the branding workflow.
Changes:
- Add a final setup-wizard prompt to choose Built-in (writes nothing) or eject one of five starter designs into
.zitadel/branding/and publish revision 1 (with--designskipping the prompt). - Surface the selected design via
data.designin the JSON envelope, an extranext_actionsguidance line, updated setup summary output, and updated setup telemetry dimensions. - Add docs page
docs/cli/customize-designand update the envelope-contract scanner to map topic commands likebranding ejecttobranding:eject.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/docs/content/docs/cli/meta.json | Adds the new customize-design doc page to the CLI docs nav. |
| apps/docs/content/docs/cli/customize-design.mdx | Documents starter designs, ejecting, asset rules, and the plan/apply revision loop. |
| apps/cli/tests/unit/commands/setup/prompts.test.ts | Adds unit coverage for the new DesignPrompt behavior. |
| apps/cli/tests/integration/setup-next.test.ts | Adds integration coverage for data.design and --design eject/publish behavior. |
| apps/cli/tests/integration/contract.test.ts | Updates command-id extraction to understand topic commands suggested with spaces. |
| apps/cli/src/lib/journey-guidance.ts | Adds branding guidance text that varies depending on whether a design was ejected. |
| apps/cli/src/commands/setup/prompts/types.ts | Extends SetupAnswers/PromptContext with design and designFromFlag. |
| apps/cli/src/commands/setup/prompts/index.ts | Registers DesignPrompt as the final wizard prompt and exports it. |
| apps/cli/src/commands/setup/prompts/design.ts | Implements the design selection prompt with a built-in sentinel option. |
| apps/cli/src/commands/setup/index.ts | Wires design through flags → prompts → telemetry → retry options → summary + JSON envelope. |
| apps/cli/AGENTS.md | Updates documented setup telemetry dimensions to include preset/use_case/design. |
| .changeset/setup-design-question.md | Ships a minor changeset for @zitadel/cli describing the new setup design question. |
| const value = await select({ | ||
| message: | ||
| "How should the login look? A starter design adds its editable template to .zitadel/branding/.", | ||
| initialValue: (answers.design as string | undefined) ?? BUILT_IN, |
| { value: "centered", label: "Centered", hint: "card centred on the page" }, | ||
| { value: "split", label: "Split", hint: "brand panel left, form right" }, | ||
| { value: "split-right", label: "Split (right)", hint: "form left, brand panel right" }, | ||
| { value: "hero", label: "Hero", hint: "landing-style brand pane left, form right" }, |
fforootd
left a comment
There was a problem hiding this comment.
Two additional findings are inline.
Separate current blocker: full-pr fails because the cli scope is not allowed by .github/semantic.yml. Please rename this to an accepted title such as feat: ask for the login design in the setup wizard and rerun CI. The job stopped at the title check, so every build/test/journey step was skipped; the green Vercel previews do not validate the CLI test claims on this head.
| // Leading bare words form the command id; topic commands are suggested with | ||
| // a space ("branding eject") but registered with oclif's colon id | ||
| // ("branding:eject"). Flags and free text end the id. | ||
| const words: string[] = []; |
There was a problem hiding this comment.
This drops the previous support for colon-form command IDs. For example, publicCliCommand("branding:eject", ...) now produces no ID here and is silently omitted from the visibility assertion. Could we accept an already-colonized first token as well as space-separated topic words, and add focused cases for branding eject, branding:eject, and setup --force?
| install: installOutcome.install, | ||
| next_actions: installOutcome.nextActions, | ||
| // The chosen login design, or null for the built-in template — so | ||
| // agents can verify what setup published without diffing the repo. |
There was a problem hiding this comment.
Could we update apps/cli/SKILLS.md with this new setup envelope field and the interactive/--design behavior? The root AGENTS.md explicitly requires that canonical agent contract to stay aligned with CLI behavior; its setup flag list still omits --design, and its envelope section does not explain data.design or the null built-in value.
Summary
centered,split,split-right,hero,minimal— which ejects the design into.zitadel/branding/and publishes it as branding revision 1 during setup, exactly like the existing--designflag (which now skips the question). Template ownership stays an explicit opt-in: the built-in default is preselected and the option labels say that a design writes files.Login designrow), the JSON envelope (data.design,nullfor built-in), setup telemetry (designdimension, allow-listed enum), and the local-server retry hint (an interactively chosen design survives into the suggested retry command).next_actionsnow covers the branding journey in both directions: with a design, it points at.zitadel/branding/login.liquid+branding.jsonand the plan/apply loop; without one, it makesbranding ejectdiscoverable.docs/cli/customize-design): the five starter designs with per-design asset usage (onlysplit/split-rightrenderhero_url;minimaluses no assets), choosing at setup vs later, thehttps://-only asset rule, the revision model, and the ownership trade-off of ejecting. Slot for visual examples per design is a follow-up once we have screenshots.publicCliCommand("branding eject")maps to the oclif idbranding:ejectinstead of the bare topicbranding.Validation
moon run cli:test— 962/962 (includes new DesignPrompt unit tests and asetup --design splitintegration test asserting the ejected files, the inlined wire body, state pinning, and an empty first plan)moon run cli:lint cli:typecheck— clean (24 pre-existing warnings, 0 errors)moon run docs:build— cleanRelease notes / changeset
@zitadel/climinor: the setup wizard asks how the login should look; the choice is reported in the summary, JSON envelope, and retry hint.Notes
branding.jsonplusnext_actionscover it). Config-only basic branding (layout + assets without template ownership) is wire-reserved (CreateBrandingBody.layout) but the master template doesn't implement it yet — that's the proposed opener for Customise the authentication experience #678 rather than scope here.*/brandinghandlers. Adding branding tosetupPlatformHandlersis a reasonable follow-up.--forceoverwrites local edits) — tracked as its own concern, worth a ticket.