chore: new design for invitations accept

This commit is contained in:
fsylvain committed 2026-09-29 08:41:54 +02:00
1 parent 6afffc1984
commit 310cfd528e
8 files changed
+148 -34

No files matched your search

+105 -20
View File
@@ -1,29 +1,114 @@
# Accept invite
**Not designed yet.** The export has no screen for this route. The invitation email links to it, so it has to exist, but nothing in the boards fixes its layout, fields or copy. Do not implement it from this file. Get it designed first (see the prompt at the end), export it, and replace this file with the real spec.
- **Route:** `/invite/accept?c=CODE`
- **Layout:** AuthShell (public, like Register)
- **API:** not defined. It needs to read the invite behind the code and to create the account from it.
- **API:** GET /v1/auth/invite?c=CODE (pending) · POST /v1/auth/invite/accept (pending)
- **Visual reference:** `source/RenewCMS Screens Auth.dc.html`, group "Accept invite" (open it in a browser; each state is drawn at desktop and mobile, with a light/dark toggle).
## What the rest of the design already fixes
Opened from the invitation email. The link carries only the code, so the invited email is looked up on load and shown read-only. Username and password follow the Register rules, including PasswordStrengthHint, with no confirm field. On success the person is logged in and sent to /home with a toast. The account is already verified, because the invite went to their email, so it skips the pending and verify screens.
- The link is `{{.Host}}/invite/accept?c={{.VerificationCode}}`. It carries no email parameter.
- The Invite modal says: "We'll email them a link to choose a username and password. The link expires after 3 days."
- The email says: "Accept to choose a username and password. You'll sign in with your own account." and "This invite was sent to {{.Email}}. It expires in 3 days and works once."
- The email also says: "If the invite has expired, ask {{.InvitedBy}} to send a new one." Nobody else can revive an invite.
- The Users list calls the invite Accepted once the account is created.
- Registration stays closed to everyone else: [register.md](register.md) "Registration closed" (403 "This site already has an owner. Log in instead.") still applies to `/register`.
Neither endpoint exists yet:
## What has to be decided in the design
- `GET /v1/auth/invite?c=CODE` returns `{ email }`, or 404 or 410.
- `POST /v1/auth/invite/accept` takes `{ code, username, password }`. It returns 200 with the session cookie, 409 for a taken username, or 404 or 410 as above.
- Fields: username and password, with the same rules as Register (username 3 to 20, password at least 8, with the PasswordStrengthHint)? Is there a confirm field? Is the invited email shown read-only?
- What the screen does after success: log the user in and go to Home with a toast, or go to the login screen.
- States for a code that is invalid, already used, or expired (3 days), and how each one is worded.
- The submitting, validation, username-taken and server-error states.
- Whether an account created this way is verified straight away. The email address is proven by the link, so it can skip the pending and verify screens.
- Behavior when someone who is already logged in opens the link.
Registration stays closed to everyone else: [register.md](register.md) "Registration closed" still applies to `/register`. The board does not draw the case of a logged-in person opening the link; it is not specified.
## Prompt for Claude Design
## States
> Add an "Accept invite" screen to the Auth board of RenewCMS, at `/invite/accept?c=CODE`, inside AuthShell. It opens from the invitation email (emails/invitation.html). The invited person chooses a username and a password, with the same rules and PasswordStrengthHint as Register. Show the invited email read-only if that reads well. Draw every state at desktop and mobile, in light and dark: default, validation errors, submitting, username already taken, invalid or already-used link, expired link (tell them to ask the person who invited them), and server error. Decide what happens on success (logged in and sent to Home with a toast is my preference) and draw the toast. Reuse the existing Register and Verify components and copy style. Then export the boards and the handoff again.
### Checking the link
**Trigger:** On load, while the invite is looked up.
- Full-card spinner: "Checking your invite…"
### Default
**Trigger:** The code is valid and unused.
- Heading: **Accept your invite**
- Description: "Choose a username and password to finish setting up your account."
- Field `Email`: placeholder "you@example.com"; value "lea.martin@renew.example"; read-only; help "From your invitation."
- Field `Username`: placeholder "e.g. lea"; counter "0 / 20"; help "Letters and numbers, 3 to 20 characters. You'll use it to log in."
- Field `Password`: password with show/hide; checklist "At least 8 characters" (unmet)
- Submit button: "Accept invite"
- Footer: Already have an account? [Log in]
### Validation errors
**Trigger:** Checked on blur and on submit, using the same rules as Register. Nothing is sent.
- Heading: **Accept your invite**
- Description: "Choose a username and password to finish setting up your account."
- Field `Email`: placeholder "you@example.com"; value "lea.martin@renew.example"; read-only; help "From your invitation."
- Field `Username`: placeholder "e.g. lea"; value "ma"; counter "2 / 20" in error; **error "Use 3 to 20 characters."**
- Field `Password`: value "lime"; password with show/hide; checklist "At least 8 characters" (err)
- Submit button: "Accept invite"
- Footer: Already have an account? [Log in]
### Filled, valid
**Trigger:** Every rule is met and the checklist item turns green.
- Heading: **Accept your invite**
- Description: "Choose a username and password to finish setting up your account."
- Field `Email`: placeholder "you@example.com"; value "lea.martin@renew.example"; read-only; help "From your invitation."
- Field `Username`: placeholder "e.g. lea"; value "lea"; counter "3 / 20"; help "Letters and numbers, 3 to 20 characters. You'll use it to log in."
- Field `Password`: value "limewash2026"; password with show/hide; password shown; checklist "At least 8 characters" (met)
- Submit button: "Accept invite"
- Footer: Already have an account? [Log in]
### Submitting
**Trigger:** Fields and button are disabled.
- Heading: **Accept your invite**
- Description: "Choose a username and password to finish setting up your account."
- Field `Email`: placeholder "you@example.com"; value "lea.martin@renew.example"; read-only; help "From your invitation."
- Field `Username`: placeholder "e.g. lea"; value "lea"; counter "3 / 20"; help "Letters and numbers, 3 to 20 characters. You'll use it to log in."
- Field `Password`: value "limewash2026"; password with show/hide; checklist "At least 8 characters" (met)
- Submit button: "Creating account…", loading
- Footer: Already have an account? [Log in]
### Username taken (409)
**Trigger:** Another user has that username. The value is kept and the field gets focus.
- Heading: **Accept your invite**
- Description: "Choose a username and password to finish setting up your account."
- Field `Email`: placeholder "you@example.com"; value "lea.martin@renew.example"; read-only; help "From your invitation."
- Field `Username`: placeholder "e.g. lea"; value "marta"; counter "5 / 20"; focused; **error "That username is taken. Try another."**
- Field `Password`: value "limewash2026"; password with show/hide; checklist "At least 8 characters" (met)
- Submit button: "Accept invite"
- Footer: Already have an account? [Log in]
### Invalid or used link (404)
**Trigger:** The code is wrong, was already accepted, or is missing from the URL. No form is shown.
- ResultPanel (error, link-2-off): **This invite link doesn't work**; text "It may be incomplete, or it may already have been used. If you already set up your account, log in instead."; note "Open the link from your email again, or copy the full address into your browser."; actions "Go to log in" (primary)
### Expired link (410)
**Trigger:** The invite is older than 3 days.
- ResultPanel (error, clock): **This invite has expired**; text "Invites work once, for 3 days. Ask the person who invited you to send a new one."; actions "Go to log in" (secondary)
### Server error
**Trigger:** A 500 or no response. The values are kept.
- Alert (error, circle-x): **Couldn't create the account** "Something went wrong on the server. Try again in a moment."
- Heading: **Accept your invite**
- Description: "Choose a username and password to finish setting up your account."
- Field `Email`: placeholder "you@example.com"; value "lea.martin@renew.example"; read-only; help "From your invitation."
- Field `Username`: placeholder "e.g. lea"; value "lea"; counter "3 / 20"; help "Letters and numbers, 3 to 20 characters. You'll use it to log in."
- Field `Password`: value "limewash2026"; password with show/hide; checklist "At least 8 characters" (met)
- Submit button: "Accept invite"
- Footer: Already have an account? [Log in]
### Success
**Trigger:** 200 sets the session cookie → /home after 800 ms, with a toast. No verification step.
- ResultPanel (success, circle-check): **Your account is ready**; text "Taking you to your dashboard…"
- Toast (circle-check): **Welcome to RenewCMS** "You're logged in as lea."