Merge develop into main #1

Merged
nvirellia merged 132 commits from develop into main 2026-05-03 14:00:39 +00:00
Member
No description provided.
nvirellia added 132 commits 2026-05-03 14:00:17 +00:00
Signed-off-by: Noa Virellia <noa@requiem.garden>
feat: improve containerfile
Some checks failed
Client Check Build (NixCN CMS) TeamCity build failed
0f8b07a05e
Signed-off-by: Noa Virellia <noa@requiem.garden>
refactor: rename dockerignore to containerignore
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
bada3271df
Signed-off-by: Noa Virellia <noa@requiem.garden>
fix: skeleton suspense
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
59215f4a5e
feat: favicon and title
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
2af53da3f6
Implement event details and unify event list flows
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
9297747d9a
Fix KYC prompt text alignment on mobile
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
3e33cf4f5d
feat: upgrade to vite 8
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
757b5d0cb2
feat: workbench
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
4355092863
Add devenv
Some checks failed
Client Check Build (NixCN CMS) TeamCity build failed
932396866f
Signed-off-by: Asai Neko <sugar@sne.moe>
Update zed project settings
Some checks failed
Client Check Build (NixCN CMS) TeamCity build failed
d4a690854a
Signed-off-by: Asai Neko <sugar@sne.moe>
Modify zed settings
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
6130c0ebb8
Signed-off-by: Asai Neko <sugar@sne.moe>
feat: remove X-Api-Version
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
cd6cab69bd
refactor: adapt upstream changes
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
2278fe4b4a
feat: workbench background
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
7e1f249cc0
docs: add CLAUDE.md
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
cebf706708
docs: add admin interface design spec
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
f8031dc557
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs: add admin interface implementation plan
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
2e0377b5bc
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements AgendaListSkeleton, AgendaListView, AgendaListContainer and story
for reviewing, approving/rejecting, scheduling, and editing agenda submissions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements user admin list with sortable columns, permission level filter, and per-row edit button gated by canEditPermission. Adds permission edit dialog with assignable levels and optimistic query invalidation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs: debug skill
Some checks failed
Client Check Build (NixCN CMS) TeamCity build failed
464b392375
fix: fixes by autoresearch
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
f9e41cad87
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>
- 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>
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>
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>
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>
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>
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>
fix: update API types, pass event_id in agenda review, sync story fixtures
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
1322ba48d4
- 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>
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>
fix(agenda): link submitter nicknames to profiles
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
5c2e48f0b3
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>
fix: use correct user update endpoints and wrap mutations in hooks
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
f9d0531713
- 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>
fix(admin/users): invalidate getUserList queries after permission update
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
036a4e7fa5
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat: resolve backend error codes to human-readable messages on error page
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
7349997ab5
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>
feat(checkin): add camera switcher to scanner dialog
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
a6469f4737
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>
fix(checkin): force white background on QR code for scanner compatibility
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
9fa83b0a6f
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat(kyc): improve KYC UI with structured info display and spinner
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
4365304845
- 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>
chore: ignore .worktrees directory
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
8f328a1601
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>
12 bite-sized tasks: light theme CSS, SSR transformPageChunk pipeline,
theme endpoint + navbar toggle with E2E coverage, 6 targeted E2E test
fixes (wrong mock shapes / wrong role selectors), and Dockerfile +
Caddyfile for production deployment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
Project uses Podman; Containerfile is the conventional name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Integrates @sentry/sveltekit 10.49.0 via the modern SvelteKit path
(instrumentation.server.ts + experimental.instrumentation.server).

- instrumentation.server.ts: server-side init with tracing, logging,
  and console capture (log/warn/error forwarded to Sentry)
- hooks.client.ts: client-side init with browserTracingIntegration,
  replayIntegration (maskAllText/blockAllMedia), consoleLoggingIntegration,
  and handleErrorWithSentry
- hooks.server.ts: adds handleErrorWithSentry export, composes existing
  appHandle with sentryHandle() via sequence(), and sets isolation scope
  attributes (user_id, username, permission_level) per request for
  log/trace correlation
- svelte.config.js: enables experimental.instrumentation.server and
  experimental.tracing.server
