Brand Studio docs
Engineering manualAPI route source

/api/brand-studio/visual-direction

Exact current route handler: hosted-app/app/api/brand-studio/visual-direction/route.js

Methods: POST. Input signals: none detected. Literal response-status signals: 400, 403.

Source: hosted-app/app/api/brand-studio/visual-direction/route.js. Imports: ../../../../lib/bounded-http.mjs, @/lib/comprehensive-pull.mjs, @/lib/report-api.mjs, @/lib/supabase-rest.mjs, @/lib/visual-direction.mjs, next/server. Exact source is shown for inspection; its presence does not prove authentication, validation or live behavior.

All API routes · API and execution contract

import { readBoundedJsonRequest } from "../../../../lib/bounded-http.mjs";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";

import { NextResponse } from "next/server";
import { bearerTokenFromHeader } from "@/lib/comprehensive-pull.mjs";
import { readWritablePull, patchSummarySidecar } from "@/lib/report-api.mjs";
import { supabaseConfigFromEnv } from "@/lib/supabase-rest.mjs";
import { applyVisualDirectionAction, visualDirectionWriteAuthority } from "@/lib/visual-direction.mjs";

export async function POST(request) {
  const token = bearerTokenFromHeader(request.headers.get("authorization"));
  let body;
  try { body = await readBoundedJsonRequest(request); }
  catch (error) { return NextResponse.json({ status: "refused", reason: error.code || "invalid_json" }, { status: error.httpStatus || 400 }); }
  const pullId = String(body?.pull_id || "").trim();
  if (!pullId) {
    return NextResponse.json({ status: "blocked", reason: "missing_pull_id" }, { status: 400 });
  }

  const config = supabaseConfigFromEnv(process.env);
  const owned = await readWritablePull({ pullId, token, config, allowAdmin: false });
  if (!owned.ok) return NextResponse.json(owned.body, { status: owned.http_status });

  // Defense in depth after the session-only owner gate. A public-example
  // read or cross-account operator view never supplies write authority.
  const authority = visualDirectionWriteAuthority(owned);
  if (!authority.ok) {
    return NextResponse.json(
      { status: "refused", reason: authority.reason },
      { status: 403 }
    );
  }
  if (!owned.row?.capture_result) {
    return NextResponse.json(
      { status: "blocked", reason: owned.row?.status === "running" ? "pull_still_running" : "source_backed_report_required" },
      { status: owned.row?.status === "running" ? 409 : 422 }
    );
  }

  const applied = applyVisualDirectionAction({
    state: owned.row?.summary?.visual_reference_book,
    action: body?.action,
    pullId,
    now: new Date().toISOString()
  });
  if (!applied.ok) {
    return NextResponse.json({ status: "blocked", reason: applied.reason }, { status: 400 });
  }

  const written = await patchSummarySidecar({
    row: owned.row,
    key: "visual_reference_book",
    value: applied.state,
    config,
    authToken: owned.authToken
  });
  if (!written.ok) return NextResponse.json(written.body, { status: written.http_status });

  return NextResponse.json({
    status: "passed",
    state: applied.state,
    note: applied.state.interview.status === "brief_confirmed"
      ? "The visual brief is confirmed. Full-size visual approval is still required before code, animation, or editable reconstruction."
      : "Your visual direction state is saved."
  });
}