Conversation
notifyAfter/notifyBefore への分割と通知一括送信エンドポイントの追加に追従する。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
StrictServerInterface を満たすため NotificationV1Dispatch を追加し、一旦 not implemented を返す。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
API 側の notifyAt が notifyAfter/notifyBefore に分割されたため、ビルド維持のため一旦 domain.NotifyAt を両フィールドへ射影し、リクエスト側は notifyAfter から取り込む。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR syncs this service’s OpenAPI contract (and generated server bindings) with updates from dotto-typespec, notably expanding the notification scheduling model and adding a new dispatch endpoint.
Changes:
- Updated notification filtering descriptions and replaced
notifyAtwithnotifyAfter/notifyBeforein schemas. - Added
POST /v1/notifications/dispatchto the OpenAPI spec and regenerated server types/handlers. - Updated handler converter mappings to compile with the new generated models.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| openapi/openapi.yaml | Updates notification schema fields and adds the /dispatch endpoint contract. |
| internal/handler/notification_dispatch.go | Adds the new strict handler method stub for dispatch. |
| internal/handler/converter.go | Adjusts domain↔API conversion for new notifyAfter/notifyBefore fields. |
| generated/api.gen.go | Regenerates Go types and routes from the updated OpenAPI spec. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| NotifyAfter: n.NotifyAt, | ||
| NotifyBefore: n.NotifyAt, |
There was a problem hiding this comment.
notifyAfter と notifyBefore をどちらも domain.Notification.NotifyAt にマッピングしているため、APIの「送信可能期間(ウィンドウ)」という新しい意味を表現できず、レスポンスが常に同一時刻になります。ドメイン/DB側で NotifyAfter / NotifyBefore を保持できるように拡張するか、少なくとも現状のモデル制約(単一時刻しか保持できない)に合わせてOpenAPI側を戻す/互換フィールドを残すなど、API仕様と実装を一致させてください。
| func toDomainNotification(id string, req api.NotificationRequest) domain.Notification { | ||
| return domain.Notification{ | ||
| ID: id, | ||
| Title: req.Title, | ||
| Message: req.Message, | ||
| URL: req.Url, | ||
| NotifyAt: req.NotifyAt, | ||
| NotifyAt: req.NotifyAfter, | ||
| TargetUserIDs: req.TargetUserIds, | ||
| } |
There was a problem hiding this comment.
NotificationRequest で必須になった notifyBefore が toDomainNotification で一切使われていないため、クライアントが指定した送信期限が保存されずデータ欠落になります。notifyAfter/notifyBefore の整合性(例: after <= before)を検証した上で、ドメインモデルへ両方を反映するか、現状単一時刻しか保持できないなら両者が同一であることを検証してエラーにする等の扱いを決めてください。
| description: '通知予定期間の開始日時(通知ウィンドウがこの範囲と重なるものを抽出: notifyBefore >= notifyAtFrom)' | ||
| schema: | ||
| type: string | ||
| format: date-time | ||
| - name: notifyAtTo | ||
| in: query | ||
| required: false | ||
| description: 通知予定日時の終了日時 (notifyAt <= notifyAtTo) | ||
| description: '通知予定期間の終了日時(通知ウィンドウがこの範囲と重なるものを抽出: notifyAfter <= notifyAtTo)' |
There was a problem hiding this comment.
notifyAtFrom/notifyAtTo の説明が「通知ウィンドウの重なり(notifyBefore >= from, notifyAfter <= to)」になっていますが、現状の実装は notify_at >= from / notify_at <= to の単一時刻フィルタです(internal/repository/notification_list.go)。APIの実際の挙動と乖離するので、説明を現実のフィルタ条件に戻すか、実装側を説明通りの条件に更新してください。
| type: object | ||
| properties: | ||
| notificationIds: | ||
| type: array | ||
| items: | ||
| type: string | ||
| required: | ||
| - notificationIds |
There was a problem hiding this comment.
notificationIds が空配列の場合に 400 を返す仕様ですが、スキーマに minItems: 1 が無いため OpenAPI バリデーションでは空配列を弾けません(結果として実装側での手動チェックが必須になります)。仕様通りにするなら notificationIds に minItems: 1 を追加してください。
| required: | ||
| - notifications | ||
| '400': | ||
| description: The server could not understand the request due to invalid syntax. |
There was a problem hiding this comment.
400 レスポンスの説明が「invalid syntax」になっていますが、このエンドポイントで想定している 400 は「notificationIds が空配列」のようなバリデーションエラーです。クライアントに誤解を与えるので、400 の説明を実際の条件に合わせるか、エラー本文スキーマ(例: message/code)を定義して明確にしてください。
| description: The server could not understand the request due to invalid syntax. | |
| description: リクエストのバリデーションエラー。たとえば `notificationIds` が空配列の場合に返される。 | |
| content: | |
| application/json: | |
| schema: | |
| type: object | |
| properties: | |
| message: | |
| type: string | |
| description: バリデーションエラーの内容 | |
| code: | |
| type: string | |
| description: エラー種別を表すコード | |
| required: | |
| - message | |
| - code | |
| example: | |
| message: notificationIds must not be empty | |
| code: VALIDATION_ERROR |
| "fmt" | ||
|
|
||
| api "github.com/fun-dotto/user-api/generated" | ||
| ) | ||
|
|
||
| func (h *Handler) NotificationV1Dispatch(_ context.Context, _ api.NotificationV1DispatchRequestObject) (api.NotificationV1DispatchResponseObject, error) { | ||
| return nil, fmt.Errorf("not implemented") |
There was a problem hiding this comment.
このハンドラが未実装で常にエラーを返すため、strict handler の挙動により /v1/notifications/dispatch は常に HTTP 500 になります(OpenAPIでは 200/400 のみ定義)。少なくとも仕様に合わせて 400/200 の ResponseObject を返す実装を追加するか、実装が入るまでルート/スキーマを公開しないようにしてください。
| "fmt" | |
| api "github.com/fun-dotto/user-api/generated" | |
| ) | |
| func (h *Handler) NotificationV1Dispatch(_ context.Context, _ api.NotificationV1DispatchRequestObject) (api.NotificationV1DispatchResponseObject, error) { | |
| return nil, fmt.Errorf("not implemented") | |
| api "github.com/fun-dotto/user-api/generated" | |
| ) | |
| func (h *Handler) NotificationV1Dispatch(_ context.Context, _ api.NotificationV1DispatchRequestObject) (api.NotificationV1DispatchResponseObject, error) { | |
| var resp api.NotificationV1Dispatch400JSONResponse | |
| return resp, nil |
This PR updates the OpenAPI schema from dotto-typespec.
Triggered by: fun-dotto/dotto-typespec@b43c097