2 changed files with 91 additions and 0 deletions
@ -0,0 +1,88 @@ |
|||
# Registration Page Design |
|||
|
|||
## Overview |
|||
|
|||
Add a registration page at `/register` with username, password, confirm password, and SVG captcha. On success, redirect to `/login` with a query param. Login page is out of scope. |
|||
|
|||
## Stack |
|||
|
|||
- Nuxt 4.4 + Nuxt UI 4.6 + Tailwind v4 |
|||
- Drizzle ORM + SQLite (users table already exists) |
|||
- bcryptjs (already installed), svg-captcha, zod (already installed) |
|||
|
|||
## Files |
|||
|
|||
### New |
|||
|
|||
| File | Purpose | |
|||
|---|---| |
|||
| `app/pages/register.vue` | Registration page component | |
|||
| `server/api/auth/captcha.get.ts` | Generate SVG captcha, return token + svg | |
|||
| `server/api/auth/register.post.ts` | Validate input, create user | |
|||
| `server/utils/auth/captcha.ts` | Server-side captcha generation/validation | |
|||
| `server/utils/auth/validation.ts` | Zod schemas for registration input | |
|||
|
|||
### Modified |
|||
|
|||
| File | Change | |
|||
|---|---| |
|||
| `app/layouts/default.vue` | Wire header button to `/register` | |
|||
|
|||
## API Endpoints |
|||
|
|||
### GET /api/auth/captcha |
|||
|
|||
Generates a captcha, stores token→text in a server-side Map (5-min expiry), returns the SVG and token. |
|||
|
|||
``` |
|||
Response: { code: 0, data: { token: "uuid", svg: "<svg>...</svg>" } } |
|||
``` |
|||
|
|||
### POST /api/auth/register |
|||
|
|||
``` |
|||
Request: { username, password, confirmPassword, captchaToken, captchaText } |
|||
Response: { code: 0, data: { id: 1, username: "foo" } } |
|||
``` |
|||
|
|||
Steps: |
|||
1. Zod validation (username 3-30, password 8+, passwords match) |
|||
2. Verify captcha: lookup token in Map, compare text case-insensitive, delete on match |
|||
3. Check username uniqueness in DB |
|||
4. bcryptjs hash password (salt rounds 10) |
|||
5. Insert into users table with role="user", status="active" |
|||
6. Return success — no auto-login |
|||
|
|||
## Data Flow |
|||
|
|||
1. Page mounts → GET /api/auth/captcha → render SVG |
|||
2. User submits → client Zod validation → POST /api/auth/register |
|||
3. On success → `navigateTo('/login?registered=1')` |
|||
4. On error → show toast, keep form state; if captcha fail, auto-refresh captcha |
|||
|
|||
## Error Handling |
|||
|
|||
Client-side: UForm + Zod validation for empty fields, length, password match. |
|||
|
|||
Server-side: |
|||
|
|||
| Case | Message | |
|||
|---|---| |
|||
| Zod validation fail | "密码至少需要8个字符" | |
|||
| Captcha wrong | "验证码错误" | |
|||
| Captcha expired | "验证码已过期" | |
|||
| Username taken | "用户名已存在" | |
|||
| Server error | "注册失败,请稍后重试" | |
|||
|
|||
Captcha is consumed (deleted from Map) on match to prevent replay. If registration fails after captcha check, a new captcha is fetched. |
|||
|
|||
## Form Fields |
|||
|
|||
- **Username** — required, 3-30 characters, unique in DB |
|||
- **Password** — required, min 8 characters, masked input with toggle |
|||
- **Confirm Password** — required, must match password |
|||
- **Captcha** — SVG image + text input, refresh button |
|||
|
|||
## Layout |
|||
|
|||
Card-centered form (380px max-width), single column. Header already has the "登录/注册" button. Form shows a "Already have an account? Log in" link at the bottom. |
|||
Loading…
Reference in new issue