Skip to content

feat(admin): データ層モダン化(SP1)+即時インタラクティブシェル(SP2)を develop へ統合#43

Merged
ut42tech merged 6 commits into
developfrom
feat/admin-resilience-shell
Jun 2, 2026
Merged

feat(admin): データ層モダン化(SP1)+即時インタラクティブシェル(SP2)を develop へ統合#43
ut42tech merged 6 commits into
developfrom
feat/admin-resilience-shell

Conversation

@ut42tech
Copy link
Copy Markdown
Owner

@ut42tech ut42tech commented Jun 2, 2026

概要

stack PR (#41 / #42) が兄弟ブランチ同士でマージされ develop に到達しなかったため、その内容を 1 本に統合して develop へ再投入します。

stack PR の中間ブランチが削除されず、GitHub の auto-retarget が発火しなかったのが原因です。本 PR の差分は SP1 + SP2 のみ(UI リフレッシュは develop 反映済みのため含まれません)。内容は #41 / #42 でレビュー・承認済みのものと同一で、ロジック変更はありません。

含まれる変更

SP1 — データ取得ステートの集約(refactor)

  • packages/ui に読み取り専用フックを追加: useApiResource + DataError / EmptyState プリミティブ
  • admin の 6 つの fetch ステートマシンを useApiResource へ移行(dashboard / participants / stats / mentors / pre-registrations / participant-detail-sheet)

SP2 — 即時インタラクティブシェル + クラッシュ境界

  • MeProvider / MeGate に分割:シェル(ナビ・アカウント)は認証完了前でも即描画し、MeGate が本文のみゲートする
  • error.tsx(authed / root)・loading.tsx のレンダリングクラッシュ境界を追加
  • checkin / signage は <MeGate> でラップするのみで挙動不変(後方互換)

マージ後の整理(別途対応)

誤マージで残った中間ブランチ(feat/admin-ui-responsive / refactor/admin-data-layer)は本 PR マージ後に削除します。

コミット

  • eb9a370 feat(ui): add useApiResource hook + DataError/EmptyState primitives
  • f9a1b33 refactor(admin): migrate 6 fetch state machines to useApiResource
  • 5aad32b feat(admin): instant interactive shell via MeProvider/MeGate split
  • d5605df feat(admin): add render-crash error boundaries + route loading skeleton
  • (+ 設計 spec 2 件)

🤖 Generated with Claude Code

ut42tech and others added 6 commits June 2, 2026 18:52
…ub-project plan)

Records the Next.js 16.2.4 research conclusions (PPR/cacheComponents and
server-side streaming do not fit the current all-client-fetch +
host-only cross-origin cookie architecture) and decomposes the work into
three sequenced sub-projects: (1) client data-layer consolidation,
(2) resilience + instant shell, (3) server-side data (BFF vs
cross-subdomain cookie — its own design).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Shared read-only data primitives to consolidate admin's duplicated fetch
state machines:
- useApiResource<T>(path, {enabled}) — idle|loading|ok|error + reload(),
  refetches when `path` changes (query string drives search/filter/page),
  with the cancellation guard lifted from participant-detail-sheet.
  Mutations are out of scope (read-only).
- DataError — the destructive Alert used for fetch errors.
- EmptyState — the centered "no results" placeholder (non-table).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the duplicated {loading|ok|error} useEffect+apiJson state
machines across the dashboard, participants, stats, mentors,
pre-registrations and the participant detail sheet with the shared
useApiResource hook, and the inline error Alerts / empty blocks with
DataError / EmptyState.

- Query-param-driven pages build the path (date / search+filter+page /
  date-range) and rely on refetch-on-path-change; the refresh button and
  post-mutation callbacks call reload().
- Mutation callbacks become () => void (reload is fire-and-forget); the
  POST/PATCH/DELETE calls still use apiJson/apiFetch directly.

No UI/behavior change. Verified: load, reload, search refetch, detail
sheet, and DataError/EmptyState states all render as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MeProvider split into state-only MeProvider + MeGate (backward-compatible:
checkin/signage wrap content in MeGate, behavior unchanged). admin renders
the shell chrome outside the gate (skeleton nav/account until /api/me),
plus (authed)/error.tsx + root error.tsx + (authed)/loading.tsx.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Split the shared MeProvider into a state-only MeProvider (fetches /api/me,
handles 401, always renders children + provides state) and a MeGate that
does the gating (renders content only when ok, else loading/forbidden/error).
useMe() keeps its non-null signature (safe inside a gate); new useMeState()
feeds the shell. This is an atomic contract change, so all consumers move
together:

- checkin / signage: wrap content in <MeGate> (props moved over) — behavior
  unchanged (the gate logic is the same code, just relocated).
- admin: AppShell renders OUTSIDE the gate so the sidebar/top-bar chrome +
  brand logo paint immediately; sidebar/bottom-nav/mobile-top-bar use
  useMeState() and show skeleton nav/account until /api/me resolves, then the
  real role-filtered nav. Page content stays gated by <MeGate>.

Verified: admin shows the shell + skeleton nav during loading (desktop &
mobile), real nav/account on ok, MeGate forbidden on 403; checkin/signage
render through the relocated gate with no module/render errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- (authed)/error.tsx and root error.tsx ('use client') catch render-time
  throws that the per-page try/catch can't, reusing DataError + a reset button.
- (authed)/loading.tsx renders a content skeleton during soft navigation;
  meaningful now that the shell persists across navigations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ut42tech ut42tech merged commit 39d969b into develop Jun 2, 2026
6 checks passed
@ut42tech ut42tech deleted the feat/admin-resilience-shell branch June 2, 2026 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant