Conversation
- /internal/events を月間カレンダーに作り直し、これからの予定も並べる - /internal/admin/events で運営がイベントを追加・編集・削除できるようにする - events コレクションを CircleEvent (startAt/endAt/allDay/location/source) に定義し直す source と sourceRef は mini LT 取り込み (#299) 用に先に確保 - 日時は日本時間固定で扱う (lib/events-format.ts) - 運営 API 共通の認可 authorizeAdminApi を追加 (退会済みセッションも弾く) closes #174 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gtw14tqkjpEogwKBR6Bcd8
|
Deployed on https://dev-pr-300-birbz3fm6q-an.a.run.app |
Shion1305
left a comment
There was a problem hiding this comment.
ひとまず、気になったポイントを指摘しました。
(All reviews are authored manually by @Shion1305 )
| const authorized = await authorizeAdminApi(); | ||
| if ("response" in authorized) return authorized.response; |
There was a problem hiding this comment.
adminAPIとしての認可というよりかはNewsを編集する権限があるかとしての認可という実装にしたい
(現状Adminかどうかが編集権限であるという実装であるとしても、責務上の切り分けとして)
There was a problem hiding this comment.
#284 と同じ形に揃えました(a60bf5c → 979c891)。
isEventEditor(session): boolean(lib/event-auth.ts)+EVENT_API_RESPONSES(lib/events-response.ts)- 「管理者か」ではなく「イベントを編集できるか」の判定として切り出したので、権限の持ち方を変えるときはここだけ差し替えれば済むようにしています
lib/event-auth.test.tsを追加(退会済みで admin フラグが残っているケース含む)
| } | ||
|
|
||
| const month = | ||
| new URL(request.url).searchParams.get("month") ?? todayJstKey().slice(0, 7); |
There was a problem hiding this comment.
了解です。#236 がマージされたら、todayJstKey 周りを lib/date.ts の getJstToday / getDateParts / ISODateString に載せ替える形でリベースします。それまでこの PR は Hold で。
| export function EventCalendar({ month, events, today }: EventCalendarProps) { | ||
| const [selected, setSelected] = useState<string | null>(null); | ||
| const days = useMemo(() => monthGridDays(month), [month]); | ||
| const thisMonth = today.slice(0, 7); |
There was a problem hiding this comment.
#236 (comment)
slice 使う実装甘いよねって話になって、 #236 でここら辺のモジュール実装導入されるのでそれまでお待ち 🙏
There was a problem hiding this comment.
了解です。日付キーの slice はここ以外にも lib/events-format.ts に何か所かあるので、#236 の getDateParts / ISODateString が入ったらまとめて置き換えます(それまで Hold)。
| * 日時はすべて日本時間で入力・表示する。保存は UTC の Timestamp なので、 | ||
| * 表示側は必ず Asia/Tokyo で整形する (lib/events-format.ts)。 | ||
| */ | ||
| export interface CircleEvent { |
There was a problem hiding this comment.
サークルは和製英語で サークル ≠ circle です
Eventを変えたいなら LumosEvent とか CludEvent とかかな
There was a problem hiding this comment.
LumosEvent に改名しました(979c891)。LumosEventInput も同様です。
| const startAt = jstLocalToIso(form.start); | ||
| if (!form.title.trim() || !startAt) { | ||
| setError("タイトルと開始日時を入力してください"); | ||
| return; | ||
| } | ||
| const endAt = form.end ? jstLocalToIso(form.end) : null; | ||
| if (form.end && !endAt) { | ||
| setError("終了日時の形式が正しくありません"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
バリデーションロジックについてはzodを使った実装にして欲しいです
There was a problem hiding this comment.
lib/events-form.ts に zod スキーマ(eventFormSchema)としてまとめました(979c891)。
- 必須・日時の形式・「終了は開始より後」を
refine/superRefineで検証し、handleSubmitはsafeParseして最初の issue を出すだけにしています - 文言はサーバー側の
parseEventInputと同じEVENT_ERROR_RESPONSESを使うので、どちらで弾かれても同じ表示になります lib/events-form.test.tsを追加(5 件)
Shion1305
left a comment
There was a problem hiding this comment.
ひとまず、気になったポイントを指摘しました。
(All reviews are authored manually by @Shion1305 )
#284 のレビュー指摘に合わせて、authorizeAdminApi() を isAdminSession(session) に置き換え、 401 / 403 / success などの定型レスポンスを EVENT_API_RESPONSES にまとめる Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gtw14tqkjpEogwKBR6Bcd8
|
Deployed on https://dev-pr-300-birbz3fm6q-an.a.run.app |
- CircleEvent → LumosEvent (サークル ≠ circle) - 認可を「管理者か」ではなく「イベントを編集できるか」として lib/event-auth.ts の isEventEditor に - 管理フォームの検証を lib/events-form.ts の zod スキーマにまとめ、文言をサーバー側と揃える Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gtw14tqkjpEogwKBR6Bcd8
|
Deployed on https://dev-pr-300-birbz3fm6q-an.a.run.app |
closes #174
概要
一般メンバーが見られるサークル内イベントのカレンダーページと、運営がイベントを登録するダッシュボードを追加します。
/internal/events— 月間カレンダー。?m=YYYY-MMで月移動、日付クリックでその日のイベントに絞り込み。右側に「これからの予定」/internal/admin/events— 運営がイベントを追加・編集・削除するフォーム(管理者ページにもリンクを追加)mini LT の開催回をここに取り込む件は #299 に切り出しました。データ側には
source: "manual" | "mini-lt"とsourceRef(週 ID) を先に用意してあります。変更点
データ
types/event.ts— 既存のEvent(date文字列だけ) をCircleEventに定義し直し。startAt/endAt(Timestamp)、allDay、location、source、sourceRef、createdByeventsコレクションはこれまで読むだけで書き込み経路が無かったので、既存データの移行は不要lib/events.ts— 月間取得・これからの予定・管理用一覧・CRUD・zod 入力検証startAtを前月頭から絞ってメモリ側で重なり判定 (前月から続く長いイベントを拾いつつ、複合インデックスを増やさない)lib/events-format.ts— 日時は日本時間固定。datetime-local⇄ ISO、月グリッド、"9月20日(土) 19:00〜21:00"形式の表記などAPI
lib/admin-api-auth.ts— 運営 API 共通の認可authorizeAdminApi()。isAdminに加えてsession.user.optedOutも弾く (✨ お知らせをWebUIから作成・公開できるようにする #284 の指摘と同じ観点)app/api/events—GET ?month=(要ログイン) /POST(運営)app/api/events/[id]—PUT/DELETE(運営)UI
components/events/event-calendar.tsx— 月グリッド (日曜始まり、sm未満は点、以上はタイトル入りチップ、4 件以上は "+N件")components/events/event-item.tsx— 一覧カード (カレンダー・これからの予定・管理画面で共通)components/events/event-manager.tsx— 運営用フォーム。「終日」を切り替えると日付入力に変わり、入力済みの日付は保持components/event-list.tsxは削除テスト
lib/events.test.ts— 日時変換・月グリッド・日付範囲・入力検証・CRUD・月間/これから/管理用の取得 (12 件)動作確認
ローカル (エミュレータ) でブラウザ確認済み:
注意
lib/events.test.tsのbeforeEachは既存のblogs.test.tsと同じく全コレクションを消します。just devで立てた 8080 のエミュレータに対して vitest を直接回すと開発データが消えます🤖 Generated with Claude Code
https://claude.ai/code/session_01Gtw14tqkjpEogwKBR6Bcd8