- vite.config.ts: adds sentrySvelteKit() plugin for source map uploads
- .env.example: documents VITE_SENTRY_DSN, SENTRY_DSN, SENTRY_ORG,
  SENTRY_PROJECT, SENTRY_AUTH_TOKEN

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(svelte5): wrap superForm and createKycState calls in untrack()
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
17892b4546
superForm() and createKycState() called during component initialisation
were triggering reactive tracking warnings in Svelte 5 because they
access reactive state internally. Wrapping with untrack() prevents
spurious re-runs of the initialisation logic on subsequent reactive
updates.

Also converts the data.form cast in admin/events/new to $derived so it
stays in sync with SvelteKit page invalidations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore(container): add build ARGs for Sentry and Turnstile env vars
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
21b239492e
Declare build-time ARG instructions for PUBLIC_TURNSTILE_SITE_KEY,
VITE_SENTRY_DSN, SENTRY_DSN, SENTRY_ORG, SENTRY_PROJECT, and
SENTRY_AUTH_TOKEN so CI can pass them via --build-arg. TURNSTILE_SECRET_KEY
and SENTRY_DSN are runtime-only and injected via -e at container run time.
Also removes TURNSTILE_SECRET_KEY from .env.example (runtime secret,
not a build-time value).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore(container): remove PUBLIC_TURNSTILE_SITE_KEY build ARG
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
d3c2d555f7
PUBLIC_TURNSTILE_SITE_KEY uses $env/dynamic/public (runtime), not
static/build-time injection, so it doesn't need to be a build ARG.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(auth): disable login button until Turnstile verification completes
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
ba6edca4fd
Track verified state via on:turnstile-callback; button shows 等待 Turnstile...
spinner on load and remains disabled until CF widget succeeds or errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Corrects misspelling "Nix CN CMS" → "NixCN CMS" across all source files,
docs, and tests; adds <title>NixCN CMS</title> to the root layout; documents
the correct spelling in CLAUDE.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: use nixos.svg from static/ as favicon
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
a11af6e8b7
Replaces the Vite-processed $lib/assets/favicon.svg import with a direct
reference to static/nixos.svg via the base path, adding SVG MIME type.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(sentry): filter Cloudflare noise and redirect on expired session
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
fe19146d3d
Fixes NIXCN-CMS-TEST-1: add beforeSend filter that drops events where
every stack frame originates from a Cloudflare /cdn-cgi/ script —
pure third-party noise from the email-decode injector.

Fixes NIXCN-CMS-TEST-2: when an API call inside a load function gets a
401 (session expired, refresh failed), loadSdk now throws redirect(303)
to /app/authorize instead of error(401). This gives the user a working
login redirect rather than an error page, and prevents SvelteKit from
passing the deserialized HttpError object to handleError where Sentry
was incorrectly capturing it as an unexpected exception.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(session): log refresh failure reason for diagnostics
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
88e21a0bdc
When refreshSingleFlight fails, we previously returned null with no
context. Now each branch emits a console.warn with the relevant detail
(HTTP status, missing token pair, or thrown error message). Sentry's
consoleLoggingIntegration picks these up automatically, so the next
refresh failure will show the backend's actual rejection status in Sentry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: use NixOS blue instead of currentColor in favicon SVG
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
4f583e457d
`currentColor` inherits black from the browser's favicon rendering context.
Hardcode #7ebae4 (NixOS light blue) so the icon is recognisable in the tab bar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause (confirmed from backend logs): when two browser requests are
in-flight simultaneously with the same expired access token, the second
request arrives at the backend ~1s after the first refresh completed.
By then the backend's grace window has closed and it rejects the already-
rotated refresh token with 401.

The existing single-flight mechanism only collapses truly concurrent
refreshes (requests that arrive before the first promise resolves). It
cannot help a sequential caller that arrives after the first refresh
completes and its inFlight entry is deleted.

Fix: keep a process-level recentlyRotated cache keyed by the old refresh
token for 10 seconds after a successful rotation. A later caller with the
same old token gets the cached pair immediately, without a second backend
call that would be rejected.

Adds a regression test that reproduces the exact scenario.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The backend does not implement a refresh-token grace window. Without it,
two browser requests sent within the same ~15s window but in separate
HTTP round-trips both carry the same expired access token. The first
request successfully rotates the token; the backend immediately invalidates
the old token; the second request arrives after the first response's
Set-Cookie has been sent but before the browser has applied it, so it
still presents the old token — and the backend rejects the refresh.

