Newer
Older
client_dwatch / app / api / groups / route.ts
/**
 * GET /groups — ホールディングス一覧(分類マスタ。指示書AK 段階1。読み取り専用)
 *
 * 形は `app/api/schedules/route.ts` と同じ。
 * 仕様の正は `d-watch-api.yaml` の /groups。
 *
 * ★GET だけ★ — ★POST / PUT / DELETE を足さないこと★(指示書AK §4-2)。
 *   グループ・顧客マスタのCRUDは D-Security 側の画面で行う(`docs/spec.md`)。
 *   メインDBへの書き込みが許されているのは `robot_error_reports` /
 *   `control_error_histories` の4カラムだけ(`CLAUDE.md` §3 / D-042)。
 *
 * ★認証はここに書かない★ — `proxy.ts` が全ルートを横断して判定する
 *   (`d-watch-api.yaml` の info。未認証は401、IP拒否は403)。
 *
 * ★★ページングしない★★(指示書AK §4-1 #1)— セレクトリスト用なので全件を1ページで返す。
 *   `meta` の意味は `lib/masters/query.ts` の冒頭に書いた。
 */
import { NextResponse } from "next/server";
import { db } from "@/lib/db";
import { masterListResponse, sortGroups } from "@/lib/masters/query";
import { withRequestId } from "@/lib/logger";
import { logApiError } from "@/lib/logger/api";
import type { ApiError, Group, ListResponse } from "@/lib/types";

const ROUTE = "/api/groups";

export async function GET(request: Request) {
  return withRequestId(request, async () => {
    // ★クエリパラメータを持たないので 422 の分岐が無い★
    //   (`app/api/facilities/route.ts` と同じ。YAML も 200 のみを定義している)
    let rows: Group[];
    try {
      rows = await db.groups();
    } catch (e) {
      const body: ApiError = {
        error: {
          code: "internal_error",
          message: "データの取得に失敗しました",
          details: null,
        },
      };
      logApiError({ route: ROUTE, method: "GET", body, status: 500, err: e });
      return NextResponse.json(body, { status: 500 });
    }

    // ここから下は純粋な並べ替え。すべて try の外
    // (`app/api/schedules/route.ts` と同じ方針)。
    const body: ListResponse<Group> = masterListResponse(sortGroups(rows));
    return NextResponse.json(body);
  });
}