Files
RenewCMS/features/settings_page.feature

132 lines
7.2 KiB
Gherkin

Feature: Settings page and GET /v1/settings
As a verified RenewCMS user in the shared workspace
I want a Settings page that shows the version of the RenewCMS build I am running
So that I can tell which build is deployed when I report a problem or check an upgrade
Background:
Given GET /v1/settings is mounted under /v1 in api/router.go in its own router, behind
jwtauth.Verifier, jwtauth.Authenticator, middleware.RequireCurrentToken and
middleware.RequireVerifiedUser, the same chain as NewUserRouter
And the response of a verified caller is 200 with the JSON body {"version": "<value>"}, one
snake_case field and nothing else, built from the domain entity settings.Settings in
internal/domain/settings
And GetSettingsUseCase (internal/infrastructure/useCases) is built with the version string and
depends only on the domain package; the handler in api/handlers/settings receives it
through NewHandler and never reads config, os or the environment
And config.Settings gains a Version field; cmd/server/main.go sets it from its own
main.version variable ("dev" unless set with -ldflags -X main.version) right after
config.NewSettingsFromEnv, and api/dependecyInjection.go passes settings.Version to the use
case; no os.Getenv or os.LookupEnv for the version appears outside cmd/server/main.go and
internal/infrastructure/config, and the version is captured once at startup
And /settings is a verified route (meta.auth "verified", meta.title "Settings") rendered as
SettingsPage inside DashboardShell, per docs/design/routes.md and docs/design/screens/settings.md
And SettingsPage calls GET /v1/settings once per navigation to it
And the PageHeader shows breadcrumb "Settings" (mobile title "Settings"), the page title
"Settings" and the subtitle "Workspace information."
And the page is at most 720 px wide, with padding 32 px on desktop and 20px 16px 88px on
mobile, and 20 px between the header and the card
And the page holds one card, --ui-bg with a 1 px --ui-border, 20 px padding on desktop and
16 px on mobile, containing a single row laid out as the board frame draws it: the label at
the left, the value at the right, vertically centred, 16 px apart
And the label is "Version" (15 px semibold, --ui-text-highlighted) and the value is the
server's version string in IBM Plex Mono 14 px, --ui-text-toned, with no "v" added by the
SPA
And the page has no action, toggle, link or input; every verified user sees it, owner and
admin alike
And DashboardShell's navigation gains "Settings" (icon settings, i-lucide-settings, linking to
/settings) after "Integration", in the sidebar and in the mobile drawer, so it lists five
destinations in this order: Home, Articles, Users, Integration, Settings
And skeleton placeholders show only after 150 ms of loading, so a fast response never flashes
them
And the Loading and Error states are not drawn in docs/design; they are decided in this spec
and covered by Vitest only (no visual state)
Scenario Outline: A verified caller gets the running build's version
Given the process was started with a config.Settings whose Version is "<version>"
And a verified user is logged in with a valid jwt cookie
When the client sends GET /v1/settings
Then the response status is 200
And the response body is exactly the JSON object {"version": "<version>"}
Examples:
| version |
| v2.2.0-beta |
| dev |
Scenario: The use case returns the version it was built with
Given GetSettingsUseCase is built with the version "v2.2.0-beta"
When GetSettings is called
Then it returns a settings.Settings whose Version is "v2.2.0-beta"
Scenario: A request without a jwt cookie is refused
When the client sends GET /v1/settings with no jwt cookie
Then the response status is 401
And the use case is not consulted for the response
Scenario: A token whose version no longer matches the account is refused
Given user id 7 exists with token version 1
And the jwt cookie was minted for user 7 with token version 0
When the client sends GET /v1/settings with that cookie
Then the response status is 401
And the response body is apperr.UnauthorizedErrorMessage
Scenario: An unverified account is refused
Given user id 8 exists with is_verified false and a valid jwt cookie
When the client sends GET /v1/settings with that cookie
Then the response status is 403
And the response body is apperr.VerificationRequiredErrorMessage
And the response does not contain the version
Scenario: Default — the Version row shows the server's version
Given GET /v1/settings resolves 200 with {"version": "v2.2.0-beta"}
When the user navigates to /settings
Then the breadcrumb reads "Settings" (mobile title "Settings")
And the header shows the title "Settings" and the subtitle "Workspace information."
And the card shows one row: the label "Version" and the value "v2.2.0-beta"
And the "Settings" nav item has aria-current="page" and no other nav item does
Scenario: The value is shown exactly as reported, with no prefix added
Given GET /v1/settings resolves 200 with {"version": "dev"}
When the user navigates to /settings
Then the value reads "dev"
Scenario: Navigation — "Settings" sits after Integration
Given the user is on /home
When DashboardShell mounts
Then the sidebar and the mobile drawer list Home, Articles, Users, Integration, Settings in
that order
And "Settings" has the settings icon and links to /settings
Scenario: Loading — the value becomes a skeleton after 150 ms while the request is in flight
Given GET /v1/settings has not yet resolved
When the user navigates to /settings
Then the label "Version" is visible at once, and nothing stands in for the value during the
first 150 ms
And after 150 ms a skeleton replaces the value only, and the card is aria-busy="true"
When GET /v1/settings then resolves 200 with {"version": "v2.2.0-beta"}
Then the skeleton is replaced by "v2.2.0-beta" and aria-busy is no longer set
Scenario Outline: Error — a 500 or a network failure replaces the row with an inline alert and a retry
Given GET /v1/settings <failure>
When the user navigates to /settings
Then the card shows an error alert with no close button and no title, reading "Couldn't reach
RenewCMS. Check your connection and try again.", with an action "Try again" (icon rotate-cw)
And the "Version" row is not shown
And the header (title and subtitle) is still shown
When the user activates "Try again"
Then the Loading state shows and GET /v1/settings is sent again
When it then resolves 200 with {"version": "v2.2.0-beta"}
Then the Default state's row replaces the alert
Examples:
| failure |
| resolves with a 500 response |
| never reaches the server |
Scenario: A 401 or an unverified 403 is handled globally, not by the page
Given GET /v1/settings resolves 401
When the user navigates to /settings
Then useApi's global handling redirects to "/login?redirect=/settings&reason=expired"
And SettingsPage shows no error alert of its own