diff --git a/artifacts/tests/a11y-manual/TECH_LOG_STUDIO_TAXONOMY.md b/artifacts/tests/a11y-manual/TECH_LOG_STUDIO_TAXONOMY.md
new file mode 100644
index 0000000..681e27d
--- /dev/null
+++ b/artifacts/tests/a11y-manual/TECH_LOG_STUDIO_TAXONOMY.md
@@ -0,0 +1,18 @@
+# TECH_LOG_STUDIO_TAXONOMY accessibility review
+
+Status: pending-manual-review
+Route ID: TECH_LOG_STUDIO_TAXONOMY
+Release ID:
+Reviewer:
+Reviewed at:
+Signature:
+Attestation: pending
+M1 Keyboard: pending
+M2 Visible focus: pending
+M3 Route focus: pending
+M4 Modal focus: pending
+M5 Error association: pending
+M6 Color signal: pending
+M7 Reduced motion: pending
+Screen reader: pending
+Notes: Human review pending; automated evidence does not replace signed keyboard, focus, and screen-reader review.
diff --git a/config/ci/gates.json b/config/ci/gates.json
index 6bf78f8..b4655a8 100644
--- a/config/ci/gates.json
+++ b/config/ci/gates.json
@@ -1196,6 +1196,12 @@
"schemaId": "markdown",
"production": "source-controlled"
},
+ {
+ "id": "artifact-artifacts-tests-a11y-manual-TECH-LOG-STUDIO-TAXONOMY-md",
+ "path": "artifacts/tests/a11y-manual/TECH_LOG_STUDIO_TAXONOMY.md",
+ "schemaId": "markdown",
+ "production": "source-controlled"
+ },
{
"id": "artifact-artifacts-tests-a11y-manual-TECH-LOG-STUDIO-NOT-FOUND-md",
"path": "artifacts/tests/a11y-manual/TECH_LOG_STUDIO_NOT_FOUND.md",
@@ -1949,6 +1955,7 @@
"artifact-artifacts-tests-a11y-manual-TECH-LOG-STUDIO-PUBLICATIONS-md",
"artifact-artifacts-tests-a11y-manual-TECH-LOG-STUDIO-PUBLICATION-PREVIEW-md",
"artifact-artifacts-tests-a11y-manual-TECH-LOG-STUDIO-ASSETS-md",
+ "artifact-artifacts-tests-a11y-manual-TECH-LOG-STUDIO-TAXONOMY-md",
"artifact-artifacts-tests-a11y-manual-TECH-LOG-STUDIO-NOT-FOUND-md",
"artifact-artifacts-tests-a11y-manual-NOT-FOUND-md",
"artifact-artifacts-tests-a11y-manual-report-json"
diff --git a/config/runtime/production.json b/config/runtime/production.json
index b3f734d..b1d66b4 100644
--- a/config/runtime/production.json
+++ b/config/runtime/production.json
@@ -15,7 +15,7 @@
"OFFLINE_COMMANDS": "DEFAULT"
},
"TECH_LOG_STUDIO_SOURCE": "HTTP",
- "TECH_LOG_PUBLIC_SOURCE": "MOCK",
+ "TECH_LOG_PUBLIC_SOURCE": "HTTP",
"FEATURE_OVERRIDES": {
"reference-feature": "DEFAULT"
}
diff --git a/public/release-manifest.json b/public/release-manifest.json
index f49e5e8..2ec5e30 100644
--- a/public/release-manifest.json
+++ b/public/release-manifest.json
@@ -38,21 +38,28 @@
},
"contractSet": {
"setAlgorithm": "CA_CONTRACT_SET_V1",
- "setDigest": "sha256:c8a29bdf6deadd8951b0a15426fcc119ff85ee9349acc0e8b200c8a5650d8b31",
+ "setDigest": "sha256:ac1448ced933beece92924be4ffb7beb182c3df26371a83ffeffbb174ce98e72",
"packages": [
+ {
+ "packageId": "@tech-log/management-contract",
+ "version": "1.0.0",
+ "digest": "sha256:ec5e432215fb041abee980787366a6db29ff1ecdd78416aa9c61e09b9b91022f",
+ "runtimeProtocolVersion": 1,
+ "sourceRevision": "6ef5c1c"
+ },
{
"packageId": "@tech-log/public-contract",
"version": "2.0.0",
"digest": "sha256:8ac71425b38658f34641102b4c2e6e21288c811efebdb92c0a46fb9d4790e23e",
"runtimeProtocolVersion": 1,
- "sourceRevision": "b98eaf9"
+ "sourceRevision": "6ef5c1c"
},
{
"packageId": "@tech-log/studio-contract",
"version": "3.0.0",
"digest": "sha256:6cae9924403d0761f401643a022980b8e04183eea0d890c143c9fbbbbc7431e4",
"runtimeProtocolVersion": 1,
- "sourceRevision": "b98eaf9"
+ "sourceRevision": "6ef5c1c"
}
]
}
diff --git a/scripts/contracts/ci-gates.ts b/scripts/contracts/ci-gates.ts
index 2b21f31..2db948e 100644
--- a/scripts/contracts/ci-gates.ts
+++ b/scripts/contracts/ci-gates.ts
@@ -459,7 +459,12 @@ const CANONICAL_GATE_SHAPE_SHA256 =
// Dev release manifest drift fix, item 2: recomputed again after FE-GATE-010
// gained `check-dev-release-manifest`. Same method — 98d19911… was first
// reproduced from the previous gates.json before this value was hashed.
- "b40962448e617883060e09eb7183837cfea6833519f435f11713efd083210dbe";
+ // Taxonomy route: recomputed again after FE-GATE-009 gained the
+ // TECH_LOG_STUDIO_TAXONOMY manual accessibility evidence artifact. The gate
+ // lists one evidence artifact per installed route and refuses a set that does
+ // not match the route scope exactly, so adding a route necessarily moves this
+ // digest — that is the point of pinning it.
+ "8c73d4477392a63e91088ff91e53293e7fc3ace891f8eb3da3b0d05fa714df60";
function canonicalGateShapeSha256(gates: CiGateContract["gates"]): string {
const normalized = gates.map(
@@ -512,8 +517,10 @@ function canonicalAuthorityBaselineFailures(contract: CiGateContract): string[]
// Template merge. 126 product artifacts plus the two the template added.
// Task 11 added one more: the TECH_LOG_STUDIO_ASSETS manual a11y evidence file.
// Alignment follow-up, item 2 added the TechLog junit report.
- if (contract.artifacts.length !== 130) {
- failures.push(`artifact authority baseline must contain exactly 130 artifacts; received ${contract.artifacts.length}`);
+ // The taxonomy route added its own manual a11y evidence file — every installed
+ // route carries one, and the gate checks that the two sets match exactly.
+ if (contract.artifacts.length !== 131) {
+ failures.push(`artifact authority baseline must contain exactly 131 artifacts; received ${contract.artifacts.length}`);
}
if (contract.stages.length !== 5) {
failures.push(`stage authority baseline must contain exactly 5 stages; received ${contract.stages.length}`);
diff --git a/scripts/generate-tech-log-contract.ts b/scripts/generate-tech-log-contract.ts
index 02ce433..30070c6 100644
--- a/scripts/generate-tech-log-contract.ts
+++ b/scripts/generate-tech-log-contract.ts
@@ -50,6 +50,14 @@ const CONTRACTS: readonly ContractTarget[] = Object.freeze([
generated: "src/features/tech-log/contracts/public/generated.ts",
sourceRecord: "src/features/tech-log/contracts/public/canonical-source.json",
}),
+ Object.freeze({
+ name: "management",
+ packageId: "@tech-log/management-contract",
+ canonicalYaml: `${CANONICAL_ROOT}/contracts/openapi/studio-management-v1.yaml`,
+ vendorYaml: "src/features/tech-log/contracts/management/management-api.openapi.yaml",
+ generated: "src/features/tech-log/contracts/management/generated.ts",
+ sourceRecord: "src/features/tech-log/contracts/management/canonical-source.json",
+ }),
]);
const OPENAPI_TYPESCRIPT = "openapi-typescript@7.9.1";
diff --git a/scripts/lib/tech-log-serving-contract.ts b/scripts/lib/tech-log-serving-contract.ts
index 9c5c506..caa7bf8 100644
--- a/scripts/lib/tech-log-serving-contract.ts
+++ b/scripts/lib/tech-log-serving-contract.ts
@@ -56,6 +56,7 @@ const studioSpaPathPatterns = Object.freeze([
// reload of /studio/assets was served the in-shell Studio 404 -- the screen
// was only reachable by client-side navigation from another Studio page.
"^/studio/assets$",
+ "^/studio/taxonomy$",
"^/studio/documents$",
"^/studio/documents/new$",
"^/studio/documents/[^/]+/(edit|validation|preview|publish)$",
diff --git a/src/features/installed-contract-contributions.ts b/src/features/installed-contract-contributions.ts
index 448d646..753abd9 100644
--- a/src/features/installed-contract-contributions.ts
+++ b/src/features/installed-contract-contributions.ts
@@ -6,6 +6,7 @@ import {
import { REFERENCE_FEATURE_TEMPLATE_CONTRIBUTION } from "./reference-feature/contracts/reference-feature-contract-contribution.ts";
import { REFERENCE_FEATURE_ID } from "./reference-feature/contracts/reference-feature-contract.ts";
import { INSTALLED_PRODUCT_FEATURE_IDS } from "./installed-product-manifest.ts";
+import { TECH_LOG_MANAGEMENT_CONTRIBUTION } from "./tech-log/contracts/tech-log-management-contract-contribution.ts";
import { TECH_LOG_PUBLIC_CONTRIBUTION } from "./tech-log/contracts/tech-log-public-contract-contribution.ts";
import { TECH_LOG_STUDIO_CONTRIBUTION } from "./tech-log/contracts/tech-log-studio-contract-contribution.ts";
@@ -23,8 +24,13 @@ export const INSTALLED_CONTRACT_CONTRIBUTIONS: readonly InstalledContractContrib
REFERENCE_FEATURE_TEMPLATE_CONTRIBUTION,
TECH_LOG_STUDIO_CONTRIBUTION,
TECH_LOG_PUBLIC_CONTRIBUTION,
+ TECH_LOG_MANAGEMENT_CONTRIBUTION,
]
- : [TECH_LOG_STUDIO_CONTRIBUTION, TECH_LOG_PUBLIC_CONTRIBUTION],
+ : [
+ TECH_LOG_STUDIO_CONTRIBUTION,
+ TECH_LOG_PUBLIC_CONTRIBUTION,
+ TECH_LOG_MANAGEMENT_CONTRIBUTION,
+ ],
);
export const COMPOSED_CONTRACT_CONTRIBUTIONS = composeContractContributions(
diff --git a/src/features/tech-log/adapters/create-tech-log-feature-input.ts b/src/features/tech-log/adapters/create-tech-log-feature-input.ts
index 416506f..194670e 100644
--- a/src/features/tech-log/adapters/create-tech-log-feature-input.ts
+++ b/src/features/tech-log/adapters/create-tech-log-feature-input.ts
@@ -12,6 +12,7 @@ import {
import type { CsrfTokenProvider } from "./http/studio-session-csrf.ts";
import { createMockStudioAssetGateway } from "./mock/mock-studio-asset-gateway.ts";
import { createMockStudioGateway } from "./mock/mock-studio-gateway.ts";
+import { createHttpManagementGateway } from "./http/http-management-gateway.ts";
import { createHttpPublicContentGateway } from "./http/http-public-content-gateway.ts";
import { publicContentQueries } from "./static/public-query.ts";
@@ -76,8 +77,12 @@ export function createTechLogFeatureInstalledInput(
? publicContentQueries
: createHttpPublicContentGateway({ operations: context.contractOperations });
+ const createManagementGateway = () =>
+ createHttpManagementGateway({ operations: context.contractOperations });
+
const input: TechLogFeatureInput = Object.freeze({
publicContent,
+ createManagementGateway,
createStudioGateway,
createStudioAssetGateway,
});
diff --git a/src/features/tech-log/adapters/http/http-management-gateway.ts b/src/features/tech-log/adapters/http/http-management-gateway.ts
new file mode 100644
index 0000000..9f62f14
--- /dev/null
+++ b/src/features/tech-log/adapters/http/http-management-gateway.ts
@@ -0,0 +1,64 @@
+import type {
+ CreateDraftResponse,
+ ProjectEditResponse,
+ ProjectIndexPage,
+ ProjectUpdateRequest,
+ TopicEdit,
+} from "../../contracts/management/contract.ts";
+import type { ManagementGateway } from "../../application/ports/management-gateway.ts";
+import type { StudioOperationExecutor } from "./http-studio-gateway.ts";
+
+export type { ManagementGateway };
+
+const ROUTE_ID = "TECH_LOG_STUDIO";
+
+/**
+ * 주제·프로젝트 관리 게이트웨이.
+ *
+ *
Studio 게이트웨이와 같은 실패 규약을 쓴다 — 실패는 던지고, 화면은 `usePublicContent` 가 아니라
+ * Studio 쪽 상태 처리를 그대로 쓴다. 여기서 Result 로 감싸면 이 표면만 다른 규약이 된다.
+ */
+
+export class ManagementGatewayError extends Error {
+ readonly operationId: string;
+ readonly code: string;
+
+ constructor(operationId: string, code: string) {
+ super(`${operationId}: ${code}`);
+ this.name = "ManagementGatewayError";
+ this.operationId = operationId;
+ this.code = code;
+ }
+}
+
+export function createHttpManagementGateway(
+ deps: Readonly<{ operations: StudioOperationExecutor }>,
+): ManagementGateway {
+ async function run(operationId: string, input: unknown): Promise {
+ const outcome = await deps.operations.execute(operationId, input, { routeId: ROUTE_ID });
+ if (outcome.kind === "SUCCESS") return outcome.value as T;
+ if (outcome.kind === "PROBLEM") {
+ const problem = outcome.problem as Readonly<{ code?: string }> | null;
+ throw new ManagementGatewayError(operationId, problem?.code ?? "PROBLEM");
+ }
+ throw new ManagementGatewayError(operationId, outcome.kind);
+ }
+
+ return Object.freeze({
+ listTopics: () => run("listStudioTopics", {}),
+ createTopic: (input: TopicEdit) => run("createTopic", input),
+ updateTopic: (id: string, body: TopicEdit) => run("updateTopic", { id, body }),
+ deleteTopic: async (id: string, expectedVersion: number) => {
+ await run("deleteTopic", { id, expectedVersion });
+ },
+ listProjects: (page?: number, size?: number) =>
+ run("listStudioProjects", { ...(page !== undefined ? { page } : {}), ...(size !== undefined ? { size } : {}) }),
+ getProject: (id: string) => run("getProjectForEdit", { id }),
+ createProject: (title: string) => run("createProject", { title }),
+ updateProject: (id: string, body: ProjectUpdateRequest) =>
+ run("updateProject", { id, body }),
+ deleteProject: async (id: string, expectedVersion: number) => {
+ await run("deleteProject", { id, expectedVersion });
+ },
+ });
+}
diff --git a/src/features/tech-log/application/ports/management-gateway.ts b/src/features/tech-log/application/ports/management-gateway.ts
new file mode 100644
index 0000000..e0a7057
--- /dev/null
+++ b/src/features/tech-log/application/ports/management-gateway.ts
@@ -0,0 +1,26 @@
+import type {
+ CreateDraftResponse,
+ ProjectEditResponse,
+ ProjectIndexPage,
+ ProjectUpdateRequest,
+ TopicEdit,
+} from "../../contracts/management/contract.ts";
+
+/**
+ * 주제·프로젝트 관리 표면.
+ *
+ * Studio 게이트웨이와 같은 실패 규약이다 — 실패는 던지고, 화면이 잡는다. MOCK 대응물을 두지
+ * 않는 것도 의도다: 이 표면은 백엔드가 없으면 존재할 이유가 없고, 픽스처를 만들면 실제로는 만들
+ * 수 없는 주제를 화면이 보여주게 된다.
+ */
+export type ManagementGateway = Readonly<{
+ listTopics(): Promise;
+ createTopic(input: TopicEdit): Promise;
+ updateTopic(id: string, body: TopicEdit): Promise;
+ deleteTopic(id: string, expectedVersion: number): Promise;
+ listProjects(page?: number, size?: number): Promise;
+ getProject(id: string): Promise;
+ createProject(title: string): Promise;
+ updateProject(id: string, body: ProjectUpdateRequest): Promise;
+ deleteProject(id: string, expectedVersion: number): Promise;
+}>;
diff --git a/src/features/tech-log/application/tech-log-feature-input.ts b/src/features/tech-log/application/tech-log-feature-input.ts
index 8f150f1..fadb72c 100644
--- a/src/features/tech-log/application/tech-log-feature-input.ts
+++ b/src/features/tech-log/application/tech-log-feature-input.ts
@@ -1,5 +1,6 @@
import type { PublicContentQueries } from "./ports/public-content-queries.ts";
import type { StudioAssetGateway } from "./ports/studio-asset-gateway.ts";
+import type { ManagementGateway } from "./ports/management-gateway.ts";
import type { StudioGateway } from "./ports/studio-gateway.ts";
export const TECH_LOG_FEATURE_ID = "tech-log" as const;
@@ -8,6 +9,9 @@ export type TechLogFeatureInput = Readonly<{
publicContent: PublicContentQueries;
createStudioGateway(): StudioGateway;
createStudioAssetGateway(): StudioAssetGateway;
+ // 주제·프로젝트 관리. MOCK 대응물이 없다 — 이 표면은 백엔드가 없으면 존재할 이유가 없고,
+ // 픽스처를 만들면 실제로는 못 만드는 주제를 화면이 보여주게 된다.
+ createManagementGateway(): ManagementGateway;
}>;
declare module "../../../application/ports/in/application-api.ts" {
diff --git a/src/features/tech-log/contracts/management/canonical-source.json b/src/features/tech-log/contracts/management/canonical-source.json
new file mode 100644
index 0000000..bf05689
--- /dev/null
+++ b/src/features/tech-log/contracts/management/canonical-source.json
@@ -0,0 +1,87 @@
+{
+ "packageId": "@tech-log/management-contract",
+ "version": "1.0.0",
+ "digest": "sha256:ec5e432215fb041abee980787366a6db29ff1ecdd78416aa9c61e09b9b91022f",
+ "sourceRevision": "6ef5c1c",
+ "operationIds": [
+ "createCaseDraft",
+ "getCaseForEdit",
+ "updateCaseDraft",
+ "deleteCaseDraft",
+ "createReferenceDraft",
+ "getReferenceForEdit",
+ "updateReferenceDraft",
+ "deleteReferenceDraft",
+ "validateCase",
+ "submitReviewCase",
+ "returnToDraftCase",
+ "unpublishCase",
+ "archiveCase",
+ "restoreCase",
+ "publishCase",
+ "validateReference",
+ "submitReviewReference",
+ "returnToDraftReference",
+ "unpublishReference",
+ "archiveReference",
+ "restoreReference",
+ "publishReference",
+ "createQuestion",
+ "listStudioQuestions",
+ "getQuestionForEdit",
+ "updateQuestion",
+ "deleteQuestion",
+ "addQuestionUpdate",
+ "updateQuestionUpdate",
+ "deleteQuestionUpdate",
+ "resolveQuestion",
+ "startQuestionInvestigation",
+ "pauseQuestion",
+ "resumeQuestion",
+ "reopenQuestion",
+ "archiveQuestion",
+ "publishQuestion",
+ "unpublishQuestion",
+ "createProject",
+ "listStudioProjects",
+ "getProjectForEdit",
+ "updateProject",
+ "deleteProject",
+ "changeProjectPhase",
+ "publishProject",
+ "unpublishProject",
+ "createProjectDecision",
+ "listStudioProjectDecisions",
+ "getProjectDecision",
+ "updateProjectDecision",
+ "acceptProjectDecision",
+ "rejectProjectDecision",
+ "supersedeProjectDecision",
+ "createRelease",
+ "listStudioReleases",
+ "getReleaseForEdit",
+ "updateRelease",
+ "deleteRelease",
+ "publishRelease",
+ "archiveRelease",
+ "listStudioTopics",
+ "createTopic",
+ "updateTopic",
+ "deleteTopic",
+ "listStudioTags",
+ "createTag",
+ "updateTag",
+ "deleteTag",
+ "getStudioSite",
+ "updateStudioSite",
+ "getStudioProfile",
+ "updateStudioProfile",
+ "publishProfile",
+ "unpublishProfile",
+ "getHomeFocus",
+ "updateHomeFocus",
+ "listStudioProjectActivities",
+ "createProjectActivity",
+ "updateProjectActivity"
+ ]
+}
diff --git a/src/features/tech-log/contracts/management/contract.ts b/src/features/tech-log/contracts/management/contract.ts
new file mode 100644
index 0000000..4984668
--- /dev/null
+++ b/src/features/tech-log/contracts/management/contract.ts
@@ -0,0 +1,12 @@
+import type { components } from "./generated.ts";
+
+type Schemas = components["schemas"];
+
+export type TopicEdit = Schemas["TopicEdit"];
+export type ProjectEditResponse = Schemas["ProjectEditResponse"];
+export type ProjectIndexItem = Schemas["ProjectIndexItem"];
+export type ProjectIndexPage = Schemas["ProjectIndexPage"];
+export type ProjectUpdateRequest = Schemas["ProjectUpdateRequest"];
+export type CreateDraftRequest = Schemas["CreateDraftRequest"];
+export type CreateDraftResponse = Schemas["CreateDraftResponse"];
+export type ExpectedVersionRequest = Schemas["ExpectedVersionRequest"];
diff --git a/src/features/tech-log/contracts/management/generated.ts b/src/features/tech-log/contracts/management/generated.ts
new file mode 100644
index 0000000..a078080
--- /dev/null
+++ b/src/features/tech-log/contracts/management/generated.ts
@@ -0,0 +1,8387 @@
+/**
+ * This file was auto-generated by openapi-typescript.
+ * Do not make direct changes to the file.
+ */
+
+export interface paths {
+ "/api/v1/studio/cases": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["createCaseDraft"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/cases/{id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["getCaseForEdit"];
+ put: operations["updateCaseDraft"];
+ post?: never;
+ delete: operations["deleteCaseDraft"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/references": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["createReferenceDraft"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/references/{id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["getReferenceForEdit"];
+ put: operations["updateReferenceDraft"];
+ post?: never;
+ delete: operations["deleteReferenceDraft"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/cases/{id}/validate": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["validateCase"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/cases/{id}/submit-review": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["submitReviewCase"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/cases/{id}/return-to-draft": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["returnToDraftCase"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/cases/{id}/unpublish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["unpublishCase"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/cases/{id}/archive": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["archiveCase"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/cases/{id}/restore": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["restoreCase"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/cases/{id}/publish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["publishCase"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/references/{id}/validate": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["validateReference"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/references/{id}/submit-review": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["submitReviewReference"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/references/{id}/return-to-draft": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["returnToDraftReference"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/references/{id}/unpublish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["unpublishReference"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/references/{id}/archive": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["archiveReference"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/references/{id}/restore": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["restoreReference"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/references/{id}/publish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["publishReference"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["listStudioQuestions"];
+ put?: never;
+ post: operations["createQuestion"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["getQuestionForEdit"];
+ put: operations["updateQuestion"];
+ post?: never;
+ delete: operations["deleteQuestion"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/updates": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["addQuestionUpdate"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/updates/{updateId}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put: operations["updateQuestionUpdate"];
+ post?: never;
+ delete: operations["deleteQuestionUpdate"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/resolve": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["resolveQuestion"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/start-investigation": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["startQuestionInvestigation"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/pause": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["pauseQuestion"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/resume": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["resumeQuestion"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/reopen": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["reopenQuestion"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/archive": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["archiveQuestion"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/publish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["publishQuestion"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/questions/{id}/unpublish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["unpublishQuestion"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["listStudioProjects"];
+ put?: never;
+ post: operations["createProject"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["getProjectForEdit"];
+ put: operations["updateProject"];
+ post?: never;
+ delete: operations["deleteProject"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/change-phase": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["changeProjectPhase"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/publish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["publishProject"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/unpublish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["unpublishProject"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/decisions": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["listStudioProjectDecisions"];
+ put?: never;
+ post: operations["createProjectDecision"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/decisions/{decisionId}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["getProjectDecision"];
+ put: operations["updateProjectDecision"];
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/decisions/{decisionId}/accept": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["acceptProjectDecision"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/decisions/{decisionId}/reject": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["rejectProjectDecision"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/decisions/{decisionId}/supersede": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["supersedeProjectDecision"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/releases": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["listStudioReleases"];
+ put?: never;
+ post: operations["createRelease"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/releases/{id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["getReleaseForEdit"];
+ put: operations["updateRelease"];
+ post?: never;
+ delete: operations["deleteRelease"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/releases/{id}/publish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["publishRelease"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/releases/{id}/archive": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["archiveRelease"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/topics": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["listStudioTopics"];
+ put?: never;
+ post: operations["createTopic"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/topics/{id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put: operations["updateTopic"];
+ post?: never;
+ delete: operations["deleteTopic"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/tags": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["listStudioTags"];
+ put?: never;
+ post: operations["createTag"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/tags/{id}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put: operations["updateTag"];
+ post?: never;
+ delete: operations["deleteTag"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/site": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["getStudioSite"];
+ put: operations["updateStudioSite"];
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/profile": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["getStudioProfile"];
+ put: operations["updateStudioProfile"];
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/profile/publish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["publishProfile"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/profile/unpublish": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ post: operations["unpublishProfile"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/home-focus": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["getHomeFocus"];
+ put: operations["updateHomeFocus"];
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/activities": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get: operations["listStudioProjectActivities"];
+ put?: never;
+ post: operations["createProjectActivity"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+ "/api/v1/studio/projects/{id}/activities/{activityId}": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put: operations["updateProjectActivity"];
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
+}
+export type webhooks = Record;
+export interface components {
+ schemas: {
+ ResponseMeta: {
+ requestId: string;
+ traceId: string;
+ correlationId?: string | null;
+ /** @description 백엔드 템플릿의 ResponseMeta record 가 직렬화하는 자리다. 페이지 정보는 payload 의 `page` 가 소유하므로 이 관리 표면에서는 항상 null 이다. */
+ page?: {
+ [key: string]: unknown;
+ } | null;
+ };
+ ApiError: {
+ /**
+ * @description `INTERNAL_ERROR` 는 이 기능이 아니라 스켈레톤의 공통 처리기가 내는 코드다. 계약이 그것까지 열거해야 500 응답이 계약을 벗어나지 않는다.
+ * @enum {string}
+ */
+ code: "AUTHENTICATION_REQUIRED" | "STUDIO_ACCESS_DENIED" | "REQUEST_VALIDATION_FAILED" | "VERSION_CONFLICT" | "TOPIC_NOT_FOUND" | "TOPIC_NAME_TAKEN" | "TOPIC_SLUG_TAKEN" | "TOPIC_IN_USE" | "PROJECT_NOT_FOUND" | "PROJECT_SLUG_TAKEN" | "PROJECT_IN_USE" | "INTERNAL_ERROR";
+ /** @enum {string} */
+ category: "VALIDATION" | "AUTH" | "AUTHZ" | "NOT_FOUND" | "CONFLICT" | "RATE_LIMIT" | "TRANSIENT_DEPENDENCY" | "PERMANENT_DEPENDENCY" | "DATA_INTEGRITY" | "INTERNAL";
+ message: string;
+ retryable: boolean;
+ details?: components["schemas"]["ValidationErrorDetails"] | components["schemas"]["VersionConflictDetails"] | null;
+ };
+ ValidationErrorDetails: {
+ fieldErrors: components["schemas"]["FieldError"][];
+ };
+ VersionConflictDetails: {
+ /** Format: int64 */
+ currentVersion: number;
+ };
+ ErrorEnvelope: {
+ /** @constant */
+ success: false;
+ error: components["schemas"]["ApiError"];
+ meta: components["schemas"]["ResponseMeta"];
+ };
+ TopicEditEnvelope: {
+ /** @constant */
+ success: true;
+ data: components["schemas"]["TopicEdit"];
+ meta: components["schemas"]["ResponseMeta"];
+ };
+ TopicEditListEnvelope: {
+ /** @constant */
+ success: true;
+ data: components["schemas"]["TopicEdit"][];
+ meta: components["schemas"]["ResponseMeta"];
+ };
+ CreateDraftResponseEnvelope: {
+ /** @constant */
+ success: true;
+ data: components["schemas"]["CreateDraftResponse"];
+ meta: components["schemas"]["ResponseMeta"];
+ };
+ ProjectIndexPageEnvelope: {
+ /** @constant */
+ success: true;
+ data: components["schemas"]["ProjectIndexPage"];
+ meta: components["schemas"]["ResponseMeta"];
+ };
+ ProjectEditResponseEnvelope: {
+ /** @constant */
+ success: true;
+ data: components["schemas"]["ProjectEditResponse"];
+ meta: components["schemas"]["ResponseMeta"];
+ };
+ FieldError: {
+ field: string;
+ code: string;
+ message: string;
+ };
+ ProblemDetails: {
+ type: string;
+ title: string;
+ status: number;
+ code: string;
+ detail: string;
+ instance: string;
+ traceId: string;
+ fieldErrors?: components["schemas"]["FieldError"][];
+ /** Format: int64 */
+ currentVersion?: number;
+ };
+ PageMetadata: {
+ number: number;
+ size: number;
+ /** Format: int64 */
+ totalElements: number;
+ totalPages: number;
+ hasPrevious: boolean;
+ hasNext: boolean;
+ };
+ TagSummary: {
+ name: string;
+ slug: string;
+ };
+ ProjectSummary: {
+ name: string;
+ slug: string;
+ path: string;
+ };
+ AssetReference: {
+ /** Format: uuid */
+ assetId: string;
+ url: string;
+ altText?: string;
+ width?: number;
+ height?: number;
+ contentType?: string;
+ };
+ RelatedEntry: {
+ /** @enum {string} */
+ type: "CASE" | "REFERENCE" | "QUESTION" | "PROJECT" | "PROJECT_DECISION" | "RELEASE";
+ title: string;
+ summary?: string;
+ path: string;
+ };
+ PublicationStatus: {
+ /** @enum {string} */
+ state: "NEVER_PUBLISHED" | "ACTIVE" | "WITHDRAWN";
+ /** Format: int64 */
+ publishedSourceVersion?: number;
+ hasUnpublishedChanges: boolean;
+ canonicalPath?: string;
+ /** Format: date-time */
+ publishedAt?: string;
+ };
+ ValidationIssue: {
+ /** @enum {string} */
+ severity: "ERROR" | "WARNING";
+ code: string;
+ field?: string;
+ message: string;
+ };
+ ValidationResponse: {
+ validForSave: boolean;
+ validForPublish: boolean;
+ issues: components["schemas"]["ValidationIssue"][];
+ };
+ CreateDraftRequest: {
+ title: string;
+ };
+ CreateDraftResponse: {
+ /** Format: uuid */
+ id: string;
+ /** @enum {string} */
+ status: "DRAFT";
+ /** Format: int64 */
+ version: number;
+ /** Format: date-time */
+ createdAt: string;
+ };
+ RelationEdit: {
+ /** Format: uuid */
+ primaryProjectId?: string;
+ relatedProjectIds?: string[];
+ /** Format: uuid */
+ originQuestionId?: string;
+ relatedDocumentIds?: string[];
+ derivedReferenceIds?: string[];
+ };
+ CaseUpdateRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ title: string;
+ slug?: string;
+ problemSummary: string;
+ conclusionSummary: string;
+ environmentSummary?: string[];
+ content: string;
+ contentFormatVersion: number;
+ /** Format: uuid */
+ primaryTopicId?: string;
+ tagIds: string[];
+ relations: components["schemas"]["RelationEdit"];
+ /** Format: uuid */
+ coverAssetId?: string;
+ /** Format: date-time */
+ lastVerifiedAt?: string;
+ /** @enum {string} */
+ targetVisibility?: "PRIVATE" | "UNLISTED" | "PUBLIC";
+ };
+ CaseEditResponse: {
+ /** Format: uuid */
+ id: string;
+ /** Format: int64 */
+ version: number;
+ title: string;
+ slug?: string;
+ problemSummary: string;
+ conclusionSummary: string;
+ environmentSummary?: string[];
+ content: string;
+ contentFormatVersion: number;
+ /** Format: uuid */
+ primaryTopicId?: string;
+ tagIds: string[];
+ relations: components["schemas"]["RelationEdit"];
+ /** Format: uuid */
+ coverAssetId?: string;
+ /** Format: date-time */
+ lastVerifiedAt?: string;
+ workflowStatus: string;
+ targetVisibility: string;
+ publication: components["schemas"]["PublicationStatus"];
+ /** Format: date-time */
+ updatedAt: string;
+ };
+ ReferenceUpdateRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ title: string;
+ slug?: string;
+ scopeSummary: string;
+ appliesTo: string[];
+ excludedScope: string[];
+ /** @enum {string} */
+ freshnessStatus: "CURRENT" | "REVIEW_DUE" | "HISTORICAL";
+ content: string;
+ contentFormatVersion: number;
+ /** Format: uuid */
+ primaryTopicId?: string;
+ tagIds: string[];
+ relations: components["schemas"]["RelationEdit"];
+ /** Format: uuid */
+ coverAssetId?: string;
+ /** Format: date-time */
+ lastVerifiedAt?: string;
+ /** @enum {string} */
+ targetVisibility?: "PRIVATE" | "UNLISTED" | "PUBLIC";
+ };
+ ReferenceEditResponse: {
+ /** Format: uuid */
+ id: string;
+ /** Format: int64 */
+ version: number;
+ title: string;
+ slug?: string;
+ scopeSummary: string;
+ appliesTo: string[];
+ excludedScope: string[];
+ freshnessStatus: string;
+ content: string;
+ contentFormatVersion: number;
+ /** Format: uuid */
+ primaryTopicId?: string;
+ tagIds: string[];
+ relations: components["schemas"]["RelationEdit"];
+ /** Format: uuid */
+ coverAssetId?: string;
+ /** Format: date-time */
+ lastVerifiedAt?: string;
+ workflowStatus: string;
+ targetVisibility: string;
+ publication: components["schemas"]["PublicationStatus"];
+ /** Format: date-time */
+ updatedAt: string;
+ };
+ ExpectedVersionRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ };
+ PublishRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ /** @enum {string} */
+ visibility: "PUBLIC" | "UNLISTED";
+ };
+ PublishResponse: {
+ /** Format: uuid */
+ id: string;
+ /** @enum {string} */
+ status: "PUBLISHED";
+ /** @enum {string} */
+ visibility: "PUBLIC" | "UNLISTED";
+ canonicalPath: string;
+ /** Format: date-time */
+ publishedAt: string;
+ /** Format: int64 */
+ version: number;
+ };
+ QuestionPointEdit: {
+ /** Format: uuid */
+ id?: string;
+ /** @enum {string} */
+ kind: "FACT" | "ASSUMPTION" | "UNKNOWN" | "CONSTRAINT";
+ content: string;
+ displayOrder: number;
+ };
+ QuestionUpdateRequest: {
+ /** @enum {string} */
+ type: "OBSERVATION" | "EVIDENCE" | "SCOPE_CHANGE" | "BLOCKER" | "NEXT_STEP" | "RESOLUTION" | "RESOLUTION_REOPENED";
+ title: string;
+ bodyMarkdown: string;
+ /** @enum {string} */
+ visibility: "PRIVATE" | "PUBLIC";
+ /** Format: date-time */
+ occurredAt: string;
+ /** Format: int64 */
+ expectedVersion: number;
+ };
+ QuestionUpdateResponse: {
+ /** Format: uuid */
+ id: string;
+ /** Format: int64 */
+ questionVersion: number;
+ type: string;
+ title: string;
+ bodyMarkdown: string;
+ visibility: string;
+ /** Format: date-time */
+ occurredAt: string;
+ };
+ QuestionUpdateBody: {
+ /** Format: int64 */
+ expectedVersion: number;
+ question: string;
+ slug?: string;
+ summary: string;
+ context: string;
+ importance: string;
+ nextVerification?: string;
+ /** @enum {string} */
+ targetVisibility?: "PRIVATE" | "UNLISTED" | "PUBLIC";
+ /** Format: uuid */
+ primaryProjectId?: string;
+ /** Format: uuid */
+ topicId?: string;
+ tagIds: string[];
+ points: components["schemas"]["QuestionPointEdit"][];
+ };
+ QuestionEditResponse: {
+ /** Format: uuid */
+ id: string;
+ /** Format: int64 */
+ version: number;
+ question: string;
+ slug?: string;
+ summary?: string;
+ context?: string;
+ importance?: string;
+ nextVerification?: string;
+ status: string;
+ targetVisibility: string;
+ /** Format: uuid */
+ primaryProjectId?: string;
+ /** Format: uuid */
+ topicId?: string;
+ tagIds?: string[];
+ points: components["schemas"]["QuestionPointEdit"][];
+ updates: components["schemas"]["QuestionUpdateResponse"][];
+ resolution?: {
+ type?: string;
+ summary?: string;
+ /** Format: date-time */
+ resolvedAt?: string;
+ };
+ publication: components["schemas"]["PublicationStatus"];
+ /** Format: date-time */
+ updatedAt: string;
+ };
+ ResolveQuestionRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ /** @enum {string} */
+ resolutionType: "DECISION_MADE" | "ASSUMPTION_REJECTED" | "QUESTION_REFRAMED" | "NO_LONGER_RELEVANT";
+ resolutionSummary: string;
+ /** Format: date-time */
+ resolvedAt: string;
+ createCaseDraft: boolean;
+ createProjectDecision: boolean;
+ };
+ ResolveQuestionResponse: {
+ /** Format: uuid */
+ questionId: string;
+ /** @enum {string} */
+ status: "RESOLVED";
+ /** Format: int64 */
+ version: number;
+ /** Format: uuid */
+ createdCaseDraftId?: string;
+ /** Format: uuid */
+ createdProjectDecisionId?: string;
+ };
+ ProjectUpdateRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ name: string;
+ slug?: string;
+ oneLinePurpose: string;
+ purposeMarkdown: string;
+ boundaryMarkdown: string;
+ systemOverviewMarkdown?: string;
+ phase: string;
+ currentObjective?: string;
+ nextStep?: string;
+ technologyLabels: string[];
+ /** @enum {string} */
+ targetVisibility: "PRIVATE" | "UNLISTED" | "PUBLIC";
+ featuredOrder?: number;
+ topicIds?: string[];
+ documentLinks?: components["schemas"]["ProjectResourceLinkEdit"][];
+ questionLinks?: components["schemas"]["ProjectResourceLinkEdit"][];
+ };
+ ProjectEditResponse: {
+ /** Format: uuid */
+ id: string;
+ /** Format: int64 */
+ version: number;
+ name: string;
+ slug?: string;
+ oneLinePurpose?: string;
+ purposeMarkdown?: string;
+ boundaryMarkdown?: string;
+ systemOverviewMarkdown?: string;
+ phase: string;
+ currentObjective?: string;
+ nextStep?: string;
+ technologyLabels?: string[];
+ workflowStatus: string;
+ targetVisibility: string;
+ featuredOrder?: number;
+ publication: components["schemas"]["PublicationStatus"];
+ /** Format: date-time */
+ updatedAt: string;
+ topicIds?: string[];
+ documentLinks?: components["schemas"]["ProjectResourceLinkEdit"][];
+ questionLinks?: components["schemas"]["ProjectResourceLinkEdit"][];
+ };
+ ChangeProjectPhaseRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ phase: string;
+ reason: string;
+ publishActivity: boolean;
+ };
+ DecisionUpdateRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ statement: string;
+ rationaleMarkdown: string;
+ consequences: string[];
+ alternativesMarkdown: string;
+ /** @enum {string} */
+ targetVisibility: "PRIVATE" | "PUBLIC";
+ /** Format: uuid */
+ sourceQuestionId?: string;
+ /** Format: uuid */
+ sourceCaseId?: string;
+ isFeatured?: boolean;
+ /** Format: date-time */
+ decidedAt?: string;
+ };
+ DecisionResponse: components["schemas"]["DecisionUpdateRequest"] & {
+ /** Format: uuid */
+ id: string;
+ /** Format: uuid */
+ projectId: string;
+ status: string;
+ /** Format: int64 */
+ version: number;
+ /** Format: uuid */
+ supersededById?: string;
+ };
+ ReleaseUpdateRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ versionLabel: string;
+ title: string;
+ summary: string;
+ /** Format: date */
+ releasedOn?: string;
+ changeTypes: string[];
+ reasonMarkdown?: string;
+ changesMarkdown: string;
+ userImpactMarkdown?: string;
+ implementationImpactMarkdown?: string;
+ verificationMarkdown: string;
+ knownLimitationsMarkdown?: string;
+ relatedResources?: {
+ resourceType: string;
+ /** Format: uuid */
+ resourceId: string;
+ }[];
+ };
+ ReleaseEditResponse: components["schemas"]["ReleaseUpdateRequest"] & {
+ /** Format: uuid */
+ id: string;
+ workflowStatus: string;
+ /** Format: int64 */
+ version: number;
+ publication: components["schemas"]["PublicationStatus"];
+ };
+ TopicEdit: {
+ /**
+ * Format: uuid
+ * @description 응답에만 실린다. 경로가 `/topics/{id}`이므로 이 값이 없으면 목록에서 어떤 주제도
+ * 주소지정할 수 없다 — ProjectEditResponse / CaseEditResponse는 같은 이유로 이미
+ * id를 싣고 있었고, TopicEdit만 빠져 있었다. 쓰기 요청에 와도 서버는 무시한다;
+ * 수정 대상은 경로가 소유한다.
+ */
+ id?: string;
+ /**
+ * Format: int64
+ * @description 응답에만 실린다. 다음 수정에서 보낼 `expectedVersion`의 출처다. 이것이 없으면
+ * 클라이언트가 낙관적 잠금에 쓸 값을 얻을 방법이 없다.
+ */
+ version?: number;
+ name: string;
+ slug: string;
+ description?: string;
+ scope?: string;
+ /** @enum {string} */
+ status?: "ACTIVE" | "ARCHIVED";
+ /** Format: int64 */
+ expectedVersion?: number;
+ /** Format: uuid */
+ featuredReferenceId?: string;
+ featuredCaseIds?: string[];
+ };
+ TagEdit: {
+ name: string;
+ slug: string;
+ /** Format: int64 */
+ expectedVersion?: number;
+ };
+ SiteConfigRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ brandTitle: string;
+ identityStatement: string;
+ operatorDisplayName: string;
+ shortIdentity?: string;
+ /** Format: uuid */
+ avatarAssetId?: string;
+ contacts: Record[];
+ };
+ ProfileEditRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ headline: string;
+ introductionMarkdown?: string;
+ workingModel: Record[];
+ territories: Record[];
+ selectedEvidence: Record[];
+ trajectory: Record[];
+ contacts: Record[];
+ /** @enum {string} */
+ targetVisibility: "PRIVATE" | "PUBLIC";
+ };
+ HomeFocusRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ /** @enum {string} */
+ defaultType?: "CURRENT_WORK" | "OPEN_QUESTION" | "RECENT_DECISION";
+ /** Format: uuid */
+ currentProjectId?: string;
+ /** Format: uuid */
+ openQuestionId?: string;
+ /** Format: uuid */
+ recentDecisionId?: string;
+ };
+ QuestionIndexItem: {
+ /** Format: uuid */
+ id: string;
+ question: string;
+ status: string;
+ targetVisibility: string;
+ primaryProject?: components["schemas"]["ProjectSummary"];
+ nextVerification?: string;
+ /** Format: date-time */
+ updatedAt: string;
+ /** Format: int64 */
+ version: number;
+ publication: components["schemas"]["PublicationStatus"];
+ };
+ QuestionIndexPage: {
+ items: components["schemas"]["QuestionIndexItem"][];
+ page: components["schemas"]["PageMetadata"];
+ };
+ ProjectIndexItem: {
+ /** Format: uuid */
+ id: string;
+ name: string;
+ phase: string;
+ workflowStatus: string;
+ targetVisibility: string;
+ currentObjective?: string;
+ nextStep?: string;
+ /** Format: date-time */
+ updatedAt: string;
+ /** Format: int64 */
+ version: number;
+ publication: components["schemas"]["PublicationStatus"];
+ };
+ ProjectIndexPage: {
+ items: components["schemas"]["ProjectIndexItem"][];
+ page: components["schemas"]["PageMetadata"];
+ };
+ ReleaseIndexItem: {
+ /** Format: uuid */
+ id: string;
+ versionLabel: string;
+ title: string;
+ /** Format: date */
+ releasedOn?: string;
+ workflowStatus: string;
+ /** Format: date-time */
+ updatedAt: string;
+ /** Format: int64 */
+ version: number;
+ publication: components["schemas"]["PublicationStatus"];
+ };
+ ReleaseIndexPage: {
+ items: components["schemas"]["ReleaseIndexItem"][];
+ page: components["schemas"]["PageMetadata"];
+ };
+ SiteConfigResponse: {
+ /** Format: uuid */
+ id: string;
+ /** Format: int64 */
+ version: number;
+ brandTitle: string;
+ identityStatement: string;
+ operatorDisplayName: string;
+ shortIdentity?: string;
+ /** Format: uuid */
+ avatarAssetId?: string;
+ contacts: Record[];
+ };
+ ProfileEditResponse: {
+ /** Format: uuid */
+ id: string;
+ /** Format: int64 */
+ version: number;
+ headline: string;
+ introductionMarkdown?: string;
+ workingModel: Record[];
+ territories: Record[];
+ selectedEvidence: Record[];
+ trajectory: Record[];
+ contacts: Record[];
+ targetVisibility: string;
+ publication: components["schemas"]["PublicationStatus"];
+ };
+ HomeFocusResponse: {
+ /** Format: uuid */
+ id: string;
+ /** Format: int64 */
+ version: number;
+ defaultType?: string;
+ /** Format: uuid */
+ currentProjectId?: string;
+ /** Format: uuid */
+ openQuestionId?: string;
+ /** Format: uuid */
+ recentDecisionId?: string;
+ };
+ ProjectResourceLinkEdit: {
+ /** Format: uuid */
+ resourceId: string;
+ /** @enum {string} */
+ relationType: "PRIMARY" | "RELATED";
+ featuredOrder?: number;
+ };
+ CreateDecisionRequest: {
+ /** Format: int64 */
+ expectedProjectVersion: number;
+ statement: string;
+ rationaleMarkdown: string;
+ consequences: string[];
+ alternativesMarkdown: string;
+ /** @enum {string} */
+ targetVisibility: "PRIVATE" | "PUBLIC";
+ /** Format: uuid */
+ sourceQuestionId?: string;
+ /** Format: uuid */
+ sourceCaseId?: string;
+ isFeatured?: boolean;
+ /** Format: date-time */
+ decidedAt?: string;
+ };
+ SupersedeDecisionRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ /** Format: uuid */
+ supersededById: string;
+ };
+ ProjectActivityRequest: {
+ /** Format: int64 */
+ expectedProjectVersion: number;
+ activityType: string;
+ title: string;
+ summary?: string;
+ /** @enum {string} */
+ visibility: "PRIVATE" | "PUBLIC";
+ relatedResourceType?: string;
+ /** Format: uuid */
+ relatedResourceId?: string;
+ /** Format: date-time */
+ occurredAt: string;
+ };
+ ProjectActivityResponse: {
+ /** Format: uuid */
+ id: string;
+ /** Format: uuid */
+ projectId: string;
+ activityType: string;
+ title: string;
+ summary?: string;
+ visibility: string;
+ origin: string;
+ relatedResourceType?: string;
+ /** Format: uuid */
+ relatedResourceId?: string;
+ /** Format: date-time */
+ occurredAt: string;
+ /** Format: int64 */
+ version: number;
+ };
+ UpdateProjectActivityRequest: {
+ /** Format: int64 */
+ expectedVersion: number;
+ title: string;
+ summary?: string;
+ /** @enum {string} */
+ visibility: "PRIVATE" | "PUBLIC";
+ /** Format: date-time */
+ occurredAt: string;
+ };
+ };
+ responses: never;
+ parameters: {
+ CsrfToken: string;
+ };
+ requestBodies: never;
+ headers: never;
+ pathItems: never;
+}
+export type $defs = Record;
+export interface operations {
+ createCaseDraft: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["CreateDraftRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CreateDraftResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ getCaseForEdit: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateCaseDraft: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["CaseUpdateRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ deleteCaseDraft: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description No Content */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ createReferenceDraft: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["CreateDraftRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CreateDraftResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ getReferenceForEdit: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReferenceEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateReferenceDraft: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ReferenceUpdateRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReferenceEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ deleteReferenceDraft: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description No Content */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ validateCase: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ValidationResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ submitReviewCase: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ returnToDraftCase: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ unpublishCase: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ archiveCase: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ restoreCase: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ publishCase: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["PublishRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["PublishResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ validateReference: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ValidationResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ submitReviewReference: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReferenceEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ returnToDraftReference: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReferenceEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ unpublishReference: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReferenceEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ archiveReference: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReferenceEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ restoreReference: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReferenceEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ publishReference: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["PublishRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["PublishResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ listStudioQuestions: {
+ parameters: {
+ query?: {
+ page?: number;
+ size?: number;
+ };
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionIndexPage"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ createQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["CreateDraftRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CreateDraftResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ getQuestionForEdit: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["QuestionUpdateBody"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ deleteQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description No Content */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ addQuestionUpdate: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["QuestionUpdateRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionUpdateResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateQuestionUpdate: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ updateId: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["QuestionUpdateRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionUpdateResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ deleteQuestionUpdate: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ updateId: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description No Content */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ resolveQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ResolveQuestionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ResolveQuestionResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ startQuestionInvestigation: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ pauseQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ resumeQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ reopenQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ archiveQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ publishQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["PublishRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["PublishResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ unpublishQuestion: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["QuestionEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ listStudioProjects: {
+ parameters: {
+ query?: {
+ page?: number;
+ size?: number;
+ };
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProjectIndexPageEnvelope"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ };
+ };
+ createProject: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["CreateDraftRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CreateDraftResponseEnvelope"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ };
+ };
+ getProjectForEdit: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProjectEditResponseEnvelope"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ };
+ };
+ updateProject: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ProjectUpdateRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProjectEditResponseEnvelope"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ };
+ };
+ deleteProject: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description No Content */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ };
+ };
+ changeProjectPhase: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ChangeProjectPhaseRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProjectEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ publishProject: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["PublishRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["PublishResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ unpublishProject: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProjectEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ listStudioProjectDecisions: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["DecisionResponse"][];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ createProjectDecision: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["CreateDecisionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["DecisionResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ getProjectDecision: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ id: string;
+ decisionId: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["DecisionResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateProjectDecision: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ decisionId: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["DecisionUpdateRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["DecisionResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ acceptProjectDecision: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ decisionId: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["DecisionResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ rejectProjectDecision: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ decisionId: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["DecisionResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ supersedeProjectDecision: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ decisionId: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["SupersedeDecisionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["DecisionResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ listStudioReleases: {
+ parameters: {
+ query?: {
+ page?: number;
+ size?: number;
+ };
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReleaseIndexPage"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ createRelease: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["CreateDraftRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["CreateDraftResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ getReleaseForEdit: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReleaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateRelease: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ReleaseUpdateRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReleaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ deleteRelease: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description No Content */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ publishRelease: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["PublishResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ archiveRelease: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ReleaseEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ listStudioTopics: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["TopicEditListEnvelope"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ };
+ };
+ createTopic: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["TopicEdit"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["TopicEditEnvelope"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ };
+ };
+ updateTopic: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["TopicEdit"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["TopicEditEnvelope"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ };
+ };
+ deleteTopic: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description No Content */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ErrorEnvelope"];
+ };
+ };
+ };
+ };
+ listStudioTags: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["TagEdit"][];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ createTag: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["TagEdit"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["TagEdit"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateTag: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["TagEdit"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["TagEdit"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ deleteTag: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description No Content */
+ 204: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content?: never;
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ getStudioSite: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["SiteConfigResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateStudioSite: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["SiteConfigRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["SiteConfigResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ getStudioProfile: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProfileEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateStudioProfile: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ProfileEditRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProfileEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ publishProfile: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["PublishResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ unpublishProfile: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ExpectedVersionRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProfileEditResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ getHomeFocus: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["HomeFocusResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateHomeFocus: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["HomeFocusRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["HomeFocusResponse"];
+ };
+ };
+ /** @description Bad Request */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unauthorized */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Forbidden */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Not Found */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Conflict */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Unprocessable Content */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description Internal Server Error */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ listStudioProjectActivities: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProjectActivityResponse"][];
+ };
+ };
+ /** @description 401 */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 403 */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 404 */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 500 */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ createProjectActivity: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["ProjectActivityRequest"];
+ };
+ };
+ responses: {
+ /** @description Created */
+ 201: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProjectActivityResponse"];
+ };
+ };
+ /** @description 400 */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 401 */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 403 */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 404 */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 409 */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 422 */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 500 */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+ updateProjectActivity: {
+ parameters: {
+ query?: never;
+ header: {
+ "X-CSRF-TOKEN": components["parameters"]["CsrfToken"];
+ };
+ path: {
+ id: string;
+ activityId: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["UpdateProjectActivityRequest"];
+ };
+ };
+ responses: {
+ /** @description OK */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["ProjectActivityResponse"];
+ };
+ };
+ /** @description 400 */
+ 400: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 401 */
+ 401: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 403 */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 404 */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 409 */
+ 409: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 422 */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ /** @description 500 */
+ 500: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/problem+json": components["schemas"]["ProblemDetails"];
+ };
+ };
+ };
+ };
+}
diff --git a/src/features/tech-log/contracts/management/management-api.openapi.yaml b/src/features/tech-log/contracts/management/management-api.openapi.yaml
new file mode 100644
index 0000000..0a65f79
--- /dev/null
+++ b/src/features/tech-log/contracts/management/management-api.openapi.yaml
@@ -0,0 +1,7065 @@
+openapi: 3.1.0
+info:
+ title: Tech Log Studio Management API (Secondary)
+ version: 1.0.0
+ description: |-
+ ⚠ 봉투 결정(ADR-006) 부분 반영 — 이 파일에는 두 모양이 공존한다.
+
+ topics 4개와 projects 5개는 studio-v1.yaml과 같은 방식으로 변환했다
+ (`application/json` + ErrorEnvelope / Envelope). 그 9개가 첫 구현
+ 대상이자 첫 소비자이기 때문이다.
+
+ 나머지 70개는 아직 bare payload + `application/problem+json` + ProblemDetails
+ 다. 구현에 착수할 때 같은 방식으로 따라온다 — 소비자가 없는 operation을 미리
+ 변환해 두면 검증되지 않은 모양이 계약에 고정된다.
+
+ Tech Log의 유형별 specialized management 계약이다.
+
+ 이 계약은 primary Studio orchestration 계약(`studio-v1.yaml`)이 아니다.
+ 현재 Studio UI는 이 operation들을 직접 호출하지 않는다.
+
+ 존재 이유는 설계 수정 가이드 14장과 23.7의 규칙이다.
+
+ > 현재 UI에서 사용하지 않는다는 이유로 Backend capability를 삭제하지 않는다.
+ > 다만 capability 보존과 endpoint 보존을 동일시하지 않는다.
+
+ 따라서 Question start/pause/resume/reopen/archive, Project phase change,
+ Project Activity, Release, Topic/Tag, Profile/Site/Home Focus,
+ Decision supersede/reject 등의 Domain/Application capability를 여기에 보존하고,
+ 현재 Frontend가 사용하는 통합 편집 흐름은 `studio-v1.yaml`이 소유한다.
+
+ ## 이 계약을 사용하는 규칙
+
+ - primary 흐름(작업본 편집·검증·미리보기·게시)은 반드시 `studio-v1.yaml`을 사용한다.
+ - 여기의 publish/unpublish 계열 operation은 primary `publishStudioDocument`와
+ 동일한 Publication Event/Snapshot 경로를 거쳐야 한다.
+ 서로 다른 두 개의 게시 경로를 허용하지 않는다.
+ - 새 UI가 특정 capability를 실제로 사용하기 시작하면 해당 operation을
+ primary 계약으로 승격하고 여기에서 제거한다.
+
+ ## 이 계약에서 제거된 것
+
+ - `GET /session` : primary `studio-v1.yaml`이 소유한다.
+ - `/documents` 계열 : primary 통합 Working Copy operation으로 대체되었다.
+ - `/assets` 계열 : primary `studio-v1.yaml`이 소유한다.
+ - `/previews`, `/previews/{token}` : Preview Token 계약은 폐기되었다.
+ 인증된 Preview Artifact(`studio-v1.yaml`)로 대체되었다.
+servers:
+- url: /
+security:
+- sessionCookie: []
+tags:
+- name: Cases
+- name: References
+- name: Questions
+- name: Projects
+- name: Decisions
+- name: Releases
+- name: Taxonomy
+- name: Identity
+paths:
+ /api/v1/studio/cases:
+ post:
+ operationId: createCaseDraft
+ tags:
+ - Cases
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '201':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/cases/{id}:
+ get:
+ operationId: getCaseForEdit
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ put:
+ operationId: updateCaseDraft
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CaseUpdateRequest'
+ security:
+ - sessionCookie: []
+ delete:
+ operationId: deleteCaseDraft
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/references:
+ post:
+ operationId: createReferenceDraft
+ tags:
+ - References
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '201':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/references/{id}:
+ get:
+ operationId: getReferenceForEdit
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReferenceEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ put:
+ operationId: updateReferenceDraft
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReferenceEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReferenceUpdateRequest'
+ security:
+ - sessionCookie: []
+ delete:
+ operationId: deleteReferenceDraft
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/cases/{id}/validate:
+ post:
+ operationId: validateCase
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ValidationResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/cases/{id}/submit-review:
+ post:
+ operationId: submitReviewCase
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/cases/{id}/return-to-draft:
+ post:
+ operationId: returnToDraftCase
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/cases/{id}/unpublish:
+ post:
+ operationId: unpublishCase
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/cases/{id}/archive:
+ post:
+ operationId: archiveCase
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/cases/{id}/restore:
+ post:
+ operationId: restoreCase
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/cases/{id}/publish:
+ post:
+ operationId: publishCase
+ tags:
+ - Cases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/references/{id}/validate:
+ post:
+ operationId: validateReference
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ValidationResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/references/{id}/submit-review:
+ post:
+ operationId: submitReviewReference
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReferenceEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/references/{id}/return-to-draft:
+ post:
+ operationId: returnToDraftReference
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReferenceEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/references/{id}/unpublish:
+ post:
+ operationId: unpublishReference
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReferenceEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/references/{id}/archive:
+ post:
+ operationId: archiveReference
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReferenceEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/references/{id}/restore:
+ post:
+ operationId: restoreReference
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReferenceEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/references/{id}/publish:
+ post:
+ operationId: publishReference
+ tags:
+ - References
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions:
+ post:
+ operationId: createQuestion
+ tags:
+ - Questions
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '201':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftRequest'
+ security:
+ - sessionCookie: []
+ get:
+ operationId: listStudioQuestions
+ tags:
+ - Questions
+ parameters:
+ - name: page
+ in: query
+ schema:
+ type: integer
+ minimum: 1
+ default: 1
+ - name: size
+ in: query
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ default: 20
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionIndexPage'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}:
+ get:
+ operationId: getQuestionForEdit
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ put:
+ operationId: updateQuestion
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionUpdateBody'
+ security:
+ - sessionCookie: []
+ delete:
+ operationId: deleteQuestion
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/updates:
+ post:
+ operationId: addQuestionUpdate
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '201':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionUpdateResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionUpdateRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/updates/{updateId}:
+ put:
+ operationId: updateQuestionUpdate
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: updateId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionUpdateResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionUpdateRequest'
+ security:
+ - sessionCookie: []
+ delete:
+ operationId: deleteQuestionUpdate
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: updateId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/resolve:
+ post:
+ operationId: resolveQuestion
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ResolveQuestionResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ResolveQuestionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/start-investigation:
+ post:
+ operationId: startQuestionInvestigation
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/pause:
+ post:
+ operationId: pauseQuestion
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/resume:
+ post:
+ operationId: resumeQuestion
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/reopen:
+ post:
+ operationId: reopenQuestion
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/archive:
+ post:
+ operationId: archiveQuestion
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/publish:
+ post:
+ operationId: publishQuestion
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/questions/{id}/unpublish:
+ post:
+ operationId: unpublishQuestion
+ tags:
+ - Questions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QuestionEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects:
+ post:
+ operationId: createProject
+ tags:
+ - Projects
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '201':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftResponseEnvelope'
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '404':
+ description: Not Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '409':
+ description: Conflict
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '500':
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftRequest'
+ security:
+ - sessionCookie: []
+ get:
+ operationId: listStudioProjects
+ tags:
+ - Projects
+ parameters:
+ - name: page
+ in: query
+ schema:
+ type: integer
+ minimum: 1
+ default: 1
+ - name: size
+ in: query
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ default: 20
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectIndexPageEnvelope'
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '404':
+ description: Not Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '500':
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}:
+ get:
+ operationId: getProjectForEdit
+ tags:
+ - Projects
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectEditResponseEnvelope'
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '404':
+ description: Not Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '500':
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ security:
+ - sessionCookie: []
+ put:
+ operationId: updateProject
+ tags:
+ - Projects
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectEditResponseEnvelope'
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '404':
+ description: Not Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '409':
+ description: Conflict
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '500':
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectUpdateRequest'
+ security:
+ - sessionCookie: []
+ delete:
+ operationId: deleteProject
+ tags:
+ - Projects
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '404':
+ description: Not Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '409':
+ description: Conflict
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '500':
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}/change-phase:
+ post:
+ operationId: changeProjectPhase
+ tags:
+ - Projects
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ChangeProjectPhaseRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}/publish:
+ post:
+ operationId: publishProject
+ tags:
+ - Projects
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}/unpublish:
+ post:
+ operationId: unpublishProject
+ tags:
+ - Projects
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}/decisions:
+ post:
+ operationId: createProjectDecision
+ tags:
+ - Decisions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '201':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DecisionResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDecisionRequest'
+ security:
+ - sessionCookie: []
+ get:
+ operationId: listStudioProjectDecisions
+ tags:
+ - Decisions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/DecisionResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}/decisions/{decisionId}:
+ get:
+ operationId: getProjectDecision
+ tags:
+ - Decisions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: decisionId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DecisionResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ put:
+ operationId: updateProjectDecision
+ tags:
+ - Decisions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: decisionId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DecisionResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DecisionUpdateRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}/decisions/{decisionId}/accept:
+ post:
+ operationId: acceptProjectDecision
+ tags:
+ - Decisions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: decisionId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DecisionResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}/decisions/{decisionId}/reject:
+ post:
+ operationId: rejectProjectDecision
+ tags:
+ - Decisions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: decisionId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DecisionResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}/decisions/{decisionId}/supersede:
+ post:
+ operationId: supersedeProjectDecision
+ tags:
+ - Decisions
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: decisionId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DecisionResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SupersedeDecisionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/releases:
+ post:
+ operationId: createRelease
+ tags:
+ - Releases
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '201':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateDraftRequest'
+ security:
+ - sessionCookie: []
+ get:
+ operationId: listStudioReleases
+ tags:
+ - Releases
+ parameters:
+ - name: page
+ in: query
+ schema:
+ type: integer
+ minimum: 1
+ default: 1
+ - name: size
+ in: query
+ schema:
+ type: integer
+ minimum: 1
+ maximum: 100
+ default: 20
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReleaseIndexPage'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/releases/{id}:
+ get:
+ operationId: getReleaseForEdit
+ tags:
+ - Releases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReleaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ put:
+ operationId: updateRelease
+ tags:
+ - Releases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReleaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReleaseUpdateRequest'
+ security:
+ - sessionCookie: []
+ delete:
+ operationId: deleteRelease
+ tags:
+ - Releases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/releases/{id}/publish:
+ post:
+ operationId: publishRelease
+ tags:
+ - Releases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/releases/{id}/archive:
+ post:
+ operationId: archiveRelease
+ tags:
+ - Releases
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ReleaseEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/topics:
+ get:
+ operationId: listStudioTopics
+ tags:
+ - Taxonomy
+ parameters: []
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TopicEditListEnvelope'
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '404':
+ description: Not Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '500':
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ security:
+ - sessionCookie: []
+ post:
+ operationId: createTopic
+ tags:
+ - Taxonomy
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '201':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TopicEditEnvelope'
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '404':
+ description: Not Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '409':
+ description: Conflict
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '500':
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TopicEdit'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/topics/{id}:
+ put:
+ operationId: updateTopic
+ tags:
+ - Taxonomy
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TopicEditEnvelope'
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '404':
+ description: Not Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '409':
+ description: Conflict
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '500':
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TopicEdit'
+ security:
+ - sessionCookie: []
+ delete:
+ operationId: deleteTopic
+ tags:
+ - Taxonomy
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '401':
+ description: Unauthorized
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '403':
+ description: Forbidden
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '404':
+ description: Not Found
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '409':
+ description: Conflict
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ '500':
+ description: Internal Server Error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorEnvelope'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/tags:
+ get:
+ operationId: listStudioTags
+ tags:
+ - Taxonomy
+ parameters: []
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/TagEdit'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ post:
+ operationId: createTag
+ tags:
+ - Taxonomy
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '201':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TagEdit'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TagEdit'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/tags/{id}:
+ put:
+ operationId: updateTag
+ tags:
+ - Taxonomy
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TagEdit'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/TagEdit'
+ security:
+ - sessionCookie: []
+ delete:
+ operationId: deleteTag
+ tags:
+ - Taxonomy
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '204':
+ description: No Content
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/site:
+ get:
+ operationId: getStudioSite
+ tags:
+ - Identity
+ parameters: []
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SiteConfigResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ put:
+ operationId: updateStudioSite
+ tags:
+ - Identity
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SiteConfigResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SiteConfigRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/profile:
+ get:
+ operationId: getStudioProfile
+ tags:
+ - Identity
+ parameters: []
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProfileEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ put:
+ operationId: updateStudioProfile
+ tags:
+ - Identity
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProfileEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProfileEditRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/profile/publish:
+ post:
+ operationId: publishProfile
+ tags:
+ - Identity
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PublishResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/profile/unpublish:
+ post:
+ operationId: unpublishProfile
+ tags:
+ - Identity
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProfileEditResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ExpectedVersionRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/home-focus:
+ get:
+ operationId: getHomeFocus
+ tags:
+ - Identity
+ parameters: []
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HomeFocusResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ security:
+ - sessionCookie: []
+ put:
+ operationId: updateHomeFocus
+ tags:
+ - Identity
+ parameters:
+ - $ref: '#/components/parameters/CsrfToken'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HomeFocusResponse'
+ '400':
+ description: Bad Request
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: Unauthorized
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: Forbidden
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: Not Found
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: Conflict
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: Unprocessable Content
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: Internal Server Error
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/HomeFocusRequest'
+ security:
+ - sessionCookie: []
+ /api/v1/studio/projects/{id}/activities:
+ get:
+ operationId: listStudioProjectActivities
+ tags:
+ - Projects
+ security:
+ - sessionCookie: []
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectActivityResponse'
+ '401':
+ description: '401'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: '403'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: '404'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: '500'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ post:
+ operationId: createProjectActivity
+ tags:
+ - Projects
+ security:
+ - sessionCookie: []
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectActivityRequest'
+ responses:
+ '201':
+ description: Created
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectActivityResponse'
+ '400':
+ description: '400'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: '401'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: '403'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: '404'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: '409'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: '422'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: '500'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ /api/v1/studio/projects/{id}/activities/{activityId}:
+ put:
+ operationId: updateProjectActivity
+ tags:
+ - Projects
+ security:
+ - sessionCookie: []
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - name: activityId
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ - $ref: '#/components/parameters/CsrfToken'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateProjectActivityRequest'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ProjectActivityResponse'
+ '400':
+ description: '400'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '401':
+ description: '401'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '403':
+ description: '403'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '404':
+ description: '404'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '409':
+ description: '409'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '422':
+ description: '422'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+ '500':
+ description: '500'
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemDetails'
+components:
+ securitySchemes:
+ sessionCookie:
+ type: apiKey
+ in: cookie
+ name: TECHLOG_SESSION
+ parameters:
+ CsrfToken:
+ name: X-CSRF-TOKEN
+ in: header
+ required: true
+ schema:
+ type: string
+ schemas:
+ # -------------------------------------------------------------------------
+ # 응답 봉투 (ADR-006)
+ #
+ # 이 파일 상단이 예고한 변환이다. 지금은 topics/projects 9개 operation 만
+ # 옮겼다 — 그 둘이 첫 소비자이기 때문이고, 나머지는 구현에 착수할 때 같은
+ # 방식으로 따라온다. 그동안 이 파일에는 두 모양이 공존한다: 변환된
+ # operation 은 `application/json` + Envelope, 나머지는 예전
+ # `application/problem+json` + ProblemDetails 다.
+ # -------------------------------------------------------------------------
+ ResponseMeta:
+ type: object
+ additionalProperties: false
+ required:
+ - requestId
+ - traceId
+ properties:
+ requestId:
+ type: string
+ minLength: 1
+ maxLength: 200
+ traceId:
+ type: string
+ minLength: 1
+ maxLength: 200
+ correlationId:
+ type:
+ - string
+ - 'null'
+ maxLength: 200
+ page:
+ type:
+ - object
+ - 'null'
+ additionalProperties: true
+ description: 백엔드 템플릿의 ResponseMeta record 가 직렬화하는 자리다. 페이지 정보는 payload 의 `page` 가 소유하므로 이 관리 표면에서는 항상 null 이다.
+ ApiError:
+ type: object
+ additionalProperties: false
+ required:
+ - code
+ - category
+ - message
+ - retryable
+ properties:
+ code:
+ type: string
+ enum:
+ - AUTHENTICATION_REQUIRED
+ - STUDIO_ACCESS_DENIED
+ - REQUEST_VALIDATION_FAILED
+ - VERSION_CONFLICT
+ - TOPIC_NOT_FOUND
+ - TOPIC_NAME_TAKEN
+ - TOPIC_SLUG_TAKEN
+ - TOPIC_IN_USE
+ - PROJECT_NOT_FOUND
+ - PROJECT_SLUG_TAKEN
+ - PROJECT_IN_USE
+ - INTERNAL_ERROR
+ description: '`INTERNAL_ERROR` 는 이 기능이 아니라 스켈레톤의 공통 처리기가 내는 코드다. 계약이 그것까지 열거해야 500 응답이 계약을 벗어나지 않는다.'
+ category:
+ type: string
+ enum:
+ - VALIDATION
+ - AUTH
+ - AUTHZ
+ - NOT_FOUND
+ - CONFLICT
+ - RATE_LIMIT
+ - TRANSIENT_DEPENDENCY
+ - PERMANENT_DEPENDENCY
+ - DATA_INTEGRITY
+ - INTERNAL
+ message:
+ type: string
+ minLength: 1
+ maxLength: 5000
+ retryable:
+ type: boolean
+ details:
+ oneOf:
+ - $ref: '#/components/schemas/ValidationErrorDetails'
+ - $ref: '#/components/schemas/VersionConflictDetails'
+ - type: 'null'
+ ValidationErrorDetails:
+ type: object
+ additionalProperties: false
+ required:
+ - fieldErrors
+ properties:
+ fieldErrors:
+ type: array
+ maxItems: 200
+ items:
+ $ref: '#/components/schemas/FieldError'
+ VersionConflictDetails:
+ type: object
+ additionalProperties: false
+ required:
+ - currentVersion
+ properties:
+ currentVersion:
+ type: integer
+ format: int64
+ minimum: 0
+ ErrorEnvelope:
+ type: object
+ additionalProperties: false
+ required:
+ - success
+ - error
+ - meta
+ properties:
+ success:
+ type: boolean
+ const: false
+ error:
+ $ref: '#/components/schemas/ApiError'
+ meta:
+ $ref: '#/components/schemas/ResponseMeta'
+ TopicEditEnvelope:
+ type: object
+ additionalProperties: false
+ required:
+ - success
+ - data
+ - meta
+ properties:
+ success:
+ type: boolean
+ const: true
+ data:
+ $ref: '#/components/schemas/TopicEdit'
+ meta:
+ $ref: '#/components/schemas/ResponseMeta'
+ TopicEditListEnvelope:
+ type: object
+ additionalProperties: false
+ required:
+ - success
+ - data
+ - meta
+ properties:
+ success:
+ type: boolean
+ const: true
+ data:
+ type: array
+ maxItems: 500
+ items:
+ $ref: '#/components/schemas/TopicEdit'
+ meta:
+ $ref: '#/components/schemas/ResponseMeta'
+ CreateDraftResponseEnvelope:
+ type: object
+ additionalProperties: false
+ required:
+ - success
+ - data
+ - meta
+ properties:
+ success:
+ type: boolean
+ const: true
+ data:
+ $ref: '#/components/schemas/CreateDraftResponse'
+ meta:
+ $ref: '#/components/schemas/ResponseMeta'
+ ProjectIndexPageEnvelope:
+ type: object
+ additionalProperties: false
+ required:
+ - success
+ - data
+ - meta
+ properties:
+ success:
+ type: boolean
+ const: true
+ data:
+ $ref: '#/components/schemas/ProjectIndexPage'
+ meta:
+ $ref: '#/components/schemas/ResponseMeta'
+ ProjectEditResponseEnvelope:
+ type: object
+ additionalProperties: false
+ required:
+ - success
+ - data
+ - meta
+ properties:
+ success:
+ type: boolean
+ const: true
+ data:
+ $ref: '#/components/schemas/ProjectEditResponse'
+ meta:
+ $ref: '#/components/schemas/ResponseMeta'
+ FieldError:
+ type: object
+ required:
+ - field
+ - code
+ - message
+ properties:
+ field:
+ type: string
+ code:
+ type: string
+ message:
+ type: string
+ ProblemDetails:
+ type: object
+ required:
+ - type
+ - title
+ - status
+ - code
+ - detail
+ - instance
+ - traceId
+ properties:
+ type:
+ type: string
+ title:
+ type: string
+ status:
+ type: integer
+ code:
+ type: string
+ detail:
+ type: string
+ instance:
+ type: string
+ traceId:
+ type: string
+ fieldErrors:
+ type: array
+ items:
+ $ref: '#/components/schemas/FieldError'
+ currentVersion:
+ type: integer
+ format: int64
+ PageMetadata:
+ type: object
+ required:
+ - number
+ - size
+ - totalElements
+ - totalPages
+ - hasPrevious
+ - hasNext
+ properties:
+ number:
+ type: integer
+ minimum: 1
+ size:
+ type: integer
+ minimum: 1
+ maximum: 100
+ totalElements:
+ type: integer
+ format: int64
+ minimum: 0
+ totalPages:
+ type: integer
+ minimum: 0
+ hasPrevious:
+ type: boolean
+ hasNext:
+ type: boolean
+ TagSummary:
+ type: object
+ required:
+ - name
+ - slug
+ properties:
+ name:
+ type: string
+ slug:
+ type: string
+ ProjectSummary:
+ type: object
+ required:
+ - name
+ - slug
+ - path
+ properties:
+ name:
+ type: string
+ slug:
+ type: string
+ path:
+ type: string
+ AssetReference:
+ type: object
+ required:
+ - assetId
+ - url
+ properties:
+ assetId:
+ type: string
+ format: uuid
+ url:
+ type: string
+ altText:
+ type: string
+ width:
+ type: integer
+ height:
+ type: integer
+ contentType:
+ type: string
+ RelatedEntry:
+ type: object
+ required:
+ - type
+ - title
+ - path
+ properties:
+ type:
+ type: string
+ enum:
+ - CASE
+ - REFERENCE
+ - QUESTION
+ - PROJECT
+ - PROJECT_DECISION
+ - RELEASE
+ title:
+ type: string
+ summary:
+ type: string
+ path:
+ type: string
+ PublicationStatus:
+ type: object
+ required:
+ - state
+ - hasUnpublishedChanges
+ properties:
+ state:
+ type: string
+ enum:
+ - NEVER_PUBLISHED
+ - ACTIVE
+ - WITHDRAWN
+ publishedSourceVersion:
+ type: integer
+ format: int64
+ hasUnpublishedChanges:
+ type: boolean
+ canonicalPath:
+ type: string
+ publishedAt:
+ type: string
+ format: date-time
+ ValidationIssue:
+ type: object
+ required:
+ - severity
+ - code
+ - message
+ properties:
+ severity:
+ type: string
+ enum:
+ - ERROR
+ - WARNING
+ code:
+ type: string
+ field:
+ type: string
+ message:
+ type: string
+ ValidationResponse:
+ type: object
+ required:
+ - validForSave
+ - validForPublish
+ - issues
+ properties:
+ validForSave:
+ type: boolean
+ validForPublish:
+ type: boolean
+ issues:
+ type: array
+ items:
+ $ref: '#/components/schemas/ValidationIssue'
+ CreateDraftRequest:
+ type: object
+ required:
+ - title
+ properties:
+ title:
+ type: string
+ maxLength: 180
+ CreateDraftResponse:
+ type: object
+ required:
+ - id
+ - status
+ - version
+ - createdAt
+ properties:
+ id:
+ type: string
+ format: uuid
+ status:
+ type: string
+ enum:
+ - DRAFT
+ version:
+ type: integer
+ format: int64
+ createdAt:
+ type: string
+ format: date-time
+ RelationEdit:
+ type: object
+ properties:
+ primaryProjectId:
+ type: string
+ format: uuid
+ relatedProjectIds:
+ type: array
+ items:
+ type: string
+ format: uuid
+ originQuestionId:
+ type: string
+ format: uuid
+ relatedDocumentIds:
+ type: array
+ items:
+ type: string
+ format: uuid
+ derivedReferenceIds:
+ type: array
+ items:
+ type: string
+ format: uuid
+ CaseUpdateRequest:
+ type: object
+ required:
+ - expectedVersion
+ - title
+ - problemSummary
+ - conclusionSummary
+ - content
+ - contentFormatVersion
+ - tagIds
+ - relations
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ title:
+ type: string
+ maxLength: 180
+ slug:
+ type: string
+ maxLength: 180
+ problemSummary:
+ type: string
+ maxLength: 600
+ conclusionSummary:
+ type: string
+ maxLength: 600
+ environmentSummary:
+ type: array
+ items:
+ type: string
+ content:
+ type: string
+ maxLength: 2000000
+ contentFormatVersion:
+ type: integer
+ minimum: 1
+ primaryTopicId:
+ type: string
+ format: uuid
+ tagIds:
+ type: array
+ maxItems: 12
+ items:
+ type: string
+ format: uuid
+ relations:
+ $ref: '#/components/schemas/RelationEdit'
+ coverAssetId:
+ type: string
+ format: uuid
+ lastVerifiedAt:
+ type: string
+ format: date-time
+ targetVisibility:
+ type: string
+ enum:
+ - PRIVATE
+ - UNLISTED
+ - PUBLIC
+ CaseEditResponse:
+ type: object
+ required:
+ - id
+ - version
+ - title
+ - problemSummary
+ - conclusionSummary
+ - content
+ - contentFormatVersion
+ - tagIds
+ - relations
+ - workflowStatus
+ - targetVisibility
+ - publication
+ - updatedAt
+ properties:
+ id:
+ type: string
+ format: uuid
+ version:
+ type: integer
+ format: int64
+ title:
+ type: string
+ slug:
+ type: string
+ problemSummary:
+ type: string
+ conclusionSummary:
+ type: string
+ environmentSummary:
+ type: array
+ items:
+ type: string
+ content:
+ type: string
+ contentFormatVersion:
+ type: integer
+ primaryTopicId:
+ type: string
+ format: uuid
+ tagIds:
+ type: array
+ items:
+ type: string
+ format: uuid
+ relations:
+ $ref: '#/components/schemas/RelationEdit'
+ coverAssetId:
+ type: string
+ format: uuid
+ lastVerifiedAt:
+ type: string
+ format: date-time
+ workflowStatus:
+ type: string
+ targetVisibility:
+ type: string
+ publication:
+ $ref: '#/components/schemas/PublicationStatus'
+ updatedAt:
+ type: string
+ format: date-time
+ ReferenceUpdateRequest:
+ type: object
+ required:
+ - expectedVersion
+ - title
+ - scopeSummary
+ - appliesTo
+ - excludedScope
+ - freshnessStatus
+ - content
+ - contentFormatVersion
+ - tagIds
+ - relations
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ title:
+ type: string
+ maxLength: 180
+ slug:
+ type: string
+ maxLength: 180
+ scopeSummary:
+ type: string
+ maxLength: 600
+ appliesTo:
+ type: array
+ items:
+ type: string
+ excludedScope:
+ type: array
+ items:
+ type: string
+ freshnessStatus:
+ type: string
+ enum:
+ - CURRENT
+ - REVIEW_DUE
+ - HISTORICAL
+ content:
+ type: string
+ maxLength: 2000000
+ contentFormatVersion:
+ type: integer
+ minimum: 1
+ primaryTopicId:
+ type: string
+ format: uuid
+ tagIds:
+ type: array
+ maxItems: 12
+ items:
+ type: string
+ format: uuid
+ relations:
+ $ref: '#/components/schemas/RelationEdit'
+ coverAssetId:
+ type: string
+ format: uuid
+ lastVerifiedAt:
+ type: string
+ format: date-time
+ targetVisibility:
+ type: string
+ enum:
+ - PRIVATE
+ - UNLISTED
+ - PUBLIC
+ ReferenceEditResponse:
+ type: object
+ required:
+ - id
+ - version
+ - title
+ - scopeSummary
+ - appliesTo
+ - excludedScope
+ - freshnessStatus
+ - content
+ - contentFormatVersion
+ - tagIds
+ - relations
+ - workflowStatus
+ - targetVisibility
+ - publication
+ - updatedAt
+ properties:
+ id:
+ type: string
+ format: uuid
+ version:
+ type: integer
+ format: int64
+ title:
+ type: string
+ slug:
+ type: string
+ scopeSummary:
+ type: string
+ appliesTo:
+ type: array
+ items:
+ type: string
+ excludedScope:
+ type: array
+ items:
+ type: string
+ freshnessStatus:
+ type: string
+ content:
+ type: string
+ contentFormatVersion:
+ type: integer
+ primaryTopicId:
+ type: string
+ format: uuid
+ tagIds:
+ type: array
+ items:
+ type: string
+ format: uuid
+ relations:
+ $ref: '#/components/schemas/RelationEdit'
+ coverAssetId:
+ type: string
+ format: uuid
+ lastVerifiedAt:
+ type: string
+ format: date-time
+ workflowStatus:
+ type: string
+ targetVisibility:
+ type: string
+ publication:
+ $ref: '#/components/schemas/PublicationStatus'
+ updatedAt:
+ type: string
+ format: date-time
+ ExpectedVersionRequest:
+ type: object
+ required:
+ - expectedVersion
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ PublishRequest:
+ type: object
+ required:
+ - expectedVersion
+ - visibility
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ visibility:
+ type: string
+ enum:
+ - PUBLIC
+ - UNLISTED
+ PublishResponse:
+ type: object
+ required:
+ - id
+ - status
+ - visibility
+ - canonicalPath
+ - publishedAt
+ - version
+ properties:
+ id:
+ type: string
+ format: uuid
+ status:
+ type: string
+ enum:
+ - PUBLISHED
+ visibility:
+ type: string
+ enum:
+ - PUBLIC
+ - UNLISTED
+ canonicalPath:
+ type: string
+ publishedAt:
+ type: string
+ format: date-time
+ version:
+ type: integer
+ format: int64
+ QuestionPointEdit:
+ type: object
+ required:
+ - kind
+ - content
+ - displayOrder
+ properties:
+ id:
+ type: string
+ format: uuid
+ kind:
+ type: string
+ enum:
+ - FACT
+ - ASSUMPTION
+ - UNKNOWN
+ - CONSTRAINT
+ content:
+ type: string
+ displayOrder:
+ type: integer
+ minimum: 0
+ QuestionUpdateRequest:
+ type: object
+ required:
+ - expectedVersion
+ - type
+ - title
+ - bodyMarkdown
+ - visibility
+ - occurredAt
+ properties:
+ type:
+ type: string
+ enum:
+ - OBSERVATION
+ - EVIDENCE
+ - SCOPE_CHANGE
+ - BLOCKER
+ - NEXT_STEP
+ - RESOLUTION
+ - RESOLUTION_REOPENED
+ title:
+ type: string
+ maxLength: 180
+ bodyMarkdown:
+ type: string
+ visibility:
+ type: string
+ enum:
+ - PRIVATE
+ - PUBLIC
+ occurredAt:
+ type: string
+ format: date-time
+ expectedVersion:
+ type: integer
+ format: int64
+ QuestionUpdateResponse:
+ type: object
+ required:
+ - id
+ - questionVersion
+ - type
+ - title
+ - bodyMarkdown
+ - visibility
+ - occurredAt
+ properties:
+ id:
+ type: string
+ format: uuid
+ questionVersion:
+ type: integer
+ format: int64
+ type:
+ type: string
+ title:
+ type: string
+ bodyMarkdown:
+ type: string
+ visibility:
+ type: string
+ occurredAt:
+ type: string
+ format: date-time
+ QuestionUpdateBody:
+ type: object
+ required:
+ - expectedVersion
+ - question
+ - summary
+ - context
+ - importance
+ - points
+ - tagIds
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ question:
+ type: string
+ maxLength: 300
+ slug:
+ type: string
+ maxLength: 180
+ summary:
+ type: string
+ maxLength: 600
+ context:
+ type: string
+ importance:
+ type: string
+ nextVerification:
+ type: string
+ targetVisibility:
+ type: string
+ enum:
+ - PRIVATE
+ - UNLISTED
+ - PUBLIC
+ primaryProjectId:
+ type: string
+ format: uuid
+ topicId:
+ type: string
+ format: uuid
+ tagIds:
+ type: array
+ maxItems: 12
+ items:
+ type: string
+ format: uuid
+ points:
+ type: array
+ items:
+ $ref: '#/components/schemas/QuestionPointEdit'
+ QuestionEditResponse:
+ type: object
+ required:
+ - id
+ - version
+ - question
+ - status
+ - targetVisibility
+ - points
+ - updates
+ - publication
+ - updatedAt
+ properties:
+ id:
+ type: string
+ format: uuid
+ version:
+ type: integer
+ format: int64
+ question:
+ type: string
+ slug:
+ type: string
+ summary:
+ type: string
+ context:
+ type: string
+ importance:
+ type: string
+ nextVerification:
+ type: string
+ status:
+ type: string
+ targetVisibility:
+ type: string
+ primaryProjectId:
+ type: string
+ format: uuid
+ topicId:
+ type: string
+ format: uuid
+ tagIds:
+ type: array
+ items:
+ type: string
+ format: uuid
+ points:
+ type: array
+ items:
+ $ref: '#/components/schemas/QuestionPointEdit'
+ updates:
+ type: array
+ items:
+ $ref: '#/components/schemas/QuestionUpdateResponse'
+ resolution:
+ type: object
+ properties:
+ type:
+ type: string
+ summary:
+ type: string
+ resolvedAt:
+ type: string
+ format: date-time
+ publication:
+ $ref: '#/components/schemas/PublicationStatus'
+ updatedAt:
+ type: string
+ format: date-time
+ ResolveQuestionRequest:
+ type: object
+ required:
+ - expectedVersion
+ - resolutionType
+ - resolutionSummary
+ - resolvedAt
+ - createCaseDraft
+ - createProjectDecision
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ resolutionType:
+ type: string
+ enum:
+ - DECISION_MADE
+ - ASSUMPTION_REJECTED
+ - QUESTION_REFRAMED
+ - NO_LONGER_RELEVANT
+ resolutionSummary:
+ type: string
+ resolvedAt:
+ type: string
+ format: date-time
+ createCaseDraft:
+ type: boolean
+ createProjectDecision:
+ type: boolean
+ ResolveQuestionResponse:
+ type: object
+ required:
+ - questionId
+ - status
+ - version
+ properties:
+ questionId:
+ type: string
+ format: uuid
+ status:
+ type: string
+ enum:
+ - RESOLVED
+ version:
+ type: integer
+ format: int64
+ createdCaseDraftId:
+ type: string
+ format: uuid
+ createdProjectDecisionId:
+ type: string
+ format: uuid
+ ProjectUpdateRequest:
+ type: object
+ required:
+ - expectedVersion
+ - name
+ - oneLinePurpose
+ - purposeMarkdown
+ - boundaryMarkdown
+ - phase
+ - technologyLabels
+ - targetVisibility
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ name:
+ type: string
+ maxLength: 180
+ slug:
+ type: string
+ maxLength: 180
+ oneLinePurpose:
+ type: string
+ maxLength: 600
+ purposeMarkdown:
+ type: string
+ boundaryMarkdown:
+ type: string
+ systemOverviewMarkdown:
+ type: string
+ phase:
+ type: string
+ currentObjective:
+ type: string
+ nextStep:
+ type: string
+ technologyLabels:
+ type: array
+ items:
+ type: string
+ targetVisibility:
+ type: string
+ enum:
+ - PRIVATE
+ - UNLISTED
+ - PUBLIC
+ featuredOrder:
+ type: integer
+ topicIds:
+ type: array
+ items:
+ type: string
+ format: uuid
+ documentLinks:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectResourceLinkEdit'
+ questionLinks:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectResourceLinkEdit'
+ ProjectEditResponse:
+ type: object
+ required:
+ - id
+ - version
+ - name
+ - phase
+ - workflowStatus
+ - targetVisibility
+ - publication
+ - updatedAt
+ properties:
+ id:
+ type: string
+ format: uuid
+ version:
+ type: integer
+ format: int64
+ name:
+ type: string
+ slug:
+ type: string
+ oneLinePurpose:
+ type: string
+ purposeMarkdown:
+ type: string
+ boundaryMarkdown:
+ type: string
+ systemOverviewMarkdown:
+ type: string
+ phase:
+ type: string
+ currentObjective:
+ type: string
+ nextStep:
+ type: string
+ technologyLabels:
+ type: array
+ items:
+ type: string
+ workflowStatus:
+ type: string
+ targetVisibility:
+ type: string
+ featuredOrder:
+ type: integer
+ publication:
+ $ref: '#/components/schemas/PublicationStatus'
+ updatedAt:
+ type: string
+ format: date-time
+ topicIds:
+ type: array
+ items:
+ type: string
+ format: uuid
+ documentLinks:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectResourceLinkEdit'
+ questionLinks:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectResourceLinkEdit'
+ ChangeProjectPhaseRequest:
+ type: object
+ required:
+ - expectedVersion
+ - phase
+ - reason
+ - publishActivity
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ phase:
+ type: string
+ reason:
+ type: string
+ publishActivity:
+ type: boolean
+ DecisionUpdateRequest:
+ type: object
+ required:
+ - expectedVersion
+ - statement
+ - rationaleMarkdown
+ - consequences
+ - alternativesMarkdown
+ - targetVisibility
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ statement:
+ type: string
+ maxLength: 1000
+ rationaleMarkdown:
+ type: string
+ consequences:
+ type: array
+ items:
+ type: string
+ alternativesMarkdown:
+ type: string
+ targetVisibility:
+ type: string
+ enum:
+ - PRIVATE
+ - PUBLIC
+ sourceQuestionId:
+ type: string
+ format: uuid
+ sourceCaseId:
+ type: string
+ format: uuid
+ isFeatured:
+ type: boolean
+ decidedAt:
+ type: string
+ format: date-time
+ DecisionResponse:
+ allOf:
+ - $ref: '#/components/schemas/DecisionUpdateRequest'
+ - type: object
+ required:
+ - id
+ - projectId
+ - status
+ - version
+ properties:
+ id:
+ type: string
+ format: uuid
+ projectId:
+ type: string
+ format: uuid
+ status:
+ type: string
+ version:
+ type: integer
+ format: int64
+ supersededById:
+ type: string
+ format: uuid
+ ReleaseUpdateRequest:
+ type: object
+ required:
+ - expectedVersion
+ - versionLabel
+ - title
+ - summary
+ - changeTypes
+ - changesMarkdown
+ - verificationMarkdown
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ versionLabel:
+ type: string
+ maxLength: 32
+ title:
+ type: string
+ maxLength: 180
+ summary:
+ type: string
+ maxLength: 600
+ releasedOn:
+ type: string
+ format: date
+ changeTypes:
+ type: array
+ items:
+ type: string
+ reasonMarkdown:
+ type: string
+ changesMarkdown:
+ type: string
+ userImpactMarkdown:
+ type: string
+ implementationImpactMarkdown:
+ type: string
+ verificationMarkdown:
+ type: string
+ knownLimitationsMarkdown:
+ type: string
+ relatedResources:
+ type: array
+ items:
+ type: object
+ required:
+ - resourceType
+ - resourceId
+ properties:
+ resourceType:
+ type: string
+ resourceId:
+ type: string
+ format: uuid
+ ReleaseEditResponse:
+ allOf:
+ - $ref: '#/components/schemas/ReleaseUpdateRequest'
+ - type: object
+ required:
+ - id
+ - workflowStatus
+ - version
+ - publication
+ properties:
+ id:
+ type: string
+ format: uuid
+ workflowStatus:
+ type: string
+ version:
+ type: integer
+ format: int64
+ publication:
+ $ref: '#/components/schemas/PublicationStatus'
+ TopicEdit:
+ type: object
+ required:
+ - name
+ - slug
+ properties:
+ id:
+ type: string
+ format: uuid
+ description: |-
+ 응답에만 실린다. 경로가 `/topics/{id}`이므로 이 값이 없으면 목록에서 어떤 주제도
+ 주소지정할 수 없다 — ProjectEditResponse / CaseEditResponse는 같은 이유로 이미
+ id를 싣고 있었고, TopicEdit만 빠져 있었다. 쓰기 요청에 와도 서버는 무시한다;
+ 수정 대상은 경로가 소유한다.
+ version:
+ type: integer
+ format: int64
+ description: |-
+ 응답에만 실린다. 다음 수정에서 보낼 `expectedVersion`의 출처다. 이것이 없으면
+ 클라이언트가 낙관적 잠금에 쓸 값을 얻을 방법이 없다.
+ name:
+ type: string
+ maxLength: 80
+ slug:
+ type: string
+ maxLength: 100
+ description:
+ type: string
+ maxLength: 600
+ scope:
+ type: string
+ status:
+ type: string
+ enum:
+ - ACTIVE
+ - ARCHIVED
+ expectedVersion:
+ type: integer
+ format: int64
+ featuredReferenceId:
+ type: string
+ format: uuid
+ featuredCaseIds:
+ type: array
+ maxItems: 3
+ items:
+ type: string
+ format: uuid
+ TagEdit:
+ type: object
+ required:
+ - name
+ - slug
+ properties:
+ name:
+ type: string
+ maxLength: 40
+ slug:
+ type: string
+ maxLength: 60
+ expectedVersion:
+ type: integer
+ format: int64
+ SiteConfigRequest:
+ type: object
+ required:
+ - expectedVersion
+ - brandTitle
+ - identityStatement
+ - operatorDisplayName
+ - contacts
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ brandTitle:
+ type: string
+ identityStatement:
+ type: string
+ operatorDisplayName:
+ type: string
+ shortIdentity:
+ type: string
+ avatarAssetId:
+ type: string
+ format: uuid
+ contacts:
+ type: array
+ items:
+ type: object
+ ProfileEditRequest:
+ type: object
+ required:
+ - expectedVersion
+ - headline
+ - workingModel
+ - territories
+ - selectedEvidence
+ - trajectory
+ - contacts
+ - targetVisibility
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ headline:
+ type: string
+ introductionMarkdown:
+ type: string
+ workingModel:
+ type: array
+ items:
+ type: object
+ territories:
+ type: array
+ items:
+ type: object
+ selectedEvidence:
+ type: array
+ items:
+ type: object
+ trajectory:
+ type: array
+ items:
+ type: object
+ contacts:
+ type: array
+ items:
+ type: object
+ targetVisibility:
+ type: string
+ enum:
+ - PRIVATE
+ - PUBLIC
+ HomeFocusRequest:
+ type: object
+ required:
+ - expectedVersion
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ defaultType:
+ type: string
+ enum:
+ - CURRENT_WORK
+ - OPEN_QUESTION
+ - RECENT_DECISION
+ currentProjectId:
+ type: string
+ format: uuid
+ openQuestionId:
+ type: string
+ format: uuid
+ recentDecisionId:
+ type: string
+ format: uuid
+ QuestionIndexItem:
+ type: object
+ required:
+ - id
+ - question
+ - status
+ - targetVisibility
+ - updatedAt
+ - version
+ - publication
+ properties:
+ id:
+ type: string
+ format: uuid
+ question:
+ type: string
+ status:
+ type: string
+ targetVisibility:
+ type: string
+ primaryProject:
+ $ref: '#/components/schemas/ProjectSummary'
+ nextVerification:
+ type: string
+ updatedAt:
+ type: string
+ format: date-time
+ version:
+ type: integer
+ format: int64
+ publication:
+ $ref: '#/components/schemas/PublicationStatus'
+ QuestionIndexPage:
+ type: object
+ required:
+ - items
+ - page
+ properties:
+ items:
+ type: array
+ items:
+ $ref: '#/components/schemas/QuestionIndexItem'
+ page:
+ $ref: '#/components/schemas/PageMetadata'
+ ProjectIndexItem:
+ type: object
+ required:
+ - id
+ - name
+ - phase
+ - workflowStatus
+ - targetVisibility
+ - updatedAt
+ - version
+ - publication
+ properties:
+ id:
+ type: string
+ format: uuid
+ name:
+ type: string
+ phase:
+ type: string
+ workflowStatus:
+ type: string
+ targetVisibility:
+ type: string
+ currentObjective:
+ type: string
+ nextStep:
+ type: string
+ updatedAt:
+ type: string
+ format: date-time
+ version:
+ type: integer
+ format: int64
+ publication:
+ $ref: '#/components/schemas/PublicationStatus'
+ ProjectIndexPage:
+ type: object
+ required:
+ - items
+ - page
+ properties:
+ items:
+ type: array
+ items:
+ $ref: '#/components/schemas/ProjectIndexItem'
+ page:
+ $ref: '#/components/schemas/PageMetadata'
+ ReleaseIndexItem:
+ type: object
+ required:
+ - id
+ - versionLabel
+ - title
+ - workflowStatus
+ - updatedAt
+ - version
+ - publication
+ properties:
+ id:
+ type: string
+ format: uuid
+ versionLabel:
+ type: string
+ title:
+ type: string
+ releasedOn:
+ type: string
+ format: date
+ workflowStatus:
+ type: string
+ updatedAt:
+ type: string
+ format: date-time
+ version:
+ type: integer
+ format: int64
+ publication:
+ $ref: '#/components/schemas/PublicationStatus'
+ ReleaseIndexPage:
+ type: object
+ required:
+ - items
+ - page
+ properties:
+ items:
+ type: array
+ items:
+ $ref: '#/components/schemas/ReleaseIndexItem'
+ page:
+ $ref: '#/components/schemas/PageMetadata'
+ SiteConfigResponse:
+ type: object
+ required:
+ - id
+ - version
+ - brandTitle
+ - identityStatement
+ - operatorDisplayName
+ - contacts
+ properties:
+ id:
+ type: string
+ format: uuid
+ version:
+ type: integer
+ format: int64
+ brandTitle:
+ type: string
+ identityStatement:
+ type: string
+ operatorDisplayName:
+ type: string
+ shortIdentity:
+ type: string
+ avatarAssetId:
+ type: string
+ format: uuid
+ contacts:
+ type: array
+ items:
+ type: object
+ ProfileEditResponse:
+ type: object
+ required:
+ - id
+ - version
+ - headline
+ - workingModel
+ - territories
+ - selectedEvidence
+ - trajectory
+ - contacts
+ - targetVisibility
+ - publication
+ properties:
+ id:
+ type: string
+ format: uuid
+ version:
+ type: integer
+ format: int64
+ headline:
+ type: string
+ introductionMarkdown:
+ type: string
+ workingModel:
+ type: array
+ items:
+ type: object
+ territories:
+ type: array
+ items:
+ type: object
+ selectedEvidence:
+ type: array
+ items:
+ type: object
+ trajectory:
+ type: array
+ items:
+ type: object
+ contacts:
+ type: array
+ items:
+ type: object
+ targetVisibility:
+ type: string
+ publication:
+ $ref: '#/components/schemas/PublicationStatus'
+ HomeFocusResponse:
+ type: object
+ required:
+ - id
+ - version
+ properties:
+ id:
+ type: string
+ format: uuid
+ version:
+ type: integer
+ format: int64
+ defaultType:
+ type: string
+ currentProjectId:
+ type: string
+ format: uuid
+ openQuestionId:
+ type: string
+ format: uuid
+ recentDecisionId:
+ type: string
+ format: uuid
+ ProjectResourceLinkEdit:
+ type: object
+ required:
+ - resourceId
+ - relationType
+ properties:
+ resourceId:
+ type: string
+ format: uuid
+ relationType:
+ type: string
+ enum:
+ - PRIMARY
+ - RELATED
+ featuredOrder:
+ type: integer
+ minimum: 0
+ CreateDecisionRequest:
+ type: object
+ required:
+ - expectedProjectVersion
+ - statement
+ - rationaleMarkdown
+ - consequences
+ - alternativesMarkdown
+ - targetVisibility
+ properties:
+ expectedProjectVersion:
+ type: integer
+ format: int64
+ statement:
+ type: string
+ maxLength: 1000
+ rationaleMarkdown:
+ type: string
+ consequences:
+ type: array
+ items:
+ type: string
+ alternativesMarkdown:
+ type: string
+ targetVisibility:
+ type: string
+ enum:
+ - PRIVATE
+ - PUBLIC
+ sourceQuestionId:
+ type: string
+ format: uuid
+ sourceCaseId:
+ type: string
+ format: uuid
+ isFeatured:
+ type: boolean
+ decidedAt:
+ type: string
+ format: date-time
+ SupersedeDecisionRequest:
+ type: object
+ required:
+ - expectedVersion
+ - supersededById
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ supersededById:
+ type: string
+ format: uuid
+ ProjectActivityRequest:
+ type: object
+ required:
+ - expectedProjectVersion
+ - activityType
+ - title
+ - visibility
+ - occurredAt
+ properties:
+ expectedProjectVersion:
+ type: integer
+ format: int64
+ activityType:
+ type: string
+ title:
+ type: string
+ maxLength: 180
+ summary:
+ type: string
+ maxLength: 600
+ visibility:
+ type: string
+ enum:
+ - PRIVATE
+ - PUBLIC
+ relatedResourceType:
+ type: string
+ relatedResourceId:
+ type: string
+ format: uuid
+ occurredAt:
+ type: string
+ format: date-time
+ ProjectActivityResponse:
+ type: object
+ required:
+ - id
+ - projectId
+ - activityType
+ - title
+ - visibility
+ - origin
+ - occurredAt
+ - version
+ properties:
+ id:
+ type: string
+ format: uuid
+ projectId:
+ type: string
+ format: uuid
+ activityType:
+ type: string
+ title:
+ type: string
+ summary:
+ type: string
+ visibility:
+ type: string
+ origin:
+ type: string
+ relatedResourceType:
+ type: string
+ relatedResourceId:
+ type: string
+ format: uuid
+ occurredAt:
+ type: string
+ format: date-time
+ version:
+ type: integer
+ format: int64
+ UpdateProjectActivityRequest:
+ type: object
+ required:
+ - expectedVersion
+ - title
+ - visibility
+ - occurredAt
+ properties:
+ expectedVersion:
+ type: integer
+ format: int64
+ title:
+ type: string
+ summary:
+ type: string
+ visibility:
+ type: string
+ enum:
+ - PRIVATE
+ - PUBLIC
+ occurredAt:
+ type: string
+ format: date-time
diff --git a/src/features/tech-log/contracts/public/canonical-source.json b/src/features/tech-log/contracts/public/canonical-source.json
index f39638e..1b36765 100644
--- a/src/features/tech-log/contracts/public/canonical-source.json
+++ b/src/features/tech-log/contracts/public/canonical-source.json
@@ -2,7 +2,7 @@
"packageId": "@tech-log/public-contract",
"version": "2.0.0",
"digest": "sha256:8ac71425b38658f34641102b4c2e6e21288c811efebdb92c0a46fb9d4790e23e",
- "sourceRevision": "b98eaf9",
+ "sourceRevision": "6ef5c1c",
"operationIds": [
"getPublicSite",
"getPublicHome",
diff --git a/src/features/tech-log/contracts/studio/canonical-source.json b/src/features/tech-log/contracts/studio/canonical-source.json
index 259f6df..cf93a8e 100644
--- a/src/features/tech-log/contracts/studio/canonical-source.json
+++ b/src/features/tech-log/contracts/studio/canonical-source.json
@@ -2,7 +2,7 @@
"packageId": "@tech-log/studio-contract",
"version": "3.0.0",
"digest": "sha256:6cae9924403d0761f401643a022980b8e04183eea0d890c143c9fbbbbc7431e4",
- "sourceRevision": "b98eaf9",
+ "sourceRevision": "6ef5c1c",
"operationIds": [
"getStudioSession",
"getStudioDashboard",
diff --git a/src/features/tech-log/contracts/tech-log-management-contract-contribution.ts b/src/features/tech-log/contracts/tech-log-management-contract-contribution.ts
new file mode 100644
index 0000000..2dc5c2a
--- /dev/null
+++ b/src/features/tech-log/contracts/tech-log-management-contract-contribution.ts
@@ -0,0 +1,256 @@
+import type {
+ CommandEffectDescriptor,
+ InstalledContractContribution,
+ InstalledHttpContract,
+} from "../../../contracts/external-contract-runtime.ts";
+import type { ProblemDetails } from "./studio/contract.ts";
+import { TECH_LOG_FEATURE_ID } from "../application/tech-log-feature-input.ts";
+import canonicalSource from "./management/canonical-source.json" with { type: "json" };
+import {
+ envelopeData,
+ envelopeError,
+ passthroughInput,
+} from "./tech-log-studio-contract-contribution.ts";
+import { TECH_LOG_STUDIO_SESSION_AUTH_PROFILE_ID } from "../adapters/http/studio-session-credentials.ts";
+
+type PathValues = Readonly>;
+type QueryEntries = readonly (readonly [string, string])[];
+
+const NO_PATH: PathValues = Object.freeze({});
+const NO_QUERY = Object.freeze([]) as QueryEntries;
+const PROBLEM = envelopeError();
+
+/** Studio 쪽과 같은 판정이다: 4xx 도메인 거절은 적용되지 않았음이 확정, 5xx·네트워크는 불확정. */
+const COMMAND_EFFECT: CommandEffectDescriptor = Object.freeze({
+ successEffect: "APPLIED_CONFIRMED" as const,
+ classifyProblem({ status }: Readonly<{ status: number; problem: unknown }>) {
+ return status >= 400 && status < 500 ? "NOT_APPLIED" : "MAYBE_APPLIED";
+ },
+});
+
+/**
+ * 관리 표면은 Studio 와 같은 세션·CSRF 를 쓴다. 계약이 `sessionCookie` 보안과 `CsrfToken`
+ * 파라미터를 선언하고 있고, 실제로 같은 백엔드의 같은 필터 체인을 지난다 — 그래서 인증 프로필도
+ * 공유한다. 부트스트랩 프로필은 쓰지 않는다: CSRF 토큰을 발급하는 것은 `getStudioSession`
+ * 하나뿐이고, 이 표면은 그 뒤에만 호출된다.
+ */
+function readOperation(
+ operationId: string,
+ pathTemplate: string,
+ responseByteLimit: number,
+ project: (input: never) => Readonly<{ pathValues: PathValues; queryEntries: QueryEntries }> = () =>
+ Object.freeze({ pathValues: NO_PATH, queryEntries: NO_QUERY }),
+): InstalledHttpContract {
+ return Object.freeze({
+ contract: Object.freeze({
+ operationId,
+ method: "GET" as const,
+ pathTemplate,
+ inputValidator: passthroughInput(`${operationId}Input`),
+ outputValidator: envelopeData(`${operationId}Output`),
+ problemValidator: PROBLEM,
+ acceptedStatuses: Object.freeze([200]),
+ emptyBodyStatuses: Object.freeze([]),
+ retrySemantics: "SAFE" as const,
+ requestBody: "NONE" as const,
+ responseBody: "REQUIRED_JSON" as const,
+ commandRecovery: null,
+ commandEffect: null,
+ projectRequest(input: never) {
+ return Object.freeze({ ...project(input), body: null });
+ },
+ }),
+ frontend: Object.freeze({
+ policyId: `${operationId}_V1`,
+ requestByteLimit: 0,
+ responseByteLimit,
+ totalDeadlineMs: 10_000,
+ retryBudget: 2 as const,
+ authProfileId: TECH_LOG_STUDIO_SESSION_AUTH_PROFILE_ID,
+ diagnosticsOperation: `techLog.management.${operationId}`,
+ }),
+ }) as InstalledHttpContract;
+}
+
+/**
+ * 쓰기는 `Idempotency-Key` 를 쓰지 않는다 — 계약이 요구하지 않고, 재생 보호는 `expectedVersion`
+ * 이 맡는다. 그래서 `NOT_IDEMPOTENT` 가 아니라 재시도 예산 0 으로 둔다: 응답을 못 본 재시도가
+ * 두 번째 생성을 만들 수 있는 표면이다.
+ */
+function writeOperation(
+ operationId: string,
+ method: "POST" | "PUT" | "DELETE",
+ pathTemplate: string,
+ options: Readonly<{
+ acceptedStatuses: readonly number[];
+ emptyBodyStatuses?: readonly number[];
+ requestByteLimit: number;
+ responseByteLimit: number;
+ }>,
+ project: (input: never) => Readonly<{
+ pathValues: PathValues;
+ queryEntries: QueryEntries;
+ body: unknown;
+ }>,
+): InstalledHttpContract {
+ return Object.freeze({
+ contract: Object.freeze({
+ operationId,
+ method,
+ pathTemplate,
+ inputValidator: passthroughInput(`${operationId}Input`),
+ outputValidator: envelopeData(`${operationId}Output`),
+ problemValidator: PROBLEM,
+ acceptedStatuses: Object.freeze([...options.acceptedStatuses]),
+ emptyBodyStatuses: Object.freeze([...(options.emptyBodyStatuses ?? [])]),
+ // 생성은 재생 보호가 없으므로 NEVER 다. 수정·삭제는 expectedVersion 이 두 번째
+ // 적용을 409 로 막으므로 IDEMPOTENT 로 둘 수 있지만, 세 경우를 한 헬퍼가 만들고
+ // 있어 가장 보수적인 값으로 통일한다 — 재시도 예산도 0 이라 실제 차이는 없다.
+ retrySemantics: "NEVER" as const,
+ requestBody: "JSON" as const,
+ responseBody:
+ (options.emptyBodyStatuses ?? []).length > 0
+ ? ("OPTIONAL_JSON" as const)
+ : ("REQUIRED_JSON" as const),
+ commandRecovery: null,
+ commandEffect: COMMAND_EFFECT,
+ projectRequest(input: never) {
+ return Object.freeze(project(input));
+ },
+ }),
+ frontend: Object.freeze({
+ policyId: `${operationId}_V1`,
+ requestByteLimit: options.requestByteLimit,
+ responseByteLimit: options.responseByteLimit,
+ totalDeadlineMs: 15_000,
+ retryBudget: 0 as const,
+ authProfileId: TECH_LOG_STUDIO_SESSION_AUTH_PROFILE_ID,
+ diagnosticsOperation: `techLog.management.${operationId}`,
+ }),
+ // read 쪽과 달리 여기서만 unknown 을 거친다: `emptyBodyStatuses` 유무로 responseBody 가
+ // 갈리는 삼항이 union 타입을 만들어, 컴파일러가 리터럴을 대상 타입과 겹친다고 보지 않는다.
+ }) as unknown as InstalledHttpContract;
+}
+
+const byId = (input: never) => {
+ const value = input as unknown as Readonly<{ id: string }>;
+ return Object.freeze({ pathValues: Object.freeze({ id: value.id }), queryEntries: NO_QUERY });
+};
+
+const T = "/api/v1/studio/topics";
+const P = "/api/v1/studio/projects";
+
+const HTTP_CONTRACTS = Object.freeze([
+ readOperation("listStudioTopics", T, 131_072),
+ writeOperation(
+ "createTopic",
+ "POST",
+ T,
+ { acceptedStatuses: [201], requestByteLimit: 16_384, responseByteLimit: 16_384 },
+ (input: never) =>
+ Object.freeze({ pathValues: NO_PATH, queryEntries: NO_QUERY, body: input }),
+ ),
+ writeOperation(
+ "updateTopic",
+ "PUT",
+ `${T}/{id}`,
+ { acceptedStatuses: [200], requestByteLimit: 16_384, responseByteLimit: 16_384 },
+ (input: never) => {
+ const value = input as unknown as Readonly<{ id: string; body: unknown }>;
+ return Object.freeze({
+ pathValues: Object.freeze({ id: value.id }),
+ queryEntries: NO_QUERY,
+ body: value.body,
+ });
+ },
+ ),
+ writeOperation(
+ "deleteTopic",
+ "DELETE",
+ `${T}/{id}`,
+ {
+ acceptedStatuses: [204],
+ emptyBodyStatuses: [204],
+ requestByteLimit: 1_024,
+ responseByteLimit: 1_024,
+ },
+ (input: never) => {
+ const value = input as unknown as Readonly<{ id: string; expectedVersion: number }>;
+ return Object.freeze({
+ pathValues: Object.freeze({ id: value.id }),
+ queryEntries: NO_QUERY,
+ body: { expectedVersion: value.expectedVersion },
+ });
+ },
+ ),
+ readOperation("listStudioProjects", P, 262_144, (input: never) => {
+ const value = input as unknown as Readonly<{ page?: number; size?: number }> | undefined;
+ const entries: (readonly [string, string])[] = [];
+ if (value?.page !== undefined) entries.push(["page", String(value.page)]);
+ if (value?.size !== undefined) entries.push(["size", String(value.size)]);
+ return Object.freeze({ pathValues: NO_PATH, queryEntries: Object.freeze(entries) });
+ }),
+ readOperation("getProjectForEdit", `${P}/{id}`, 262_144, byId),
+ writeOperation(
+ "createProject",
+ "POST",
+ P,
+ { acceptedStatuses: [201], requestByteLimit: 4_096, responseByteLimit: 8_192 },
+ (input: never) =>
+ Object.freeze({ pathValues: NO_PATH, queryEntries: NO_QUERY, body: input }),
+ ),
+ writeOperation(
+ "updateProject",
+ "PUT",
+ `${P}/{id}`,
+ { acceptedStatuses: [200], requestByteLimit: 131_072, responseByteLimit: 262_144 },
+ (input: never) => {
+ const value = input as unknown as Readonly<{ id: string; body: unknown }>;
+ return Object.freeze({
+ pathValues: Object.freeze({ id: value.id }),
+ queryEntries: NO_QUERY,
+ body: value.body,
+ });
+ },
+ ),
+ writeOperation(
+ "deleteProject",
+ "DELETE",
+ `${P}/{id}`,
+ {
+ acceptedStatuses: [204],
+ emptyBodyStatuses: [204],
+ requestByteLimit: 1_024,
+ responseByteLimit: 1_024,
+ },
+ (input: never) => {
+ const value = input as unknown as Readonly<{ id: string; expectedVersion: number }>;
+ return Object.freeze({
+ pathValues: Object.freeze({ id: value.id }),
+ queryEntries: NO_QUERY,
+ body: { expectedVersion: value.expectedVersion },
+ });
+ },
+ ),
+]);
+
+export const TECH_LOG_MANAGEMENT_OPERATION_IDS = Object.freeze(
+ HTTP_CONTRACTS.map((entry) => entry.contract.operationId),
+);
+
+export const TECH_LOG_MANAGEMENT_CONTRIBUTION: InstalledContractContribution = Object.freeze({
+ contributionId: "tech-log-management-http-v1",
+ featureId: TECH_LOG_FEATURE_ID,
+ source: Object.freeze({
+ kind: "EXTERNAL_PACKAGE" as const,
+ package: Object.freeze({
+ packageId: canonicalSource.packageId,
+ version: canonicalSource.version,
+ digest: canonicalSource.digest as `sha256:${string}`,
+ runtimeProtocolVersion: 1 as const,
+ sourceRevision: canonicalSource.sourceRevision,
+ }),
+ }),
+ http: HTTP_CONTRACTS,
+ events: Object.freeze([]),
+});
diff --git a/src/features/tech-log/contracts/tech-log-route-contract.ts b/src/features/tech-log/contracts/tech-log-route-contract.ts
index a4b8ec7..6c5292e 100644
--- a/src/features/tech-log/contracts/tech-log-route-contract.ts
+++ b/src/features/tech-log/contracts/tech-log-route-contract.ts
@@ -48,6 +48,7 @@ const TECH_LOG_ROUTE_SPECS = [
defineSpec({ routeId: "TECH_LOG_STUDIO_PUBLICATIONS", path: "/studio/publications", layoutGroup: "STUDIO", paramsSchema: null, searchSchema: null, title: "게시 기록", navigationLabel: "게시 기록", navigationOrder: 20 }),
defineSpec({ routeId: "TECH_LOG_STUDIO_PUBLICATION_PREVIEW", path: "/studio/publications/:publicationEventId/preview", layoutGroup: "STUDIO", paramsSchema: "TechLogPublicationEventIdParams", searchSchema: null, title: "게시 Snapshot", navigationLabel: null, navigationOrder: null }),
defineSpec({ routeId: "TECH_LOG_STUDIO_ASSETS", path: "/studio/assets", layoutGroup: "STUDIO", paramsSchema: null, searchSchema: null, title: "Asset", navigationLabel: null, navigationOrder: null }),
+ defineSpec({ routeId: "TECH_LOG_STUDIO_TAXONOMY", path: "/studio/taxonomy", layoutGroup: "STUDIO", paramsSchema: null, searchSchema: null, title: "주제와 프로젝트", navigationLabel: "주제·프로젝트", navigationOrder: 40 }),
defineSpec({ routeId: "TECH_LOG_STUDIO_NOT_FOUND", path: "/studio/*", layoutGroup: "STUDIO", paramsSchema: "TechLogStudioSplat", searchSchema: null, title: "Studio 화면을 찾을 수 없습니다", navigationLabel: null, navigationOrder: null }),
defineSpec({ routeId: "NOT_FOUND", path: "*", layoutGroup: "PUBLIC", paramsSchema: "NotFoundSplat", searchSchema: null, title: "페이지를 찾을 수 없습니다.", navigationLabel: null, navigationOrder: null }),
] as const;
diff --git a/src/features/tech-log/presentation/public/components/explore-filter-form.tsx b/src/features/tech-log/presentation/public/components/explore-filter-form.tsx
index 52fe466..36931c4 100644
--- a/src/features/tech-log/presentation/public/components/explore-filter-form.tsx
+++ b/src/features/tech-log/presentation/public/components/explore-filter-form.tsx
@@ -56,7 +56,11 @@ export function ExploreFilterForm({
item.title.toLocaleLowerCase("ko-KR") === normalizedProject,
)?.slug;
const hasActiveFilter = Boolean((showType && kind) || topic || project);
- const formKey = [kind, topic, project, showType].join(":");
+ // 선택지는 나중에 도착하는데 아래 select 들은 `defaultValue` 를 쓰는 비제어 요소다 —
+ // 첫 렌더에는 맞출 option 이 없어 값이 비어버린다. 도착 여부를 키에 넣어 그때 폼을
+ // 다시 마운트시키면 defaultValue 가 적용된다. 제어 요소로 바꾸지 않는 이유는 이 폼이
+ // submit 으로 URL 을 만드는 구조라 값의 주인이 URL 이기 때문이다.
+ const formKey = [kind, topic, project, showType, view.ready].join(":");
function submit(event: React.FormEvent) {
event.preventDefault();
diff --git a/src/features/tech-log/presentation/public/components/search-dialog.tsx b/src/features/tech-log/presentation/public/components/search-dialog.tsx
index ee01220..c16439d 100644
--- a/src/features/tech-log/presentation/public/components/search-dialog.tsx
+++ b/src/features/tech-log/presentation/public/components/search-dialog.tsx
@@ -23,7 +23,7 @@ export function SearchDialog({
// result list with a loading skeleton on every key, which is a worse dialog
// than a stale-free local filter. The predicate is the same one the catalog
// applies for a non-empty query, so the visible result set is unchanged.
- const view = usePublicContent(["tech-log", "search", ""], async (queries) => ({
+ const view = usePublicContent(["tech-log", "search", "dialog"], async (queries) => ({
entities: await queries.searchPublicContent(""),
}));
const results = (view.data?.entities ?? []).filter((entity) =>
diff --git a/src/features/tech-log/presentation/public/pages/search-page.tsx b/src/features/tech-log/presentation/public/pages/search-page.tsx
index cf2bd54..9daa1bb 100644
--- a/src/features/tech-log/presentation/public/pages/search-page.tsx
+++ b/src/features/tech-log/presentation/public/pages/search-page.tsx
@@ -13,7 +13,11 @@ export function SearchPage() {
const navigate = useNavigate();
const { search } = useRouteInput<"TECH_LOG_SEARCH">();
const query = optionalString(search.q)?.trim() ?? "";
- const view = usePublicContent(["tech-log", "search", query], async (queries) => ({
+ // 키의 마지막 조각이 화면을 구분한다. 헤더의 검색 다이얼로그도 같은 카탈로그를 읽고
+ // 빈 검색어일 때 앞 세 조각이 완전히 겹치는데, 두 화면이 담아 오는 모양이 다르다
+ // (여기는 `results`, 다이얼로그는 `entities`). 키가 같으면 react-query 가 한쪽 캐시를
+ // 다른 쪽에 돌려주고, 받는 쪽은 없는 필드를 읽다 렌더에서 죽는다.
+ const view = usePublicContent(["tech-log", "search", "page", query], async (queries) => ({
results: await queries.searchPublicContent(query),
}));
diff --git a/src/features/tech-log/presentation/studio/components/taxonomy-manager.tsx b/src/features/tech-log/presentation/studio/components/taxonomy-manager.tsx
new file mode 100644
index 0000000..884b86b
--- /dev/null
+++ b/src/features/tech-log/presentation/studio/components/taxonomy-manager.tsx
@@ -0,0 +1,276 @@
+import { useCallback, useEffect, useState, type FormEvent } from "react";
+
+import type { ProjectIndexItem, TopicEdit } from "../../../contracts/management/contract.ts";
+import { useStudio } from "../use-studio.ts";
+
+/**
+ * 주제와 프로젝트 관리.
+ *
+ * 이 화면이 존재하는 이유는 문서 발행이 주제를 요구하는데 주제를 만들 곳이 없었기 때문이다.
+ * 그래서 범위를 목록·생성·삭제로 끊었다 — 편집(이름 변경, 단계 전환, 공개 범위)은 계약에 있고
+ * 백엔드도 구현돼 있으나, 그 화면은 별도 설계가 필요하다.
+ *
+ *
새 CSS 를 만들지 않는다. 작업본 목록이 쓰는 클래스만 재사용하므로 이 화면은 Studio 의
+ * 나머지와 같은 간격·타이포·색을 그대로 따른다.
+ */
+export function TaxonomyManager() {
+ const { managementGateway, setRequestAnnouncement } = useStudio();
+ const [topics, setTopics] = useState(null);
+ const [projects, setProjects] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState("");
+ const [pending, setPending] = useState(false);
+ const [generation, setGeneration] = useState(0);
+
+ const [topicName, setTopicName] = useState("");
+ const [topicSlug, setTopicSlug] = useState("");
+ const [projectTitle, setProjectTitle] = useState("");
+
+ const reload = useCallback(() => setGeneration((value) => value + 1), []);
+
+ useEffect(() => {
+ let cancelled = false;
+ setLoading(true);
+ setError("");
+ void Promise.all([managementGateway.listTopics(), managementGateway.listProjects(0, 50)]).then(
+ ([topicList, projectPage]) => {
+ if (cancelled) return;
+ setTopics(topicList);
+ setProjects(projectPage.items ?? []);
+ setLoading(false);
+ },
+ () => {
+ if (cancelled) return;
+ setError("주제와 프로젝트를 불러오지 못했습니다.");
+ setLoading(false);
+ },
+ );
+ return () => {
+ cancelled = true;
+ };
+ }, [managementGateway, generation]);
+
+ /**
+ * slug 를 비워 두면 이름에서 만든다. 한글 이름이 흔한데 slug 는 ASCII 만 받으므로, 비운 채로
+ * 저장하면 서버가 422 로 거절한다 — 사용자가 규칙을 몰라도 되도록 여기서 채운다.
+ */
+ const slugify = (value: string) =>
+ value
+ .trim()
+ .toLowerCase()
+ .replace(/[^a-z0-9]+/gu, "-")
+ .replace(/^-+|-+$/gu, "");
+
+ const submitTopic = async (event: FormEvent) => {
+ event.preventDefault();
+ if (pending) return;
+ const name = topicName.trim();
+ const slug = slugify(topicSlug || topicName);
+ if (!name || !slug) {
+ setError("주제 이름과 slug 를 입력해 주세요. slug 는 영문·숫자·하이픈만 가능합니다.");
+ return;
+ }
+ setPending(true);
+ setError("");
+ try {
+ await managementGateway.createTopic({ name, slug } as TopicEdit);
+ setTopicName("");
+ setTopicSlug("");
+ setRequestAnnouncement(`주제 ${name} 을(를) 만들었습니다.`);
+ reload();
+ } catch {
+ setError("주제를 만들지 못했습니다. 같은 이름이나 slug 가 이미 있을 수 있습니다.");
+ } finally {
+ setPending(false);
+ }
+ };
+
+ const submitProject = async (event: FormEvent) => {
+ event.preventDefault();
+ if (pending) return;
+ const title = projectTitle.trim();
+ if (!title) {
+ setError("프로젝트 이름을 입력해 주세요.");
+ return;
+ }
+ setPending(true);
+ setError("");
+ try {
+ await managementGateway.createProject(title);
+ setProjectTitle("");
+ setRequestAnnouncement(`프로젝트 ${title} 을(를) 만들었습니다.`);
+ reload();
+ } catch {
+ setError("프로젝트를 만들지 못했습니다.");
+ } finally {
+ setPending(false);
+ }
+ };
+
+ const removeTopic = async (topic: TopicEdit) => {
+ if (pending || topic.id === undefined || topic.version === undefined) return;
+ setPending(true);
+ setError("");
+ try {
+ await managementGateway.deleteTopic(topic.id, topic.version);
+ setRequestAnnouncement(`주제 ${topic.name} 을(를) 삭제했습니다.`);
+ reload();
+ } catch {
+ setError("주제를 삭제하지 못했습니다. 이 주제를 쓰는 기록이 있을 수 있습니다.");
+ } finally {
+ setPending(false);
+ }
+ };
+
+ const removeProject = async (project: ProjectIndexItem) => {
+ if (pending) return;
+ setPending(true);
+ setError("");
+ try {
+ await managementGateway.deleteProject(project.id, project.version);
+ setRequestAnnouncement(`프로젝트 ${project.name} 을(를) 삭제했습니다.`);
+ reload();
+ } catch {
+ setError("프로젝트를 삭제하지 못했습니다. 연결된 기록이 있을 수 있습니다.");
+ } finally {
+ setPending(false);
+ }
+ };
+
+ return (
+
+
+
+
+
+ {loading ? (
+
+ 주제와 프로젝트를 불러오는 중입니다.
+
+ ) : null}
+ {error ? (
+
+ {error}
+
+ ) : null}
+
+ {!loading && topics ? (
+ <>
+
{topics.length}개의 주제
+ {topics.length ? (
+
+ {topics.map((topic) => (
+
+ TOPIC
+
+
{topic.name}
+
{topic.slug}
+
+
+
+
상태
+ {topic.status === "ARCHIVED" ? "보관" : "사용 중"}
+
+
+ void removeTopic(topic)}
+ >
+ 삭제
+
+
+ ))}
+
+ ) : (
+
아직 주제가 없습니다. 위에서 하나 만들어 주세요.
+ )}
+ >
+ ) : null}
+
+ {!loading && projects ? (
+ <>
+
{projects.length}개의 프로젝트
+ {projects.length ? (
+
+ {projects.map((project) => (
+
+ PROJECT
+
+
{project.name}
+
{project.currentObjective ?? "목표 미지정"}
+
+
+
+
단계
+ {project.phase}
+
+
+
공개
+ {project.targetVisibility}
+
+
+ void removeProject(project)}
+ >
+ 삭제
+
+
+ ))}
+
+ ) : (
+
아직 프로젝트가 없습니다.
+ )}
+ >
+ ) : null}
+
+ );
+}
diff --git a/src/features/tech-log/presentation/studio/pages/taxonomy-page.tsx b/src/features/tech-log/presentation/studio/pages/taxonomy-page.tsx
new file mode 100644
index 0000000..8a65f39
--- /dev/null
+++ b/src/features/tech-log/presentation/studio/pages/taxonomy-page.tsx
@@ -0,0 +1,5 @@
+import { TaxonomyManager } from "../components/taxonomy-manager.tsx";
+
+export function TaxonomyPage() {
+ return ;
+}
diff --git a/src/features/tech-log/presentation/studio/studio-provider.tsx b/src/features/tech-log/presentation/studio/studio-provider.tsx
index 21580a7..36355a8 100644
--- a/src/features/tech-log/presentation/studio/studio-provider.tsx
+++ b/src/features/tech-log/presentation/studio/studio-provider.tsx
@@ -9,6 +9,7 @@ import {
import { isStudioGatewayError } from "../../application/ports/studio-gateway-error.ts";
import type { StudioAssetGateway } from "../../application/ports/studio-asset-gateway.ts";
import type { StudioGateway } from "../../application/ports/studio-gateway.ts";
+import type { ManagementGateway } from "../../application/ports/management-gateway.ts";
import type { ResolvePublishedLabel } from "../../domain/public-render-content.ts";
import type {
WorkingCopy,
@@ -29,6 +30,7 @@ type StudioProviderProps = Readonly<{
// Optional so test harnesses that only exercise the document gateway keep
// working unchanged. `StudioShell` always supplies one in the running app.
createAssetGateway?: () => StudioAssetGateway;
+ createManagementGateway: () => ManagementGateway;
resolvePublishedLabel?: ResolvePublishedLabel;
now?: () => Date;
navigate?: (href: string) => void;
@@ -53,6 +55,7 @@ export function StudioProvider({
children,
createGateway,
createAssetGateway,
+ createManagementGateway,
resolvePublishedLabel = missingPublishedLabel,
now = () => new Date("2026-08-14T01:00:00.000Z"),
navigate = defaultNavigate,
@@ -64,6 +67,7 @@ export function StudioProvider({
const [assetGateway] = useState(
() => createAssetGateway?.() ?? null,
);
+ const [managementGateway] = useState(() => createManagementGateway());
const [editor, setEditor] = useState(null);
const [pendingHref, setPendingHref] = useState(null);
const [requestAnnouncement, setRequestAnnouncement] = useState("");
@@ -159,6 +163,7 @@ export function StudioProvider({
const value = useMemo(
() => ({
gateway,
+ managementGateway,
assetGateway,
resolvePublishedLabel,
now,
@@ -177,6 +182,7 @@ export function StudioProvider({
clearEditor,
editor,
gateway,
+ managementGateway,
navigateInternal,
now,
requestAnnouncement,
diff --git a/src/features/tech-log/presentation/studio/studio-shell.tsx b/src/features/tech-log/presentation/studio/studio-shell.tsx
index 99d49c7..34d6e4d 100644
--- a/src/features/tech-log/presentation/studio/studio-shell.tsx
+++ b/src/features/tech-log/presentation/studio/studio-shell.tsx
@@ -58,6 +58,10 @@ export function StudioShell({ children }: StudioShellProps) {
() => application.features.get(TECH_LOG_FEATURE_ID).createStudioGateway(),
[application],
);
+ const createManagementGateway = useCallback(
+ () => application.features.get(TECH_LOG_FEATURE_ID).createManagementGateway(),
+ [application],
+ );
const createAssetGateway = useCallback(
() => application.features.get(TECH_LOG_FEATURE_ID).createStudioAssetGateway(),
[application],
@@ -92,6 +96,7 @@ export function StudioShell({ children }: StudioShellProps) {
key={generation}
createGateway={createGateway}
createAssetGateway={createAssetGateway}
+ createManagementGateway={createManagementGateway}
resolvePublishedLabel={resolvePublishedLabel}
navigate={navigateInternal}
>
diff --git a/src/features/tech-log/presentation/studio/use-studio.ts b/src/features/tech-log/presentation/studio/use-studio.ts
index aea95e4..5be80a4 100644
--- a/src/features/tech-log/presentation/studio/use-studio.ts
+++ b/src/features/tech-log/presentation/studio/use-studio.ts
@@ -2,6 +2,7 @@ import { createContext, useContext, useMemo } from "react";
import type { StudioAssetGateway } from "../../application/ports/studio-asset-gateway.ts";
import type { StudioGateway } from "../../application/ports/studio-gateway.ts";
+import type { ManagementGateway } from "../../application/ports/management-gateway.ts";
import type { ResolvePublishedLabel } from "../../domain/public-render-content.ts";
import type {
WorkingCopy,
@@ -23,6 +24,9 @@ export type StudioContextValue = Readonly<{
// `createAssetGateway` prop. `StudioShell` — the real app path — always
// supplies one, so production code sees this populated.
assetGateway: StudioAssetGateway | null;
+ // 주제·프로젝트 관리. `assetGateway` 와 같은 이유로 nullable 이 아니다 — 이 표면은
+ // MOCK 소스가 없어 항상 HTTP 이고, 없는 경우가 존재하지 않는다.
+ managementGateway: ManagementGateway;
resolvePublishedLabel: ResolvePublishedLabel;
now(): Date;
editor: StudioEditorState | null;
diff --git a/src/features/tech-log/presentation/tech-log-route-runtime.tsx b/src/features/tech-log/presentation/tech-log-route-runtime.tsx
index 66133a2..57bd97b 100644
--- a/src/features/tech-log/presentation/tech-log-route-runtime.tsx
+++ b/src/features/tech-log/presentation/tech-log-route-runtime.tsx
@@ -209,6 +209,13 @@ export const TECH_LOG_ROUTE_RUNTIME = Object.freeze({
"AssetsPage",
),
),
+ TECH_LOG_STUDIO_TAXONOMY: runtime(
+ "TECH_LOG_STUDIO_TAXONOMY",
+ routeModule(
+ () => import("./studio/pages/taxonomy-page.tsx"),
+ "TaxonomyPage",
+ ),
+ ),
TECH_LOG_STUDIO_NOT_FOUND: runtime(
"TECH_LOG_STUDIO_NOT_FOUND",
routeModule(
diff --git a/tests/features/tech-log/asset-picker.test.tsx b/tests/features/tech-log/asset-picker.test.tsx
index 71f7e18..cf40d18 100644
--- a/tests/features/tech-log/asset-picker.test.tsx
+++ b/tests/features/tech-log/asset-picker.test.tsx
@@ -28,6 +28,7 @@ import { MOCK_STUDIO_INSTALL_CONTEXT } from "../../helpers/studio-install-contex
import type { StudioAssetGateway } from "../../../src/features/tech-log/application/ports/studio-asset-gateway.ts";
import { StudioGatewayError } from "../../../src/features/tech-log/application/ports/studio-gateway-error.ts";
import type { Asset } from "../../../src/features/tech-log/contracts/studio/contract.ts";
+import { createManagementGatewayStub } from "../../helpers/management-gateway-stub.ts";
// jsdom does not implement `` -- same polyfill `studio-save-navigation.test.tsx`
// and `studio-decision-authoring.test.tsx` already use for the other Studio dialogs.
@@ -433,7 +434,8 @@ test("inserts the directive at the saved cursor position and the live preview re
render(
- gateway} createAssetGateway={() => assetGateway}>
+ gateway} createAssetGateway={() => assetGateway}>
,
@@ -538,7 +540,8 @@ test("an asset uploaded through the mock composition previews live and passes mo
render(
- gateway} createAssetGateway={() => assetGateway}>
+ gateway} createAssetGateway={() => assetGateway}>
,
@@ -1259,7 +1262,8 @@ function caseDraft(bodyMarkdown: string) {
function renderInstantPreview(bodyMarkdown: string, assets: readonly Asset[]) {
render(
- createMockStudioGateway()}>
+ createMockStudioGateway()}>
,
@@ -1479,7 +1483,8 @@ test("an asset uploaded with alt text inserts that alt and the document validate
render(
- gateway} createAssetGateway={() => assetGateway}>
+ gateway} createAssetGateway={() => assetGateway}>
,
@@ -1524,7 +1529,8 @@ test("a decorative upload inserts an empty alt and the document is still publish
render(
- gateway} createAssetGateway={() => assetGateway}>
+ gateway} createAssetGateway={() => assetGateway}>
,
@@ -1797,7 +1803,8 @@ test("a Picker search never drops an already-inserted asset out of Instant Previ
render(
- gateway} createAssetGateway={() => assetGateway}>
+ gateway} createAssetGateway={() => assetGateway}>
,
diff --git a/tests/features/tech-log/feature-input.test.ts b/tests/features/tech-log/feature-input.test.ts
index d379aae..1d4bb64 100644
--- a/tests/features/tech-log/feature-input.test.ts
+++ b/tests/features/tech-log/feature-input.test.ts
@@ -16,7 +16,10 @@ type Assert = Condition;
type TechLogFeatureInputExposesNoMissingOrAdditionalKeys = Assert<
Equal<
keyof ApplicationFeatureInputs["tech-log"],
- "publicContent" | "createStudioGateway" | "createStudioAssetGateway"
+ | "publicContent"
+ | "createStudioGateway"
+ | "createStudioAssetGateway"
+ | "createManagementGateway"
>
>;
type TechLogFeatureInputRegistryValueMatchesFeatureContract = Assert<
diff --git a/tests/features/tech-log/navigation-derivation.test.ts b/tests/features/tech-log/navigation-derivation.test.ts
index a1dab08..bc1a2e0 100644
--- a/tests/features/tech-log/navigation-derivation.test.ts
+++ b/tests/features/tech-log/navigation-derivation.test.ts
@@ -28,6 +28,7 @@ describe("TechLog navigation derivation", () => {
["작업본", "/studio/documents"],
["게시 기록", "/studio/publications"],
["새 문서", "/studio/documents/new"],
+ ["주제·프로젝트", "/studio/taxonomy"],
]);
});
diff --git a/tests/features/tech-log/public-discovery-screens.test.tsx b/tests/features/tech-log/public-discovery-screens.test.tsx
index d757185..49506c7 100644
--- a/tests/features/tech-log/public-discovery-screens.test.tsx
+++ b/tests/features/tech-log/public-discovery-screens.test.tsx
@@ -34,6 +34,7 @@ import { ApplicationProvider } from "../../../src/presentation/providers/applica
import { createGroupedRouteObjects } from "../../../src/presentation/routes/app-router.tsx";
import { PLATFORM_ROUTE_CODECS } from "../../../src/presentation/routes/platform-route-codecs.ts";
import { createTestApplication } from "../../helpers/create-test-application.ts";
+import { renderWithQueryProviders } from "../../helpers/query-providers.tsx";
const routeCodecs = Object.freeze({
...PLATFORM_ROUTE_CODECS,
@@ -54,7 +55,7 @@ type DiscoveryRenderOptions = Readonly<{
application?: ReturnType;
}>;
-function renderDiscoveryRoute(
+async function renderDiscoveryRoute(
routeId: RouteId,
initialEntry: string,
options: DiscoveryRenderOptions = {},
@@ -93,6 +94,7 @@ function renderDiscoveryRoute(
);
const techLog = createTechLogFeatureInstalledInput(MOCK_STUDIO_INSTALL_CONTEXT).input;
const view = render(
+ renderWithQueryProviders(
(
>
,
+ ));
+ // 포트가 async 가 되면서 첫 페인트에는 데이터가 없다. 화면이 정착한 뒤
+ // 단언하도록 여기서 한 번 기다린다 — 각 테스트에 흩어 놓으면 빠뜨린 곳이 생긴다.
+ // `main` 을 기다리지 않는다 — 이 파일에는 의도적으로 렌더에 실패하는 라우트도 있고,
+ // 그때는 main 이 아예 없다. 로딩 표면이 사라지는 것이 두 경우 모두에 맞는 기준이다.
+ await waitFor(() =>
+ expect(document.querySelector(".state-surface--loading")).toBeNull(),
);
return { ...view, router } satisfies ReturnType & {
router: RouterProviderProps["router"];
@@ -122,7 +131,7 @@ afterEach(() => {
describe("TechLog home discovery", () => {
it("renders the exact identity, focus, latest ordering, and explore choices", async () => {
- const { router } = renderDiscoveryRoute(
+ const { router } = await renderDiscoveryRoute(
"TECH_LOG_HOME",
"/?focus=invalid&focus=question",
);
@@ -174,7 +183,7 @@ describe("TechLog home discovery", () => {
it("moves linked tabs with arrows, Home, and End while synchronizing the URL", async () => {
const user = userEvent.setup();
- const { router } = renderDiscoveryRoute("TECH_LOG_HOME", "/?focus=question");
+ const { router } = await renderDiscoveryRoute("TECH_LOG_HOME", "/?focus=question");
const question = screen.getByRole("tab", { name: "열린 질문" });
question.focus();
@@ -195,7 +204,7 @@ describe("TechLog home discovery", () => {
});
it("treats external focus URL changes as authoritative without stealing focus", async () => {
- const { router } = renderDiscoveryRoute(
+ const { router } = await renderDiscoveryRoute(
"TECH_LOG_HOME",
"/?focus=current&state=latest-empty#latest",
);
@@ -250,14 +259,14 @@ describe("TechLog home discovery", () => {
expect(screen.getAllByRole("tabpanel")).toHaveLength(1);
});
- it("preserves the source home empty and error states", () => {
- const emptyView = renderDiscoveryRoute("TECH_LOG_HOME", "/?state=latest-empty");
+ it("preserves the source home empty and error states", async () => {
+ const emptyView = await renderDiscoveryRoute("TECH_LOG_HOME", "/?state=latest-empty");
expect(screen.getByText("아직 공개된 기록이 없습니다.")).toHaveClass(
"latest-state--empty",
);
emptyView.unmount();
- const latestErrorView = renderDiscoveryRoute(
+ const latestErrorView = await renderDiscoveryRoute(
"TECH_LOG_HOME",
"/?state=latest-error",
);
@@ -270,14 +279,14 @@ describe("TechLog home discovery", () => {
);
latestErrorView.unmount();
- const errorView = renderDiscoveryRoute("TECH_LOG_HOME", "/?state=site-error");
+ const errorView = await renderDiscoveryRoute("TECH_LOG_HOME", "/?state=site-error");
expect(
screen.getByRole("heading", { name: "페이지를 불러오지 못했습니다." }),
).toBeVisible();
expect(screen.getByText("PREVIEW-HOME-500")).toBeVisible();
errorView.unmount();
- renderDiscoveryRoute("TECH_LOG_HOME", "/?state=focus-empty");
+ await renderDiscoveryRoute("TECH_LOG_HOME", "/?state=focus-empty");
expect(screen.queryByText("지금 집중하는 것")).not.toBeInTheDocument();
});
});
@@ -285,7 +294,7 @@ describe("TechLog home discovery", () => {
describe("TechLog explore discovery", () => {
it("filters by kind, topic, and project and keeps source result structure", async () => {
const user = userEvent.setup();
- const { router } = renderDiscoveryRoute(
+ const { router } = await renderDiscoveryRoute(
"TECH_LOG_EXPLORE",
"/explore?type=CASE&topic=JPA&project=backend-skeleton",
);
@@ -294,9 +303,12 @@ describe("TechLog explore discovery", () => {
expect(
screen.getByText("유형과 기술 주제, 프로젝트를 조합해 공개 기록을 찾습니다."),
).toBeVisible();
- expect(screen.getByLabelText("유형")).toHaveValue("CASE");
- expect(screen.getByLabelText("주제")).toHaveValue("JPA");
- expect(screen.getByLabelText("프로젝트")).toHaveValue("backend-skeleton");
+ // 필터의 선택지는 카탈로그가 도착한 뒤 채워지고, select 의 값도 그때 설정된다.
+ await waitFor(() => {
+ expect(screen.getByLabelText("유형")).toHaveValue("CASE");
+ expect(screen.getByLabelText("주제")).toHaveValue("JPA");
+ expect(screen.getByLabelText("프로젝트")).toHaveValue("backend-skeleton");
+ });
expect(screen.getByText("1개의 공개 기록")).toBeVisible();
expect(
screen.getByRole("link", { name: /컬렉션 Fetch Join과 페이징은 왜 충돌하는가/ }),
@@ -337,8 +349,8 @@ describe("TechLog explore discovery", () => {
]);
});
- it("renders the distinct no-result state for an unmatched query filter", () => {
- renderDiscoveryRoute("TECH_LOG_EXPLORE", "/explore?topic=missing");
+ it("renders the distinct no-result state for an unmatched query filter", async () => {
+ await renderDiscoveryRoute("TECH_LOG_EXPLORE", "/explore?topic=missing");
expect(screen.getByText("0개의 공개 기록")).toBeVisible();
expect(screen.getByText("조건에 맞는 공개 기록이 없습니다.")).toHaveClass(
@@ -351,8 +363,8 @@ describe("TechLog explore discovery", () => {
);
});
- it("keeps kind-specific copy, filtering, count, ordering, and back navigation", () => {
- renderDiscoveryRoute(
+ it("keeps kind-specific copy, filtering, count, ordering, and back navigation", async () => {
+ await renderDiscoveryRoute(
"TECH_LOG_EXPLORE_KIND",
"/explore/questions?topic=JPA&project=backend-skeleton",
);
@@ -374,7 +386,7 @@ describe("TechLog explore discovery", () => {
});
it("keeps the unreachable unknown-kind client fallback accessible", async () => {
- const { router, container } = renderDiscoveryRoute(
+ const { router, container } = await renderDiscoveryRoute(
"TECH_LOG_EXPLORE_KIND",
"/explore/unknown",
);
@@ -425,7 +437,7 @@ describe("TechLog explore discovery", () => {
},
featureInputs: { "tech-log": techLog },
});
- const { router, container } = renderDiscoveryRoute(
+ const { router, container } = await renderDiscoveryRoute(
"TECH_LOG_EXPLORE_KIND",
"/explore/unknown",
{ NotFoundComponent: LazyNotFound, application },
@@ -473,7 +485,7 @@ describe("TechLog explore discovery", () => {
describe("TechLog search discovery", () => {
it("normalizes repeated queries, preserves result ordering, and navigates canonically", async () => {
const user = userEvent.setup();
- const { router } = renderDiscoveryRoute(
+ const { router } = await renderDiscoveryRoute(
"TECH_LOG_SEARCH",
"/search?q=%20JPA%20&q=Redis&unknown=drop",
);
@@ -503,8 +515,8 @@ describe("TechLog search discovery", () => {
it("submits from the keyboard and synchronizes the searchbox with URL changes", async () => {
const user = userEvent.setup();
- const { router } = renderDiscoveryRoute("TECH_LOG_SEARCH", "/search");
- const input = screen.getByRole("searchbox", { name: "검색어" });
+ const { router } = await renderDiscoveryRoute("TECH_LOG_SEARCH", "/search");
+ const input = await screen.findByRole("searchbox", { name: "검색어" });
await user.type(input, "Redis{Enter}");
await waitFor(() => {
@@ -523,7 +535,7 @@ describe("TechLog search discovery", () => {
});
it("normalizes an explicitly empty first query and renders all canonical results", async () => {
- const { router } = renderDiscoveryRoute(
+ const { router } = await renderDiscoveryRoute(
"TECH_LOG_SEARCH",
"/search?q=%20%20&q=JPA",
);
@@ -531,13 +543,13 @@ describe("TechLog search discovery", () => {
await waitFor(() => {
expect(router.state.location.search).toBe("");
});
- expect(screen.getByRole("heading", { name: "전체 검색 결과" })).toBeVisible();
+ expect(await screen.findByRole("heading", { name: "전체 검색 결과" })).toBeVisible();
expect(screen.getByText("9개의 검색 결과")).toBeVisible();
expect(screen.getByRole("searchbox", { name: "검색어" })).toHaveValue("");
});
- it("renders the exact zero-result state without a result list", () => {
- renderDiscoveryRoute("TECH_LOG_SEARCH", "/search?q=존재하지않음");
+ it("renders the exact zero-result state without a result list", async () => {
+ await renderDiscoveryRoute("TECH_LOG_SEARCH", "/search?q=존재하지않음");
expect(screen.getByText("0개의 검색 결과")).toBeVisible();
expect(screen.getByText("일치하는 공개 기록이 없습니다.")).toHaveClass(
@@ -548,7 +560,7 @@ describe("TechLog search discovery", () => {
});
describe("home focus domain", () => {
- it("normalizes selection and wraps all supported keyboard movements", () => {
+ it("normalizes selection and wraps all supported keyboard movements", async () => {
const keys = ["current", "question", "decision"] as const;
expect(normalizeFocus(undefined, keys)).toBe("current");
diff --git a/tests/features/tech-log/public-document-screens.test.tsx b/tests/features/tech-log/public-document-screens.test.tsx
index eeebdeb..3f01a11 100644
--- a/tests/features/tech-log/public-document-screens.test.tsx
+++ b/tests/features/tech-log/public-document-screens.test.tsx
@@ -26,6 +26,7 @@ import { ApplicationProvider } from "../../../src/presentation/providers/applica
import { createGroupedRouteObjects } from "../../../src/presentation/routes/app-router.tsx";
import { PLATFORM_ROUTE_CODECS } from "../../../src/presentation/routes/platform-route-codecs.ts";
import { createTestApplication } from "../../helpers/create-test-application.ts";
+import { renderWithQueryProviders } from "../../helpers/query-providers.tsx";
const routeCodecs = Object.freeze({
...PLATFORM_ROUTE_CODECS,
@@ -63,7 +64,7 @@ afterEach(() => {
vi.unstubAllGlobals();
});
-function renderDocumentRoute(routeId: DocumentRouteId, initialEntry: string) {
+async function renderDocumentRoute(routeId: DocumentRouteId, initialEntry: string) {
const definition = TECH_LOG_ROUTE_REGISTRY[routeId];
const runtime = TECH_LOG_ROUTE_RUNTIME_CONTRACT[routeId];
const Component = routeComponents[routeId];
@@ -95,6 +96,7 @@ function renderDocumentRoute(routeId: DocumentRouteId, initialEntry: string) {
);
const techLog = createTechLogFeatureInstalledInput(MOCK_STUDIO_INSTALL_CONTEXT).input;
const view = render(
+ renderWithQueryProviders(
,
- );
+ ));
+ // 포트가 async 가 되면서 첫 페인트에는 데이터가 없다. 화면이 정착한 뒤
+ // 단언하도록 여기서 한 번 기다린다 — 각 테스트에 흩어 놓으면 빠뜨린 곳이 생긴다.
+ await screen.findByRole("main");
return { ...view, router };
}
@@ -195,8 +200,8 @@ describe("TechLog canonical Public documents", () => {
},
])(
"renders $path with exact metadata, evidence, and ordered relations",
- ({ routeId, path, title, kind, topic, project, published, evidence, relations }) => {
- const { container } = renderDocumentRoute(routeId, path);
+ async ({ routeId, path, title, kind, topic, project, published, evidence, relations }) => {
+ const { container } = await renderDocumentRoute(routeId, path);
const main = screen.getByRole("main");
expect(within(main).getByRole("heading", { level: 1, name: title })).toBeVisible();
@@ -222,8 +227,8 @@ describe("TechLog canonical Public documents", () => {
},
);
- it("preserves the specialized Fetch Join layout, TOC, rendered blocks, anchors, and evidence media", () => {
- const { container } = renderDocumentRoute(
+ it("preserves the specialized Fetch Join layout, TOC, rendered blocks, anchors, and evidence media", async () => {
+ const { container } = await renderDocumentRoute(
"TECH_LOG_CASE",
"/cases/collection-fetch-join-pagination",
);
@@ -253,8 +258,8 @@ describe("TechLog canonical Public documents", () => {
expect(image).toHaveAttribute("loading", "lazy");
});
- it("uses the generic Case markup and omits source relations for the canonical empty state", () => {
- const generic = renderDocumentRoute(
+ it("uses the generic Case markup and omits source relations for the canonical empty state", async () => {
+ const generic = await renderDocumentRoute(
"TECH_LOG_CASE",
"/cases/redis-adapter-ttl-boundary",
);
@@ -264,7 +269,7 @@ describe("TechLog canonical Public documents", () => {
);
generic.unmount();
- const empty = renderDocumentRoute(
+ const empty = await renderDocumentRoute(
"TECH_LOG_CASE",
"/cases/collection-fetch-join-pagination?state=relations-empty",
);
@@ -273,8 +278,8 @@ describe("TechLog canonical Public documents", () => {
expect(screen.queryByRole("heading", { name: "이 기록의 연결" })).not.toBeInTheDocument();
});
- it("preserves Reference rule order and resolved Question evidence and empty copy", () => {
- const reference = renderDocumentRoute(
+ it("preserves Reference rule order and resolved Question evidence and empty copy", async () => {
+ const reference = await renderDocumentRoute(
"TECH_LOG_REFERENCE",
"/references/state-and-nonce-boundary",
);
@@ -290,7 +295,7 @@ describe("TechLog canonical Public documents", () => {
expect(screen.getByText("마지막 검증 2026.08.09")).toBeVisible();
reference.unmount();
- renderDocumentRoute(
+ await renderDocumentRoute(
"TECH_LOG_QUESTION",
"/questions/collection-fetch-join-with-pagination",
);
@@ -311,16 +316,16 @@ describe("TechLog topics and Public not-found routing", () => {
["jpa", "JPA", "목록 조회, 연관 로딩과 페이지 경계를 함께 검증한 기록입니다.", "3개의 관련 기록"],
["authentication", "Authentication", "브라우저와 Edge, Resource Server 사이의 인증 책임과 신뢰 경계를 검증한 기록입니다.", "2개의 관련 기록"],
["redis", "Redis", "애플리케이션 정책과 Redis 저장 명령의 책임 경계를 검증한 기록입니다.", "1개의 관련 기록"],
- ])("aggregates /topics/%s with exact copy and count", (slug, title, description, count) => {
- renderDocumentRoute("TECH_LOG_TOPIC", `/topics/${slug}`);
+ ])("aggregates /topics/%s with exact copy and count", async (slug, title, description, count) => {
+ await renderDocumentRoute("TECH_LOG_TOPIC", `/topics/${slug}`);
expect(screen.getByRole("heading", { level: 1, name: title })).toBeVisible();
expect(screen.getByText(description)).toBeVisible();
expect(screen.getByText(count)).toBeVisible();
});
- it("keeps JPA topic records in canonical published order", () => {
- const { container } = renderDocumentRoute("TECH_LOG_TOPIC", "/topics/jpa");
+ it("keeps JPA topic records in canonical published order", async () => {
+ const { container } = await renderDocumentRoute("TECH_LOG_TOPIC", "/topics/jpa");
expect(
Array.from(container.querySelectorAll(".public-record-list > li > a"), (link) =>
@@ -339,7 +344,7 @@ describe("TechLog topics and Public not-found routing", () => {
["TECH_LOG_QUESTION" as const, "/questions/not-registered"],
["TECH_LOG_TOPIC" as const, "/topics/not-registered"],
])("keeps the unreachable client fallback accessible for %s", async (routeId, path) => {
- const { container, router } = renderDocumentRoute(routeId, path);
+ const { container, router } = await renderDocumentRoute(routeId, path);
expect(router.state.location.pathname).toBe(path);
expect(
diff --git a/tests/features/tech-log/public-index-screens.test.tsx b/tests/features/tech-log/public-index-screens.test.tsx
index 835cc24..2d07fc7 100644
--- a/tests/features/tech-log/public-index-screens.test.tsx
+++ b/tests/features/tech-log/public-index-screens.test.tsx
@@ -31,6 +31,7 @@ import { ApplicationProvider } from "../../../src/presentation/providers/applica
import { createGroupedRouteObjects } from "../../../src/presentation/routes/app-router.tsx";
import { PLATFORM_ROUTE_CODECS } from "../../../src/presentation/routes/platform-route-codecs.ts";
import { createTestApplication } from "../../helpers/create-test-application.ts";
+import { renderWithQueryProviders } from "../../helpers/query-providers.tsx";
const routeCodecs = Object.freeze({
...PLATFORM_ROUTE_CODECS,
@@ -52,7 +53,7 @@ const routeComponents = {
type PublicIndexRouteId = keyof typeof routeComponents;
-function renderPublicRoute(routeId: PublicIndexRouteId, initialEntry: string) {
+async function renderPublicRoute(routeId: PublicIndexRouteId, initialEntry: string) {
const routeIds = routeId === "NOT_FOUND" ? [routeId] : [routeId, "NOT_FOUND" as const];
const registry = Object.fromEntries(
routeIds.map((id) => [id, TECH_LOG_ROUTE_REGISTRY[id]]),
@@ -85,6 +86,7 @@ function renderPublicRoute(routeId: PublicIndexRouteId, initialEntry: string) {
);
const techLog = createTechLogFeatureInstalledInput(MOCK_STUDIO_INSTALL_CONTEXT).input;
const view = render(
+ renderWithQueryProviders(
,
- );
+ ));
+ // 포트가 async 가 되면서 첫 페인트에는 데이터가 없다. 화면이 정착한 뒤
+ // 단언하도록 여기서 한 번 기다린다 — 각 테스트에 흩어 놓으면 빠뜨린 곳이 생긴다.
+ await screen.findByRole("main");
return { ...view, router };
}
@@ -101,8 +106,8 @@ function projectNavigation() {
}
describe("TechLog project screens", () => {
- it("renders the exact ordered project index and project links", () => {
- const { container } = renderPublicRoute("TECH_LOG_PROJECTS", "/projects");
+ it("renders the exact ordered project index and project links", async () => {
+ const { container } = await renderPublicRoute("TECH_LOG_PROJECTS", "/projects");
const main = screen.getByRole("main");
expect(within(main).getByRole("heading", { level: 1, name: "프로젝트" })).toBeVisible();
@@ -145,8 +150,8 @@ describe("TechLog project screens", () => {
stats: ["2공개 기록", "1설계 결정", "2활동 기록"],
topics: ["Authentication", "OAuth 2.0", "OIDC", "Keycloak"],
},
- ])("renders $path overview with source counts and topics", ({ path, title, current, thesis, stats, topics }) => {
- const { container } = renderPublicRoute("TECH_LOG_PROJECT", path);
+ ])("renders $path overview with source counts and topics", async ({ path, title, current, thesis, stats, topics }) => {
+ const { container } = await renderPublicRoute("TECH_LOG_PROJECT", path);
const main = screen.getByRole("main");
expect(within(main).getByRole("heading", { level: 1, name: title })).toBeVisible();
@@ -167,8 +172,8 @@ describe("TechLog project screens", () => {
["TECH_LOG_PROJECT_RECORDS" as const, "/projects/backend-skeleton/records", "기록"],
["TECH_LOG_PROJECT_DECISIONS" as const, "/projects/backend-skeleton/decisions", "결정"],
["TECH_LOG_PROJECT_ACTIVITY" as const, "/projects/backend-skeleton/activity", "활동"],
- ])("derives the active project tab from %s location", (routeId, path, activeLabel) => {
- renderPublicRoute(routeId, path);
+ ])("derives the active project tab from %s location", async (routeId, path, activeLabel) => {
+ await renderPublicRoute(routeId, path);
expect(
within(projectNavigation())
@@ -199,8 +204,8 @@ describe("TechLog project screens", () => {
"/questions/validate-edge-token-again",
],
},
- ])("keeps $slug records filtered and published in source order", ({ slug, expected }) => {
- const { container } = renderPublicRoute(
+ ])("keeps $slug records filtered and published in source order", async ({ slug, expected }) => {
+ const { container } = await renderPublicRoute(
"TECH_LOG_PROJECT_RECORDS",
`/projects/${slug}/records`,
);
@@ -213,8 +218,8 @@ describe("TechLog project screens", () => {
expect(screen.getByText(`${expected.length}개의 공개 기록`)).toBeVisible();
});
- it("keeps project decisions ordered with stable IDs and evidence links", () => {
- const { container } = renderPublicRoute(
+ it("keeps project decisions ordered with stable IDs and evidence links", async () => {
+ const { container } = await renderPublicRoute(
"TECH_LOG_PROJECT_DECISIONS",
"/projects/backend-skeleton/decisions",
);
@@ -240,8 +245,8 @@ describe("TechLog project screens", () => {
]);
});
- it("keeps project activity ordered and preserves self-fragment and record links", () => {
- const { container } = renderPublicRoute(
+ it("keeps project activity ordered and preserves self-fragment and record links", async () => {
+ const { container } = await renderPublicRoute(
"TECH_LOG_PROJECT_ACTIVITY",
"/projects/backend-skeleton/activity",
);
@@ -273,8 +278,8 @@ describe("TechLog project screens", () => {
});
describe("TechLog release and profile screens", () => {
- it("renders the ordered release index and complete version link", () => {
- const { container } = renderPublicRoute("TECH_LOG_RELEASES", "/releases");
+ it("renders the ordered release index and complete version link", async () => {
+ const { container } = await renderPublicRoute("TECH_LOG_RELEASES", "/releases");
expect(screen.getByRole("heading", { level: 1, name: "변경 기록" })).toBeVisible();
expect(
@@ -297,8 +302,8 @@ describe("TechLog release and profile screens", () => {
]);
});
- it("renders exact release sections and ordered cross-links", () => {
- const { container } = renderPublicRoute("TECH_LOG_RELEASE", "/releases/0.1.0");
+ it("renders exact release sections and ordered cross-links", async () => {
+ const { container } = await renderPublicRoute("TECH_LOG_RELEASE", "/releases/0.1.0");
const main = screen.getByRole("main");
expect(
@@ -325,8 +330,8 @@ describe("TechLog release and profile screens", () => {
).toEqual(["/", "/explore", "/cases/collection-fetch-join-pagination"]);
});
- it("renders the grounded profile, principles, project links, and topics", () => {
- const { container } = renderPublicRoute("TECH_LOG_PROFILE", "/profile");
+ it("renders the grounded profile, principles, project links, and topics", async () => {
+ const { container } = await renderPublicRoute("TECH_LOG_PROFILE", "/profile");
const main = screen.getByRole("main");
expect(within(main).getByRole("heading", { level: 1, name: "동현" })).toBeVisible();
@@ -362,7 +367,7 @@ describe("TechLog Public not-found runtime", () => {
["TECH_LOG_RELEASE" as const, "/releases/9.9.9"],
["TECH_LOG_CASE" as const, "/cases/not-registered"],
])("keeps the client-only fallback accessible for %s", async (routeId, path) => {
- const { container, router } = renderPublicRoute(routeId, path);
+ const { container, router } = await renderPublicRoute(routeId, path);
expect(router.state.location.pathname).toBe(path);
expect(
@@ -374,8 +379,8 @@ describe("TechLog Public not-found runtime", () => {
expect(container.querySelector(".site-frame")).not.toBeNull();
});
- it("keeps the client-only Public catch-all accessible", () => {
- const { container, router } = renderPublicRoute(
+ it("keeps the client-only Public catch-all accessible", async () => {
+ const { container, router } = await renderPublicRoute(
"NOT_FOUND",
"/definitely-not-a-product-route",
);
diff --git a/tests/features/tech-log/public-shell.test.tsx b/tests/features/tech-log/public-shell.test.tsx
index 2dab991..fef1ce7 100644
--- a/tests/features/tech-log/public-shell.test.tsx
+++ b/tests/features/tech-log/public-shell.test.tsx
@@ -11,6 +11,7 @@ import { FatalErrorState } from "../../../src/features/tech-log/presentation/pub
import { PublicShell } from "../../../src/features/tech-log/presentation/public/public-shell.tsx";
import { ApplicationProvider } from "../../../src/presentation/providers/application-provider.tsx";
import { createTestApplication } from "../../helpers/create-test-application.ts";
+import { renderWithQueryProviders } from "../../helpers/query-providers.tsx";
const originalShowModal = HTMLDialogElement.prototype.showModal;
const originalClose = HTMLDialogElement.prototype.close;
@@ -47,7 +48,7 @@ afterEach(() => {
});
});
-function renderShell(initialEntry = "/projects") {
+async function renderShell(initialEntry = "/projects") {
const techLog = createTechLogFeatureInstalledInput(MOCK_STUDIO_INSTALL_CONTEXT).input;
const router = createMemoryRouter(
[
@@ -65,6 +66,7 @@ function renderShell(initialEntry = "/projects") {
{ initialEntries: [initialEntry] },
);
const view = render(
+ renderWithQueryProviders(
,
- );
+ ));
+ // 포트가 async 가 되면서 첫 페인트에는 데이터가 없다. 화면이 정착한 뒤
+ // 단언하도록 여기서 한 번 기다린다 — 각 테스트에 흩어 놓으면 빠뜨린 곳이 생긴다.
+ await screen.findByRole("main");
return { ...view, router };
}
describe("TechLog Public shell", () => {
- it("preserves source landmark order, navigation copy, current state, and footer", () => {
- const view = renderShell();
+ it("preserves source landmark order, navigation copy, current state, and footer", async () => {
+ const view = await renderShell();
const frame = view.container.querySelector(".site-frame");
expect(
@@ -127,7 +132,7 @@ describe("TechLog Public shell", () => {
it("uses the canonical root route for brand navigation", async () => {
const user = userEvent.setup();
- const { router } = renderShell("/projects/backend-skeleton");
+ const { router } = await renderShell("/projects/backend-skeleton");
await user.click(screen.getByRole("link", { name: "TechLog 홈" }));
@@ -136,7 +141,7 @@ describe("TechLog Public shell", () => {
it("opens search by click, closes on Escape, and restores trigger focus", async () => {
const user = userEvent.setup();
- renderShell();
+ await renderShell();
const trigger = screen.getByRole("button", { name: "TechLog 검색 열기" });
await user.click(trigger);
@@ -155,7 +160,7 @@ describe("TechLog Public shell", () => {
it("opens the native search trigger from the keyboard", async () => {
const user = userEvent.setup();
- renderShell();
+ await renderShell();
const trigger = screen.getByRole("button", { name: "TechLog 검색 열기" });
trigger.focus();
@@ -169,7 +174,7 @@ describe("TechLog Public shell", () => {
it("returns source-equivalent results and navigates to their canonical route", async () => {
const user = userEvent.setup();
- const { router } = renderShell();
+ const { router } = await renderShell();
await user.click(
screen.getByRole("button", { name: "TechLog 검색 열기" }),
);
@@ -191,7 +196,7 @@ describe("TechLog Public shell", () => {
it("navigates the full-search action with its canonical query intact", async () => {
const user = userEvent.setup();
- const { router } = renderShell();
+ const { router } = await renderShell();
await user.click(
screen.getByRole("button", { name: "TechLog 검색 열기" }),
);
@@ -210,7 +215,7 @@ describe("TechLog Public shell", () => {
it("uses native mobile disclosure activation and closes it after selection", async () => {
const user = userEvent.setup();
- const view = renderShell();
+ const view = await renderShell();
const details = view.container.querySelector(
"details.mobile-nav",
);
@@ -236,7 +241,7 @@ describe("TechLog Public shell", () => {
it("closes a natively opened mobile disclosure before opening one search dialog", async () => {
const user = userEvent.setup();
- const view = renderShell();
+ const view = await renderShell();
const details = view.container.querySelector(
"details.mobile-nav",
);
diff --git a/tests/features/tech-log/route-contract.test.ts b/tests/features/tech-log/route-contract.test.ts
index 47f3237..e471e64 100644
--- a/tests/features/tech-log/route-contract.test.ts
+++ b/tests/features/tech-log/route-contract.test.ts
@@ -38,6 +38,7 @@ const expectedRoutes = [
["TECH_LOG_STUDIO_PUBLICATIONS", "/studio/publications", "STUDIO", null, null],
["TECH_LOG_STUDIO_PUBLICATION_PREVIEW", "/studio/publications/:publicationEventId/preview", "STUDIO", "TechLogPublicationEventIdParams", null],
["TECH_LOG_STUDIO_ASSETS", "/studio/assets", "STUDIO", null, null],
+ ["TECH_LOG_STUDIO_TAXONOMY", "/studio/taxonomy", "STUDIO", null, null],
["TECH_LOG_STUDIO_NOT_FOUND", "/studio/*", "STUDIO", "TechLogStudioSplat", null],
["NOT_FOUND", "*", "PUBLIC", "NotFoundSplat", null],
] as const;
@@ -69,6 +70,7 @@ const expectedTitles = {
TECH_LOG_STUDIO_PUBLICATIONS: "게시 기록",
TECH_LOG_STUDIO_PUBLICATION_PREVIEW: "게시 Snapshot",
TECH_LOG_STUDIO_ASSETS: "Asset",
+ TECH_LOG_STUDIO_TAXONOMY: "주제와 프로젝트",
TECH_LOG_STUDIO_NOT_FOUND: "Studio 화면을 찾을 수 없습니다",
NOT_FOUND: "페이지를 찾을 수 없습니다.",
} as const;
@@ -142,12 +144,13 @@ describe("TechLog route boundary contract", () => {
["TECH_LOG_STUDIO_DOCUMENTS", "STUDIO", "작업본", 10],
["TECH_LOG_STUDIO_DOCUMENT_NEW", "STUDIO", "새 문서", 30],
["TECH_LOG_STUDIO_PUBLICATIONS", "STUDIO", "게시 기록", 20],
+ ["TECH_LOG_STUDIO_TAXONOMY", "STUDIO", "주제·프로젝트", 40],
]);
for (const locale of ["ko-KR", "en-US"] as const) {
const catalog: Readonly> =
TECH_LOG_MESSAGE_CATALOGS[locale];
- expect(Object.keys(catalog)).toHaveLength(56);
+ expect(Object.keys(catalog)).toHaveLength(58);
for (const [routeId, title] of Object.entries(expectedTitles)) {
expect(catalog[`route.${routeId}.title`]).toBe(title);
expect(catalog[`route.${routeId}.navigation`]).toBe(title);
diff --git a/tests/features/tech-log/runtime-composition.test.ts b/tests/features/tech-log/runtime-composition.test.ts
index 039441a..61d1b89 100644
--- a/tests/features/tech-log/runtime-composition.test.ts
+++ b/tests/features/tech-log/runtime-composition.test.ts
@@ -60,6 +60,7 @@ test("installs TechLog beside the retained reference feature through application
assert.deepEqual(Object.keys(installed), ["reference-feature", "tech-log"]);
assert.deepEqual(Object.keys(installed["tech-log"]).sort(), [
+ "createManagementGateway",
"createStudioAssetGateway",
"createStudioGateway",
"publicContent",
diff --git a/tests/features/tech-log/studio-decision-authoring.test.tsx b/tests/features/tech-log/studio-decision-authoring.test.tsx
index cfe1364..9484ad6 100644
--- a/tests/features/tech-log/studio-decision-authoring.test.tsx
+++ b/tests/features/tech-log/studio-decision-authoring.test.tsx
@@ -14,6 +14,7 @@ import type { WorkingCopyInput } from "../../../src/features/tech-log/contracts/
import { DocumentEditorScreen } from "../../../src/features/tech-log/presentation/studio/components/document-editor-screen.tsx";
import { NewDocumentForm } from "../../../src/features/tech-log/presentation/studio/components/new-document-form.tsx";
import { StudioProvider } from "../../../src/features/tech-log/presentation/studio/studio-provider.tsx";
+import { createManagementGatewayStub } from "../../helpers/management-gateway-stub.ts";
type DecisionInput = Extract;
@@ -54,6 +55,7 @@ function RouterStudioProvider({
const navigate = useNavigate();
return (
gateway}
navigate={(href) => { void navigate(href); }}
>
@@ -140,7 +142,8 @@ describe("TechLog Studio project decision authoring", () => {
});
render(
- gateway}>
+ gateway}>
,
diff --git a/tests/features/tech-log/studio-editor-smoke.test.tsx b/tests/features/tech-log/studio-editor-smoke.test.tsx
index dc55ebd..1fe1806 100644
--- a/tests/features/tech-log/studio-editor-smoke.test.tsx
+++ b/tests/features/tech-log/studio-editor-smoke.test.tsx
@@ -12,6 +12,7 @@ import { FIXTURE_IDS } from "../../../src/features/tech-log/adapters/mock/fixtur
import type { StudioGateway } from "../../../src/features/tech-log/application/ports/studio-gateway.ts";
import { DocumentEditorScreen } from "../../../src/features/tech-log/presentation/studio/components/document-editor-screen.tsx";
import { StudioProvider } from "../../../src/features/tech-log/presentation/studio/studio-provider.tsx";
+import { createManagementGatewayStub } from "../../helpers/management-gateway-stub.ts";
afterEach(() => vi.restoreAllMocks());
@@ -26,7 +27,8 @@ function renderEditor(
.input.createStudioAssetGateway();
return render(
- gateway} createAssetGateway={() => assetGateway}>
+ gateway} createAssetGateway={() => assetGateway}>
,
diff --git a/tests/features/tech-log/studio-publication-flow.test.tsx b/tests/features/tech-log/studio-publication-flow.test.tsx
index 630685e..4d4f8fa 100644
--- a/tests/features/tech-log/studio-publication-flow.test.tsx
+++ b/tests/features/tech-log/studio-publication-flow.test.tsx
@@ -24,6 +24,7 @@ import { PublicationEventPreviewScreen } from "../../../src/features/tech-log/pr
import { PublicationList } from "../../../src/features/tech-log/presentation/studio/components/publication-list.tsx";
import { PublishScreen } from "../../../src/features/tech-log/presentation/studio/components/publish-screen.tsx";
import { StudioProvider } from "../../../src/features/tech-log/presentation/studio/studio-provider.tsx";
+import { createManagementGatewayStub } from "../../helpers/management-gateway-stub.ts";
const originalShowModal = HTMLDialogElement.prototype.showModal;
const originalClose = HTMLDialogElement.prototype.close;
@@ -85,7 +86,8 @@ function renderInStudio(
) {
return render(
- gateway} navigate={navigate}>
+ gateway} navigate={navigate}>
{node}
,
diff --git a/tests/features/tech-log/studio-save-navigation.test.tsx b/tests/features/tech-log/studio-save-navigation.test.tsx
index 602141c..919fa28 100644
--- a/tests/features/tech-log/studio-save-navigation.test.tsx
+++ b/tests/features/tech-log/studio-save-navigation.test.tsx
@@ -23,6 +23,7 @@ import {
useStudio,
useStudioEditorSession,
} from "../../../src/features/tech-log/presentation/studio/use-studio.ts";
+import { createManagementGatewayStub } from "../../helpers/management-gateway-stub.ts";
const originalShowModal = HTMLDialogElement.prototype.showModal;
const originalClose = HTMLDialogElement.prototype.close;
@@ -86,7 +87,8 @@ function renderEditor(documentId: string, gateway: StudioGateway) {
.input.createStudioAssetGateway();
return render(
- gateway} createAssetGateway={() => assetGateway}>
+ gateway} createAssetGateway={() => assetGateway}>
@@ -214,7 +216,8 @@ describe("TechLog Studio dirty navigation", () => {
const saved = await getSavedDocument(gateway);
render(
- gateway} navigate={(href) => destinations.push(href)}>
+ gateway} navigate={(href) => destinations.push(href)}>
,
@@ -251,7 +254,8 @@ describe("TechLog Studio dirty navigation", () => {
const saved = await getSavedDocument(gateway);
render(
- gateway} navigate={(href) => destinations.push(href)}>
+ gateway} navigate={(href) => destinations.push(href)}>
,
@@ -283,7 +287,8 @@ describe("TechLog Studio dirty navigation", () => {
const saved = await getSavedDocument(base);
render(
- gateway} navigate={(href) => destinations.push(href)}>
+ gateway} navigate={(href) => destinations.push(href)}>
,
diff --git a/tests/features/tech-log/studio-screens-smoke.test.tsx b/tests/features/tech-log/studio-screens-smoke.test.tsx
index 6cace79..3e3a6b3 100644
--- a/tests/features/tech-log/studio-screens-smoke.test.tsx
+++ b/tests/features/tech-log/studio-screens-smoke.test.tsx
@@ -16,6 +16,7 @@ import { StudioDashboard } from "../../../src/features/tech-log/presentation/stu
import { StudioProvider } from "../../../src/features/tech-log/presentation/studio/studio-provider.tsx";
import { ApplicationProvider } from "../../../src/presentation/providers/application-provider.tsx";
import { createTestApplication } from "../../helpers/create-test-application.ts";
+import { createManagementGatewayStub } from "../../helpers/management-gateway-stub.ts";
afterEach(() => vi.restoreAllMocks());
@@ -30,6 +31,7 @@ function RouterStudioProvider({
const navigate = useNavigate();
return (
gateway}
navigate={(href) => {
void navigate(href);
diff --git a/tests/features/tech-log/studio-shell-smoke.test.tsx b/tests/features/tech-log/studio-shell-smoke.test.tsx
index 8af8833..87f8131 100644
--- a/tests/features/tech-log/studio-shell-smoke.test.tsx
+++ b/tests/features/tech-log/studio-shell-smoke.test.tsx
@@ -15,10 +15,11 @@ import { createExternalAuthSessionAdapter } from "../../../src/adapters/auth/ext
import { ApplicationProvider } from "../../../src/presentation/providers/application-provider.tsx";
import { SessionProvider } from "../../../src/presentation/providers/session-provider.tsx";
import { createTestApplication } from "../../helpers/create-test-application.ts";
+import { renderWithQueryProviders } from "../../helpers/query-providers.tsx";
afterEach(() => vi.restoreAllMocks());
-function renderStudio(
+async function renderStudio(
initialEntry: string,
createStudioGateway: () => StudioGateway,
) {
@@ -62,12 +63,16 @@ function renderStudio(
},
});
const view = render(
+ renderWithQueryProviders(
,
- );
+ ));
+ // 포트가 async 가 되면서 첫 페인트에는 데이터가 없다. 화면이 정착한 뒤
+ // 단언하도록 여기서 한 번 기다린다 — 각 테스트에 흩어 놓으면 빠뜨린 곳이 생긴다.
+ await screen.findByRole("main");
return { ...view, router };
}
@@ -77,7 +82,7 @@ describe("TechLog Studio shell", () => {
const gateway = createTechLogFeatureInstalledInput(MOCK_STUDIO_INSTALL_CONTEXT).input.createStudioGateway();
const createGateway = vi.fn(() => gateway);
- const { container, router } = renderStudio("/studio", createGateway);
+ const { container, router } = await renderStudio("/studio", createGateway);
expect(await screen.findByRole("heading", { level: 1, name: "작업 흐름" })).toBeVisible();
expect(createGateway).toHaveBeenCalledTimes(1);
@@ -90,6 +95,7 @@ describe("TechLog Studio shell", () => {
["작업본", "/studio/documents"],
["게시 기록", "/studio/publications"],
["새 문서", "/studio/documents/new"],
+ ["주제·프로젝트", "/studio/taxonomy"],
["공개 사이트 보기", "/"],
]);
expect(screen.getByRole("link", { name: "공개 사이트 보기" })).toHaveAttribute("href", "/");
@@ -117,7 +123,7 @@ describe("TechLog Studio shell", () => {
.mockReturnValueOnce(first)
.mockReturnValueOnce(second);
- renderStudio("/studio", createGateway);
+ await renderStudio("/studio", createGateway);
await waitFor(() => expect(firstSignal).toBeDefined());
await user.click(screen.getByRole("button", { name: "Studio 메뉴 열기" }));
expect(screen.getByRole("button", { name: "Studio 메뉴 닫기" })).toBeVisible();
@@ -131,12 +137,12 @@ describe("TechLog Studio shell", () => {
expect(secondDashboard).toHaveBeenCalledTimes(1);
});
- it("keeps unknown Studio routes inside the Studio shell without authentication UI", () => {
+ it("keeps unknown Studio routes inside the Studio shell without authentication UI", async () => {
const createGateway = vi.fn(
() => createTechLogFeatureInstalledInput(MOCK_STUDIO_INSTALL_CONTEXT).input.createStudioGateway(),
);
- renderStudio("/studio/does-not-exist", createGateway);
+ await renderStudio("/studio/does-not-exist", createGateway);
expect(screen.getByRole("banner")).toHaveClass("studio-header");
expect(screen.getByRole("heading", { level: 1, name: "Studio 화면을 찾을 수 없습니다" })).toBeVisible();
diff --git a/tests/features/tech-log/studio-validation-preview.test.tsx b/tests/features/tech-log/studio-validation-preview.test.tsx
index 733b85e..d588d97 100644
--- a/tests/features/tech-log/studio-validation-preview.test.tsx
+++ b/tests/features/tech-log/studio-validation-preview.test.tsx
@@ -13,6 +13,7 @@ import { DocumentEditorScreen } from "../../../src/features/tech-log/presentatio
import { PublicPreviewScreen } from "../../../src/features/tech-log/presentation/studio/components/public-preview-screen.tsx";
import { ValidationScreen } from "../../../src/features/tech-log/presentation/studio/components/validation-screen.tsx";
import { StudioProvider } from "../../../src/features/tech-log/presentation/studio/studio-provider.tsx";
+import { createManagementGatewayStub } from "../../helpers/management-gateway-stub.ts";
class NoopIntersectionObserver implements IntersectionObserver {
readonly root = null;
@@ -44,7 +45,8 @@ function renderStudio(
) {
return render(
- gateway}>{child}
+ gateway}>{child}
,
);
}
@@ -130,7 +132,8 @@ describe("TechLog Studio validation workflow", () => {
view.rerender(
- gateway}>
+ gateway}>
,
diff --git a/tests/features/tech-log/style-contract.test.ts b/tests/features/tech-log/style-contract.test.ts
index e5588b6..962f27d 100644
--- a/tests/features/tech-log/style-contract.test.ts
+++ b/tests/features/tech-log/style-contract.test.ts
@@ -1,6 +1,6 @@
// @vitest-environment jsdom
-import { render } from "@testing-library/react";
+import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
@@ -14,6 +14,7 @@ import { FatalErrorState } from "../../../src/features/tech-log/presentation/pub
import { PublicShell } from "../../../src/features/tech-log/presentation/public/public-shell.tsx";
import { ApplicationProvider } from "../../../src/presentation/providers/application-provider.tsx";
import { createTestApplication } from "../../helpers/create-test-application.ts";
+import { renderWithQueryProviders } from "../../helpers/query-providers.tsx";
let styleElement: HTMLStyleElement;
@@ -33,7 +34,7 @@ afterAll(() => {
styleElement.remove();
});
-function renderPublicSurface(node: React.ReactNode) {
+async function renderPublicSurface(node: React.ReactNode) {
const techLog = createTechLogFeatureInstalledInput(MOCK_STUDIO_INSTALL_CONTEXT).input;
const shell = createElement(PublicShell, { children: node });
const router = createElement(
@@ -41,19 +42,24 @@ function renderPublicSurface(node: React.ReactNode) {
{ initialEntries: ["/projects"] },
shell,
);
- return render(
- createElement(ApplicationProvider, {
- application: createTestApplication({
- featureInputs: { "tech-log": techLog },
+ const view = render(
+ renderWithQueryProviders(
+ createElement(ApplicationProvider, {
+ application: createTestApplication({
+ featureInputs: { "tech-log": techLog },
+ }),
+ children: router,
}),
- children: router,
- }),
+ ),
);
+ // 포트가 async 가 되면서 첫 페인트에는 데이터가 없다. 화면이 정착한 뒤 단언한다.
+ await screen.findByRole("main");
+ return view;
}
describe("TechLog consumer-visible style contract", () => {
- it("applies the source typography, palette, shell width, and header spacing", () => {
- const view = renderPublicSurface(
+ it("applies the source typography, palette, shell width, and header spacing", async () => {
+ const view = await renderPublicSurface(
createElement(
"main",
{ id: "main-content", className: "shell" },
@@ -97,8 +103,8 @@ describe("TechLog consumer-visible style contract", () => {
expect(getComputedStyle(wordmark).fontWeight).toBe("680");
});
- it("aligns code, table, and evidence widths with the article body", () => {
- const view = renderPublicSurface(
+ it("aligns code, table, and evidence widths with the article body", async () => {
+ const view = await renderPublicSurface(
createElement(
"main",
{ id: "main-content", className: "shell" },
@@ -152,7 +158,7 @@ describe("TechLog consumer-visible style contract", () => {
it("preserves keyboard focus and the real search-field focus style", async () => {
const user = userEvent.setup();
- const view = renderPublicSurface(
+ const view = await renderPublicSurface(
createElement(
"main",
{ id: "main-content", className: "shell" },
@@ -181,8 +187,8 @@ describe("TechLog consumer-visible style contract", () => {
);
});
- it("keeps every header and dialog control at the source minimum target size", () => {
- const view = renderPublicSurface(
+ it("keeps every header and dialog control at the source minimum target size", async () => {
+ const view = await renderPublicSurface(
createElement(
"main",
{ id: "main-content", className: "shell" },
@@ -218,8 +224,8 @@ describe("TechLog consumer-visible style contract", () => {
expect(getComputedStyle(dialogInner!).padding).toBe("27px 28px 22px");
});
- it("preserves footer spacing and fatal-action sizing", () => {
- const view = renderPublicSurface(
+ it("preserves footer spacing and fatal-action sizing", async () => {
+ const view = await renderPublicSurface(
createElement(FatalErrorState, {
traceId: "PUBLIC-500",
retryHref: "/",
diff --git a/tests/features/tech-log/use-studio-asset-gateway.test.tsx b/tests/features/tech-log/use-studio-asset-gateway.test.tsx
index b8a41f9..ace91d3 100644
--- a/tests/features/tech-log/use-studio-asset-gateway.test.tsx
+++ b/tests/features/tech-log/use-studio-asset-gateway.test.tsx
@@ -26,6 +26,8 @@ function contextValue(
return {
gateway: {} as never,
assetGateway,
+ // 이 테스트는 Asset 접근자만 고정한다 — 관리 게이트웨이는 쓰이지 않으므로 자리만 채운다.
+ managementGateway: {} as never,
resolvePublishedLabel: () => undefined,
now: () => new Date("2026-08-14T01:00:00.000Z"),
editor: null,
diff --git a/tests/helpers/management-gateway-stub.ts b/tests/helpers/management-gateway-stub.ts
new file mode 100644
index 0000000..7aa954a
--- /dev/null
+++ b/tests/helpers/management-gateway-stub.ts
@@ -0,0 +1,28 @@
+import type { ManagementGateway } from "../../src/features/tech-log/application/ports/management-gateway.ts";
+
+/**
+ * Studio 화면 테스트가 `StudioProvider` 를 렌더할 때 필요한 최소 관리 게이트웨이.
+ *
+ * 기본값은 "아무것도 없음" 이다. 이 하네스들은 문서·Asset 흐름을 검증하지 아니 주제·프로젝트
+ * 관리를 검증하지 않으므로, 호출되면 빈 목록을 주고 쓰기는 거부한다 — 조용히 성공시키면 관리
+ * 표면을 실수로 건드리는 테스트가 통과해 버린다.
+ */
+export function createManagementGatewayStub(
+ overrides: Partial = {},
+): ManagementGateway {
+ const unused = (name: string) => async (): Promise => {
+ throw new Error(`management gateway ${name} was not stubbed for this test`);
+ };
+ return Object.freeze({
+ listTopics: async () => [],
+ listProjects: async () => ({ items: [], page: {} }) as never,
+ createTopic: unused("createTopic"),
+ updateTopic: unused("updateTopic"),
+ deleteTopic: unused("deleteTopic"),
+ getProject: unused("getProject"),
+ createProject: unused("createProject"),
+ updateProject: unused("updateProject"),
+ deleteProject: unused("deleteProject"),
+ ...overrides,
+ }) as ManagementGateway;
+}
diff --git a/tests/unit/ci-workflow-generation.test.ts b/tests/unit/ci-workflow-generation.test.ts
index 88e41c5..7e25b00 100644
--- a/tests/unit/ci-workflow-generation.test.ts
+++ b/tests/unit/ci-workflow-generation.test.ts
@@ -200,8 +200,8 @@ describe("CI gate contract", () => {
// than taking either side's number.
// Task 11 added TECH_LOG_STUDIO_ASSETS's manual accessibility evidence.
// Alignment follow-up item 2 added the TechLog junit report.
- expect(contract.gates.reduce((total, gate) => total + gate.evidenceArtifactIds.length, 0)).toBe(109);
- expect(contract.artifacts).toHaveLength(130);
+ expect(contract.gates.reduce((total, gate) => total + gate.evidenceArtifactIds.length, 0)).toBe(110);
+ expect(contract.artifacts).toHaveLength(131);
expect(contract.stages).toHaveLength(5);
expect(contract.retention.classes).toHaveLength(5);
expect(index.gates.get("FE-GATE-015")?.commandIds).toHaveLength(2);
diff --git a/tests/unit/task3-selective-integration.test.ts b/tests/unit/task3-selective-integration.test.ts
index fb11579..14c5543 100644
--- a/tests/unit/task3-selective-integration.test.ts
+++ b/tests/unit/task3-selective-integration.test.ts
@@ -192,7 +192,7 @@ describe("selective Task 3 contract closure", () => {
expect(canonical.gates).toHaveLength(27);
expect(canonical.commands).toHaveLength(85);
expect(canonical.gates.reduce((sum, gate) => sum + gate.commandIds.length, 0)).toBe(97);
- expect(canonical.artifacts).toHaveLength(130);
+ expect(canonical.artifacts).toHaveLength(131);
expect(canonical.stages).toHaveLength(5);
expect(canonical.retention.classes).toHaveLength(5);
diff --git a/tests/unit/tech-log-serving-contract.test.ts b/tests/unit/tech-log-serving-contract.test.ts
index 70d7304..216de55 100644
--- a/tests/unit/tech-log-serving-contract.test.ts
+++ b/tests/unit/tech-log-serving-contract.test.ts
@@ -34,6 +34,7 @@ describe("TechLog production serving contract", () => {
expect(contract.studioSpaPathPatterns).toEqual([
"^/studio$",
"^/studio/assets$",
+ "^/studio/taxonomy$",
"^/studio/documents$",
"^/studio/documents/new$",
"^/studio/documents/[^/]+/(edit|validation|preview|publish)$",
diff --git a/vite.config.ts b/vite.config.ts
index 9486e38..1142a83 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -31,6 +31,7 @@ const techLogRouteChunks = Object.freeze({
"/studio/pages/publications-page.tsx": "route-tech-log-studio-publications",
"/studio/pages/publication-preview-page.tsx": "route-tech-log-studio-publication-preview",
"/studio/pages/assets-page.tsx": "route-tech-log-studio-assets",
+ "/studio/pages/taxonomy-page.tsx": "route-tech-log-studio-taxonomy",
"/studio/pages/studio-not-found-page.tsx": "route-tech-log-studio-not-found",
"/public/pages/public-not-found-page.tsx": "route-not-found",
} as const);