sciagent code + Gitea Actions CI/CD
CI/CD / backend (push) Failing after 2m8s
CI/CD / frontend (push) Failing after 1m40s
CI/CD / deploy (push) Has been skipped

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Thinh Lam
2026-06-30 09:38:30 +07:00
commit 688fac73e9
1167 changed files with 158244 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
# Phase 1 Signup page — how it works
This document describes [`Signup.tsx`](./Signup.tsx): a **standalone registration screen** for the `fe01` “phase1” demo flow. Use it as a spec when re-implementing the same behavior elsewhere.
## Where it lives in the app
- **Component:** `fe01/src/phase1/pages/Signup.tsx` (default export `Signup`)
- **Route:** `/phase1/signup` (see `fe01/src/App.tsx`)
This is **not** the same as the main apps tabbed login/signup at `/signup`, which uses `SignupForm` (`fe01/src/components/auth/SignupForm.tsx`) with extra fields and optional OTP. The phase1 page is intentionally simpler.
## Dependencies
| Area | What |
|------|------|
| **Router** | `react-router-dom`: `Link`, `useNavigate` — success screen uses `navigate('/login')` (root login, not phase1). Link at bottom goes to `/phase1/login`. |
| **API** | `authService` from `@/phase1/lib/auth-service``register()` and `resendVerify()`. |
| **UI** | shadcn-style: `Button`, `Input`, `Label`, `Card*`, `Alert`, `Select`; icons from `lucide-react`. |
**Base URL:** `authService` uses `import.meta.env.VITE_API_URL` or falls back to `http://localhost:3000` (see `auth-service.ts`). Ensure your re-implementation uses the same env variable or your chosen API base.
## User-facing flow (two screens)
1. **Form screen** — collect name, school email, password, role → submit.
2. **Success screen** — shown when registration succeeds: explains that a verification email was sent, offers **resend verification** and **back to login**.
There is **no** auto-redirect after signup; the user must verify email via the link in mail (handled by backend + a separate verify route elsewhere, e.g. `/verify-email?userId=...&token=...`).
## State model
| State | Type | Role |
|-------|------|------|
| `email`, `password`, `fullName` | `string` | Controlled form fields |
| `role` | `'Admin' \| 'Editor' \| 'Viewer'` | Default `'Viewer'` |
| `error` | `string` | Inline validation / API error message |
| `loading` | `boolean` | Disables inputs and shows spinner on submit/resend |
| `successMsg` | `string \| null` | Message from API after successful register or resend |
| `registeredEmail` | `string \| null` | Email used for resend; together with `successMsg` gates the success UI |
**Success UI condition:** `successMsg && registeredEmail` — both must be set after a successful `register()`.
## Role picker
- **Canonical values** sent to API: `Admin`, `Editor`, `Viewer` (must match backend).
- **Display:** Vietnamese labels + icons + a one-line **description** under the select (`ROLE_OPTIONS` array in the component).
Re-implementing: keep the **API values** exactly as the backend expects; only labels/descriptions are presentation.
## Client-side validation (before `register`)
Order in `handleSubmit`:
1. Clear `error`.
2. `fullName` — non-empty after trim.
3. `email` — non-empty after trim.
4. **Domain check**`validateDomain()`:
- Must contain `@`.
- Part after `@` (lower case, trimmed) must equal one of **`ump.edu.vn`** or **`umc.edu.vn`** (hardcoded hint list `ALLOWED_DOMAINS_HINT`).
5. `password` — length ≥ 8.
**Important:** This list is a **UX hint**. The file comment states the server re-validates using `SystemSettings` / `Auth.AllowedEmailDomains`. Your copy can change the hint list, but must stay aligned with server policy.
**On submit:** email is sent as `email.trim().toLowerCase()`; `fullName` is `fullName.trim()`.
## API: `register`
**Call:** `authService.register({ email, password, fullName, role })`
**HTTP:** `POST {API_URL}/auth/register`
**Headers:** `Content-Type: application/json`, `X-Client-Origin: window.location.origin`
**Body:** JSON `{ email, password, fullName, role }` with `role` one of `Admin` | `Editor` | `Viewer`.
**On failure (`!res.ok`):** `authService` returns `{ success: false, error: string }` — page sets `error` and stops.
**On success:** `{ success: true, userId, email, role, emailSent, message }` — page sets `registeredEmail` from `res.email`, `successMsg` from `res.message`, does **not** set tokens (registration does not log the user in).
## API: resend verification
**When:** User is on success screen and clicks “Gửi lại email xác nhận”.
**Call:** `authService.resendVerify(registeredEmail)`
**HTTP:** `POST {API_URL}/auth/resend-verify` with JSON `{ email }`, same `X-Client-Origin` pattern.
**On response:** Page updates `successMsg` with `res.message` (does not clear the success layout).
## Error display
- Errors render in a destructive `Alert` above the submit button.
- Success screen uses a non-destructive `Alert` for `successMsg`.
## Styling / layout notes
- **Form:** centered card on `bg-muted/20`, max width `max-w-md`.
- **Success:** full-height centered layout with gradient background and slightly richer card styling (backdrop blur, green mail icon).
- **Accessibility:** labels use `htmlFor` matching input `id`; password field has `minLength={8}` and `required` in addition to JS checks.
## Checklist for a faithful re-implementation
- [ ] Same route or intentionally different — document if you move it.
- [ ] `register` + `resendVerify` endpoints, payloads, and headers (`X-Client-Origin`, `credentials: 'include'` if cookies matter for your stack).
- [ ] Two-step UI: form → “check your email” with resend + login navigation.
- [ ] Client validation order and domain hint list (or replace hint with server-driven list if you add an endpoint).
- [ ] Role enum matches backend; Vietnamese copy optional.
- [ ] Distinguish this simple flow from `SignupForm` (OTP/extra fields) if both exist in the product.
## Related files
- `fe01/src/phase1/lib/auth-service.ts``register`, `resendVerify`, `verifyEmail`
- `fe01/src/App.tsx` — route wiring
- `fe01/src/components/auth/SignupForm.tsx` — richer signup used on main `/login` + `/signup` (different product path)