Task 115 — Web-UI: openapi-typescript + Orval setup
Phase: 8
Status: superseded (deprecated target — src/hercules-web, ADR-0009)
Owner: —
Slug: webui-openapi-codegen-setup
Studio Stage: N/A (hercules-web, не Studio)
Status note (2026-10-07, 2.0.0 release prep). Not outstanding work — do not start. This task targets
src/hercules-web(Astro), which ADR-0009 deprecated and which is not ported; its panels were superseded by Hercules Studio. Generating a client for an application that is intentionally frozen would be wasted effort, and the equivalent Studio-side pipeline already ships under task_113 /task_114.md. Panel-by-panel replacement map:src/hercules-web/DEPRECATED.md. Kept on disk (not deleted) so the superseded scope is recorded rather than rediscovered later.
Goal
Настроить тот же pipeline генерации TypeScript API клиента в hercules-web (Astro) из OpenAPI документа агента. Использовать openapi-typescript (types) + Orval (Vue Query hooks для Astro islands + Zod + MSW mocks). Generated files коммитятся в git. Regen — ручной.
Acceptance criteria
openapi-typescriptустановлен как devDependency вhercules-webopenapi-fetchустановлен как dependencyorvalустановлен как devDependency@tanstack/vue-queryустановлен как dependency (для Astro Vue islands)zodустановлен как dependencymswустановлен как devDependencyscripts/gen-api.mjs— скрипт gen:api:types + gen:api:orvalpackage.jsonscripts:gen:api,gen:api:types,gen:api:orvalorval.config.ts— config: tags-split, vue-query, zod, mock, mutator (Astro env vars)src/api/mutator.ts— fetch wrapper с PUBLIC_API_BASE + PUBLIC_API_KEY (Astro env)src/api/schema.ts— generated typessrc/api/generated/— generated Vue Query hooks per domainsrc/api/models/— generated Zod schemas + DTO interfacessrc/api/README.md— “Generated. Do not edit. Run: npm run gen:api”.gitignore— НЕ игнорироватьsrc/api/npm run gen:apiработаетnpm run build(astro build) проходит с generated files
orval.config.ts (hercules-web)
import { defineConfig } from "orval";
export default defineConfig({
hercules: {
// Source: build-time generated openapi.json (committed to git by task_109)
// Alternative for dev: http://localhost:8421/openapi/v1.json (running agent)
input: { target: "../../agent/Hercules.WebApi/openapi.json" },
output: {
mode: "tags-split",
target: "src/api/generated",
schemas: "src/api/models",
client: "vue-query",
mock: true,
zod: true,
},
hooks: {
mutator: "src/api/mutator.ts",
},
},
});
mutator.ts (hercules-web — Astro env vars)
const API_BASE = import.meta.env.PUBLIC_API_BASE || "http://localhost:8421";
const API_KEY = import.meta.env.PUBLIC_API_KEY || "dev-local-key";
export const customMutator = async (config) => {
const res = await fetch(`${API_BASE}${config.url}`, {
method: config.method,
headers: { "X-Api-Key": API_KEY, "Content-Type": "application/json", ...config.headers },
body: config.body ? JSON.stringify(config.body) : undefined,
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return { data: await res.json(), status: res.status };
};
Astro Vue islands integration
Astro islands с client:load / client:visible поддерживают Vue Query:
---
import SkillsList from '../components/SkillsList.vue';
---
<SkillsList client:load />
<!-- SkillsList.vue -->
<script setup lang="ts">
import { useListSkillsQuery } from "../api/generated/skills/skills";
const { data: skills, isLoading } = useListSkillsQuery();
</script>
Dependencies (backend)
- task_109 (AddOpenApi)
- task_110 (WithTags)
- task_111 (Produces
+ DTOs) - task_112 (WithName)
Scope / Likely files
- New:
src/hercules-web/scripts/gen-api.mjs - New:
src/hercules-web/orval.config.ts - New:
src/hercules-web/src/api/(generated + mutator) - Modified:
src/hercules-web/package.json(scripts + deps)
Links
- Backlog: ../backlog.md
- task_113: task_113.md (Studio — тот же pipeline)