- overview.md: M9 row flipped to shipped, links to spec/plan added,
roadmap paragraph updated with actual deliverables, conventions
updated to reflect dual-theme support
- tests/e2e/auth.spec.ts: add GET /event/list override so the dashboard
renders after the magic-link → token flow (was 500ing with no override)
- tests/e2e/profile.spec.ts: use { exact: true } on username assertion to
avoid strict-mode violation (username 'alice' matched 3 elements)
- Formatting: prettier --write pass on polish spec/plan, layout.css,
layout.svelte
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Multi-stage Dockerfile for production builds with adapter-node, reverse proxy config with Caddy, and optimized Docker context.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cookie propagation across the use:enhance redirect chain (authorize →
/token → /) may not settle before Playwright proceeds. Waiting for
networkidle after the submit click gives the chain time to complete
before asserting on the URL and user-menu elements.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ProfileCard never renders the permission level label, so the '普通用户'
assertion always fails. Replace with assertion on loggedInUser.username which
is guaranteed to be rendered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix 1: mock items in 'agenda tab lists items' now use status/description
fields instead of is_published, matching the page's filter logic.
Fix 2: 'agenda create submits form' replaced with 'approve button opens
approve dialog' since the admin agenda page has no 新增 button — it only
supports review (approve/reject) of user-submitted items.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The attendance tab test was providing a mock response with shape
{ status: 200, data: [ ... ] } (flat array). But +page.server.ts for
the admin events page casts the response to read inner?.items ?? [],
expecting shape { status: 200, data: { items: [ ... ] } }.
Updated the mock to wrap the attendance array in an { items: [...] }
object to match the server-side expectation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The "立即签到" button is rendered by bits-ui Dialog.Trigger as a
<button>, not <a>. Change getByRole('link') to getByRole('button')
on lines 120, 133, and 149 for selector consistency.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
POST /app/theme sets the theme cookie and redirects back. Sun/Moon
button in the app navbar submits the form. E2E tests verify SSR
cookie-driven theme switching.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reads theme cookie in hooks.server.ts and rewrites data-theme on <html>
before the page is sent. Root and (app) layout servers expose theme so
the navbar can show the correct toggle icon. Removes hardcoded
color-scheme meta (DaisyUI CSS handles it per-theme).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers three deliverables: light theme + SSR cookie toggle (form-action
approach, transformPageChunk in hooks.server.ts), multi-stage Dockerfile
+ Caddyfile for adapter-node production deploy, and fixes for 6 failing
E2E tests (option b: tests corrected to match existing code — wrong mock
shapes, wrong Playwright role selectors, and tests for features that were
never built).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace raw JSON pre-block with typed KycInfoDetail component for passport/cnrid info
- Upgrade KYC method selection from dropdown to card-based picker with icons
- Fix passport form loading state: replace '...' with Spinner component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents the unauthorized error page from briefly flashing before the
logout interceptor navigates away, by checking token presence synchronously
in beforeLoad and throwing a redirect immediately.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Uses getErrorMessage from the new exception.gen.ts dictionary to display
Chinese error descriptions instead of raw 13-char error codes in GlobalError.
Adds gen:errors script and supporting files for regenerating the dictionary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- useUpdateUserById: new hook for PATCH /user/update/{user_id} (admin updating others)
- user-permission-edit: switch to useUpdateUserById, move user_id from body to path
- useAuthToken: extract bare useMutation in token route into a proper data hook
- edit-profile: rename shadowed callback param (no behavior change)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update the admin agenda list to use the regenerated user_profile payload so submitter nicknames render correctly and link to the submitter's public profile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use the generated agenda list query key so approve/reject, schedule, and edit mutations invalidate the correct cache entry. Sync the generated client types with the updated agenda list response shape.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Regenerate client types making required fields non-optional
- Add checkin_count/join_count fields to EventListItems
- Pass event_id in agenda approve/reject mutations
- Use non-null assertion for eventId in event update form
- Replace kyc_status with kyc_info in attendance story examples
- Remove kycStatusFilter prop from attendance list stories
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pending agendas should always be reviewable by admins. The previous
!isPublished guard hid approve/reject buttons even when pending items
existed after agenda publication.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
15 tasks covering Cypress setup, 92 test cases across 5 permission
levels, seed SQL, and Docker Compose CI configuration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch from local-only to CI execution with Docker Compose isolation.
Replace manual test data setup with SQL dump (seed.sql) including
relative timestamps for ongoing event. Add docker-compose.e2e.yml note.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers all user permission levels (Lv10/20/30/40/50), 12 feature
modules, and 92 test cases (happy path + error states) using Cypress
against a real backend with fixed test accounts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Sticky tabs now offset by --header-height to avoid hiding behind app header
- Replace type filter buttons with Tabs component for consistent styling
- Use isLoading + keepPreviousData in useAdminEvents to prevent list flash on page/filter change
- Expand trello skill label inference rules
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove KYC status filter dropdown and status column from attendance list
- Conditionally render KYC type and operation columns based on event's enable_kyc field
- Add keepPreviousData to useAdminAttendance to prevent input focus loss on filter change
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Regenerated API client: ServiceEventEventListResponse now wraps paginated
items (renamed to ServiceEventEventListItems), event info includes quota/limit,
attendance list includes checked_in_at, joined_at, kyc_status
- Fixed toEventInfo to use renamed ServiceEventEventListItems type
- Added required quota (外显上限) and limit (实际上限) fields to event
create/edit form with positive integer validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Stop click propagation from Edit button to TableRow to prevent double-fire
- Store full editingUser state on open so dialog persists across page changes
- Remove unused targetUserId from dialog view props and currentUserId from container props
- Add useEffect to reset selectedLevel when targetCurrentLevel changes
- Replace double as-unknown-as cast with single typed assertion using ServiceUserUserInfoUpdateData
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>