The recentlyRotated cache (previous commit) covers same-process sequential
races. This commit adds the primary defence:

Proactive refresh in hooks.server.ts: decode the access token's iat claim
(payload only, no signature verification) and rotate when ≤5s remain on
the 15s lifetime, before any API call is made. All parallel load functions
in the same request then see a freshly-issued token. The single-flight in
refreshSingleFlight collapses simultaneous proactive refreshes from
concurrent browser requests on the same pod. The 401 interceptor in
api.ts remains as a safety net for unexpected cases (clock skew, etc.).

Adds getJwtIat and isTokenAboutToExpire helpers with full unit tests.
Updates CLAUDE.md to document the two-path refresh design.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend extended TTL_ACCESS to 300s. Matching the client-side constants
keeps proactive refresh in sync — fires 30s before expiry instead of
5s before a 15s token, reducing refresh frequency by ~20x.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs: add token refresh race condition design doc
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
705af7f30b
Documents the production 401-on-rotation race, the four-layer client-side
fix (proactive refresh, in-process single-flight, rotation cache, 401
interceptor), the backend AT lifetime extension to 5min, and every
alternative considered with the reasoning behind each rejection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Reject QR codes whose raw text is not exactly 6 digits (no strip-and-guess)
- Suppress repeated onScan calls for the same code within 10 s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(sentry): use includes() instead of startsWith() for cdn-cgi filter
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
be8b8c0d94
window.onerror reports script URLs as absolute URLs, so f.filename is
"https://test.nix.org.cn/cdn-cgi/..." — startsWith('/cdn-cgi/') never
matched and Cloudflare email-decode noise kept reaching Sentry.

Fixes NIXCN-CMS-TEST-1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
chore: replace hand-drawn NixOS SVG with official logo paths
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
2c5426671e
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(admin-events): redirect to list after event creation
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
60f7badbb7
After creating an event, redirect to /admin/events instead of the new
event's edit page, which was confusing since the user hasn't configured
the event yet. Adds E2E test to assert the post-create redirect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(agenda): use badge-warning for pending status to fix contrast
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
1cdefc4f49
badge-neutral on the dark theme renders with insufficient contrast;
badge-warning (amber) is both readable and semantically correct for
an awaiting-review state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Thin primary-color bar at top of viewport appears after 200 ms of
navigation latency and snaps away when the new page renders. Uses
nprogress wired to SvelteKit's navigating store via a Svelte 5
$effect. Fast navigations (< 200 ms) produce no visible flash.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs: add navigation progress bar design spec and implementation plan
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
e1009ed622
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat(sentry): add /vitals tunnel to bypass adblockers
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
e80ad704d1
Routes Sentry envelopes through a first-party /app/vitals endpoint
instead of directly to *.ingest.sentry.io. DSN host and project ID
are validated server-side from the SENTRY_DSN env var before proxying.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mandatory username/nickname gate for newly registered users (UUID username).
Layout-level detection + named action + Bits UI dialog, no dedicated route.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6-task plan: schema → layout server → component → layout wire-up → E2E tests → lint/build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Also fixes the `completeProfile` form action: SvelteKit only supports form
actions in `+page.server.ts`, not `+layout.server.ts`. Moved the action to a
dedicated `/(app)/onboarding/+page.server.ts` and updated the dialog form's
`action` attribute to the absolute path `/app/onboarding?/completeProfile`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docs(onboarding): reformat plan and spec to consistent tab indentation
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
9d0e591412
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Username: 3–32 → 5–255. Nickname: max 64 → max 24 (UTF-8 rune limit).
Applied to both onboarding and profile schemas.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(profile): update UI constraints and tests to match new 5-255/24 limits
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
95539c3807
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Asai Neko <sugar@sne.moe>
Signed-off-by: Asai Neko <sugar@sne.moe>
Signed-off-by: Asai Neko <sugar@sne.moe>
Remove antfu config from zed settings
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
46a2451e98
Signed-off-by: Asai Neko <sugar@sne.moe>
fix: daisyui theme
All checks were successful
Client Check Build (NixCN CMS) TeamCity build finished
Client Prod Build (NixCN CMS) TeamCity build finished
cbe0ec88e4
nvirellia merged commit cbe0ec88e4 into main 2026-05-03 14:00:39 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: nixcn/cms-client#1