SIGN IN SIGN UP

feat(ci): init-storage-progress (#673)

* feat(init): show progress while waiting for storage to sync

Cloud KV backends are eventually consistent: the encryption key written during
setup may not be readable immediately, so an instant redirect to login could
fail with a wrong-password error ("works after a while").

Changes:
- Poll /public/init_status until the backend reports ready (the encryption key
  is readable from its real source), showing a progress bar and status text.
- Redirect to login only after readiness, or after a 30s timeout with a warning
  to retry.
- Add init i18n keys in src/lang/en (source language; other locales are synced
  by Crowdin).

* fix(init): skip storage-readiness wait on Go backend

The readiness poll depends on the `ready` field of `/public/init_status`,
which is TS Worker-specific. The Go backend only returns `initialized`, so
`ready` was always undefined there, forcing a pointless 30s wait followed by
a misleading "storage sync timed out" warning.

Guard the wait with isTsWorker(): Go uses strongly-consistent storage
(MySQL/SQLite) with no propagation delay, so it proceeds immediately.

Backend detection is safe here because App.tsx awaits /public/settings
(which calls setBackendKind) before rendering any route.

* feat(init): show environment readiness before setup

Consumes the new TS Worker /public/env_check endpoint to display, above the
setup form:

- storage format and driver as configured, and how they resolved
- runtime kind (serverless vs local/container)
- storage and JWT secret readiness, each as Ready / Not ready
- an issue list with per-issue messages and links to the docs

Setup is blocked while the environment is not ready, so users fix the
configuration (DB_DRIVER, bindings, JWT_SECRET) instead of initializing into
a half-working state. The panel only renders on the TS Worker backend, since
Go reports no such endpoint.

* feat(init): turn setup into a three-step wizard

Restructure the initialization page into three explicit steps:

1. Environment - the env_check panel, with a Re-check button. "Continue" is
   disabled until the environment is ready (or immediately on Go, which has
   no env_check endpoint and skips the panel).
2. Admin account - username / password / confirm / site title, plus a Back
   button to return to step 1.
3. Progress and completion - after submit, shows a spinner + indeterminate
   progress bar through the creating and syncing phases, then a success
   state with the admin username and the site URL, and two actions:
   "Open home page" and "Go to login".

On failure the wizard returns to step 2 so the user can correct and retry.
Adds a step indicator at the top and the matching i18n keys.

* fix(init): do not report success until the backend confirms readiness

Previously a readiness timeout still advanced to the success screen, so a
user could be told initialization finished while the backend was not yet
able to decrypt (eventual consistency on KV). Split the terminal states:

- done: only after /public/init_status reports ready.
- timeout: shows a "still syncing" state with a Retry action (re-polls
  readiness without recreating the account) and a Go-to-login escape hatch.

Adds the matching i18n keys.

* fix(init): guide users to setup when storage is unavailable

When the worker has no storage configured, the backend returns 503 with
data.error = STORAGE_CONFIG_ERROR for every persistence-dependent API.
Previously the frontend could not react to this:

- request.ts dropped the backend response body, so all 503s looked alike
  and the specific error code was unreachable.
- App.tsx ignored the init_status failure, leaving initialized at its
  default 	rue, so the guard never redirected to /@init.
- /public/settings also fails, so setBackendKind() was never called and
  isTsWorker() fell back to false, silently skipping the env check.
- The init page's onMount redirected to /@login on any non-200, bouncing
  the user back out of the very page meant to fix the problem.

Changes:
- request.ts: pass through the backend message and data payload.
- backend.ts: add markTsWorker() to infer the backend kind from a
  TS-only error code, gated on backendResolved so /public/settings still
  wins when available.
- App.tsx: route STORAGE_CONFIG_ERROR into the setup wizard instead of
  the generic error screen; other 503s keep the existing behaviour.
- init/index.tsx: stay on the wizard when the init state cannot be
  determined, parse the backend storage message into a structured
  reason + actionable tips panel, and keep the raw text in a collapsible
  detail. Skip the env-check step entirely on the Go backend, which has
  neither the endpoint nor the problem.

Go backend behaviour is unchanged.

* refactor(init): shorten the storage unavailable notice

Dumping the parsed backend message produced a wall of text: the tips list
repeated what the collapsible raw view already showed, and the backend
message is terminal-oriented debugging material rather than something an
end user should read in full.

Replace the parsed reason + tips list with a single-line conclusion
(missing driver or environment variables) plus a link to the configuration
docs, keeping the raw text behind a collapsed details. The parser is no
longer needed and is removed.

* refactor(init): reuse the env check panel for storage errors

The dedicated storage-error block was still too heavy for what it said.
Rework it to reuse the existing environment check panel: when env_check
is unreachable (the 503 case), the storage row is simply rendered as not
ready, using the same markup as the normal path. Nothing new is invented
for the failure case.

Drop the error string signal entirely, since envCheck() being undefined
already expresses the state. Add per-platform deploy guide links at the
bottom of the panel.

* refactor(init): trim the storage-error changes

Go back over the storage-unavailable work and remove what does not earn
its place:

- backend.ts: drop isBackendResolved() and the backendResolved flag, both
  unused; markTsWorker no longer needs to respect it since /public/settings
  always resolves before the init route renders.
- App.tsx: the two 503 branches were identical, fold them into one helper.
- types/init.ts: STORAGE_CONFIG_ERROR is all the caller needs, so drop the
  StorageConfigErrorData interface and the four Partial<> intersections
  it forced. Trim EnvCheck to the fields the UI reads.
- init/index.tsx: drop the initializedUnknown signal (the panel already
  reports storage as not ready), inline showEnvStep, and remove the
  unreachable notify.error branch in goNextFromEnv.
- Add the real per-platform deploy guide URLs.

Net -83 lines.

* fix(init): always render the env panel and decouple the setup redirect

Three fixes:

1. The env panel collapsed to a single "Storage: Not ready" row whenever
   env_check was unreachable, hiding the other rows the user asked to see.
   Render the full panel with placeholders instead, so it is visible which
   items were checked and which failed.

2. The redirect to the setup wizard was driven by the storage error itself,
   so an unrelated 503 or a plain request failure left the user on the home
   page with no redirect and no error. Split the two triggers: needSetup is
   now set either by initialized === false or by an indeterminate status.

3. Restore the backendResolved gate on markTsWorker(). Settings is the
   authoritative source, so the inferred kind must not override it.

Also shorten the deploy guide labels to CF Worker / EdgeOne / ESA.

* revert(init): drop the global error-shape changes

Revert the changes to request.ts, App.tsx and backend.ts back to their
state on main.

The storage-error detection relied on reading data.error from the 503
body, which required passing the backend response body through the axios
error interceptor. That interceptor is shared by every request, so adding
a data field changed the shape of all error responses. Callers that read
.data without checking the status code first (for example
backup-restore.tsx) could then consume an error payload as if it were
normal data.

The backend already exempts the diagnostic endpoints from the storage
interceptor, so /public/init_status and /public/env_check return 200 with
structured data even when storage is unbound. Reading error codes from
503 bodies is therefore unnecessary, and the fallback backend-kind
inference built on top of it can go too.

* refactor(types): drop the unused storage error code

* refactor(init): extract the environment check into its own module

Move the env check out of the setup wizard into a sibling module so the
wizard only handles the flow it is named after.

- EnvCheck.tsx holds both the state (useEnvCheck: fetch, loading, failure
  flag, ready getter) and the panel. The panel stays presentational so the
  wizard can gate the next step on ready without owning the fetch.
- index.tsx drops the panel markup and the env-related signals, keeping
  only the step wiring.

Also drop docs/PR-init-setup-wizard.md, which should not have been
committed.

* fix(app): let the setup wizard render when storage is unbound

With no storage bound, /public/settings returns 503 and the error was
pushed into err(). That Match branch sits above the routes in the Switch,
so it won and rendered the generic error page even though the guard had
already navigated to the setup route. The user was stuck on an error
screen with no way to reach the page that fixes the configuration.

Skip err() for that status and let the route render: init_status is
exempt from the storage interceptor, so it reports initialized: false and
the guard redirects to the wizard as intended.

Also shorten the env check copy, which was too long to read.

* fix(init): probe env check support instead of relying on settings

The env check step never appeared on a TS Worker without storage bound.
The step was gated on isTsWorker(), which reads the backend kind that
setSettings() records from /public/settings. That request is blocked with
a 503 when storage is unbound, so setBackendKind never ran and the kind
stayed at its "go" default. The step the user needed most was the one
that got skipped, and the earlier fix that made the wizard reachable did
not address this.

/public/env_check is registered only on the TS Worker backend, so whether
it can be fetched is itself a reliable capability probe and does not
depend on settings. Drive the step from that instead.

loading now starts true so the capability probe is not read as "probed
and unsupported" on the first frame, which would flash past the step.

Also correct comments that claimed the storage failure surfaces as a 503
on these endpoints: both are on the backend diagnostic allow-list and
return 200 with structured data.

---------

Co-authored-by: PIKACHUIM <PIKACHUIM@users.noreply.github.com>
P
Pikachu Ren committed
d211574fdb8764d56dcdb43c26539843e0645ee5
Parent: 8de44da
Committed by GitHub <noreply@github.com> on 9/12/2026, 4:13:37 PM