К основному содержанию
скилл CX Codex

segment — скилл для Claude Code: сегменты бэкенда Vovk.ts

Делит бэкенд на сегменты Vovk.ts: отдельные префиксы API, свои настройки runtime и статические эндпоинты. Пригодится, когда бэкенд разрастается.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add finom/vovk --skill segment -a claude-code
Открыть на GitHub

Что делает segment

Сегмент в Vovk.ts — это кусок бэкенда со своим префиксом пути (/api, /api/admin, /api/foo/bar), набором контроллеров и файлом route.ts. Каждый сегмент собирается в отдельную serverless-функцию, поэтому runtime и maxDuration задаются для каждого свои. Скилл помогает выбрать форму сегмента — корневой, именованный или статический — и создать его через CLI.

Файл route.ts лежит в папке с optional catch-all: например, src/app/api/foo/[[...vovk]]/route.ts. Внутри экспортируются HTTP-обработчики из initSegment(), куда передают карту контроллеров и имя сегмента. Имя сегмента должно совпадать с путём папки: для foo/bar это segmentName: 'foo/bar'. Имя в CLI — это часть URL, а не JS-идентификатор: admin, user-portal, admin/settings. Если попросить MyAdmin, скилл переведёт в my-admin.

Глубже всего совпавший путь и выигрывает: запрос к /api/foo/bar/baz уйдёт в сегмент foo/bar, а не в корневой. Поэтому после добавления именованного сегмента старые пути под этим префиксом перестанут доходить до корня — это стоит проверить до деплоя. Статические сегменты пре-рендерятся в JSON на этапе сборки и работают с output: 'export', для которого нужен выключенный cacheComponents. Создавать сегмент лучше через npx vovk new segment, а не писать route.ts руками.

Какие задачи решает

  • вынести админский API в отдельный сегмент /api/admin
  • задать свой maxDuration для долгих запросов
  • пре-рендерить OpenAPI-спецификацию в JSON на сборке
  • создать корневой сегмент в новом проекте Vovk
  • разложить вложенные пути вида foo/bar по сегментам

Примеры запросов агенту

  • Раздели бэкенд: вынеси админские ручки в отдельный сегмент /api/admin
  • Сделай статический эндпоинт с OpenAPI-спецификацией, чтобы он пре-рендерился на сборке
  • Создай именованный сегмент user-portal с maxDuration 60

Как установить segment

1Через Skills CLI (Vercel)

npx skills add finom/vovk --skill segment -a claude-code

2Вручную: положить файлы

~/.claude/skills/segment/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/segment/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о segment

Как установить segment в Claude Code?

Выполните npx skills add finom/vovk --skill segment -a claude-code, после чего скилл окажется в ~/.claude/skills/segment/SKILL.md.

Что делает скилл segment?

Помогает нарезать бэкенд Vovk.ts на сегменты: подсказывает форму (корневой, именованный, статический), создаёт route.ts через CLI и следит за совпадением segmentName с путём папки.

Чем segment отличается от скиллов procedure и openapi?

segment отвечает только за создание сегментов и их настройки. Всё, что внутри контроллера, — к скиллу procedure; авторство OpenAPI сверх подключения openAPIObject — к openapi; мультитенантная маршрутизация — к multitenant.

Исходный текст

SKILL.md · MIT
---
name: segment
description: "Vovk.ts segments in depth (`base` already covers the one root segment and its `route.ts`) — the unit of backend slicing in a Vovk project. Use whenever the user talks about splitting a backend into parts, API paths, catch-all routes, `route.ts`, `initSegment`, per-segment runtime/maxDuration, static APIs (OpenAPI specs, historical datasets), static export (`output: 'export'`), `generateStaticParams`, or the `vovk new segment` CLI. Triggers on phrasings like \"split my backend\", \"add an API slice\", \"make a static OpenAPI endpoint\", \"separate admin API\", \"pre-render API at build time\", \"I need a `/api/foo` namespace\", \"add a root/named/static segment\". Does NOT cover procedures/handlers themselves — hand off to the `procedure` skill for anything inside a controller. Does NOT cover OpenAPI authoring beyond wiring per-segment `openAPIObject` — hand off to the `openapi` skill. Does NOT cover multi-tenant routing mechanics (subdomains, `multitenant()` proxy, per-tenant frontend pages) — hand off to the `multitenant` skill."
---

# Vovk.ts segments

A segment is a **backend slice**. Owns API path prefix (`/api`, `/api/admin`, `/api/openapi`, etc.), set of controllers, own Next.js route-handler file. Each segment compiles to independent serverless function, so runtime settings (`runtime`, `maxDuration`, etc.) can differ per segment.

Think: "one segment = one mini-backend."

## Core concepts

### The catch-all file

Every segment is Next.js App Router **optional catch-all** route handler:

```
src/app/api/[[...vovk]]/route.ts              ← root segment (path: /api/*)
src/app/api/foo/[[...vovk]]/route.ts          ← "foo" segment (path: /api/foo/*)
src/app/api/foo/bar/[[...vovk]]/route.ts      ← "foo/bar" segment (path: /api/foo/bar/*)
```

Slug name (`vovk`) can be any name: the CLI takes any `[[...name]]` folder that has a `route.ts`. Stick with `vovk` (what `vovk new segment` writes) unless user has reason to change it. `rootEntry` is something else: the API root folder (`api`).

### `initSegment()`

Every segment's `route.ts` exports HTTP handlers produced by `initSegment()`:

```ts
// src/app/api/[[...vovk]]/route.ts
import { initSegment } from 'vovk';
import UserController from '../../../modules/user/user-controller';
import PostController from '../../../modules/post/post-controller';

export const maxDuration = 300; // Next.js route-handler option

const controllers = {
  UserRPC: UserController,
  PostRPC: PostController,
};

export type Controllers = typeof controllers;

export const { GET, POST, PATCH, PUT, HEAD, OPTIONS, DELETE } = initSegment({
  controllers,
});
```

**Keys** of `controllers` (`UserRPC`, `PostRPC`) are client-side module names — generated client will expose `UserRPC.getUser(...)`, etc.

`initSegment` parameters:

| Param | Required | Default | Purpose |
|---|---|---|---|
| `controllers` | yes | — | Map of `RPCModuleName → ControllerClass`. |
| `segmentName` | no | `""` (root) | Identifier; must mirror folder path for named segments (e.g., `"foo/bar"`). |
| `emitSchema` | no | `true` | Emit schema for codegen. Leave on unless you know why. |
| `exposeValidation` | no | `true` | Expose validation data to client. Leave on for client-side validation. |
| `onError` | no | — | `(err: Error, req: VovkRequest) => void \| Promise<void>` — for logging/metrics; it can't change the response (a custom error format → **`base`**). `err` is whatever the handler threw (often `HttpException`). |
| `onSuccess` | no | — | `(resp: unknown, req: VovkRequest) => void \| Promise<void>` — fires after successful response. Use for metrics, audit logs. |
| `onBefore` | no | — | `(req: VovkRequest) => void \| Promise<void>` — fires before handler runs. Use for tracing, request enrichment. |

### Segment priority

Deepest matching path wins. Given `/`, `/foo`, `/foo/bar`:

- `GET /api/foo/bar/baz` → handled by `foo/bar` segment.
- `GET /api/foo/qux` → `foo` segment.
- `GET /api/something` → root segment.

When adding new named segment, any existing root-handled paths under that prefix will stop reaching root. Flag this to user.

## Picking a segment shape

| Shape | When | Path |
|---|---|---|
| **Root** | Default. Most projects have exactly one. | `src/app/api/[[...vovk]]/route.ts` |
| **Named** | Isolate slice with different route options (`maxDuration`), or for multi-tenancy. | `src/app/api/<name>/[[...vovk]]/route.ts` |
| **Static** | API that can be pre-rendered at build time — OpenAPI specs, enumerated datasets, infrequently changing reference data. Works with Next `output: 'export'`, which needs `cacheComponents` off. | `src/app/api/<name>/[[...vovk]]/route.ts` + `generateStaticParams` |

**When user says...**

- "split my backend", "add an admin API", "separate `/api/admin`" → **named segment**.
- "pre-render OpenAPI", "static API docs", "build-time JSON endpoint" → **static segment**.
- "new Vovk project, first route" → **root segment**.
- "different Node runtime for X" or "longer timeout for X" → **named segment** + `export const maxDuration` / `export const runtime` in its `route.ts`.
- "multi-tenant", "multitenancy", "per-tenant API", "host per subdomain", "`admin.example.com` and `customer.example.com`" → **hand off to the `multitenant` skill**. (Segments are one part of that setup; this skill only covers creating them.)

## Creating a segment (CLI)

Always use the CLI — writes `route.ts` with right `initSegment()` wiring, easy to miscopy by hand.

```bash
# Root
npx vovk new segment

# Named
npx vovk new segment <name>

# Static named
npx vovk new segment <name> --static
```

**`<name>` is URL path segment**, not JS identifier — lowercase or kebab-case for multi-word (`admin`, `user-portal`), slash-separated for nested paths (`foo/bar`, `admin/settings`). **Not camelCase.** If user asks for segment like `MyAdmin` or `user_portal`, convert to URL-safe form (`my-admin`, `user-portal`) before calling CLI — name becomes part of URL (`/api/my-admin/...`) and `segmentName` inside `initSegment({ segmentName: '...' })`. Opposite rule from `vovk new controller service` (module names there are camelCase — see `procedure` skill).

After CLI runs, verify expected `route.ts` landed at expected path. If it didn't, surface CLI output — don't hand-write it.

## Named segment example

```ts
// src/app/api/admin/[[...vovk]]/route.ts
import { initSegment } from 'vovk';
import AdminController from '../../../../modules/admin/admin-controller';

export const runtime = 'nodejs';
export const maxDuration = 60;

const controllers = { AdminRPC: AdminController };
export type Controllers = typeof controllers;

export const { GET, POST, PATCH, PUT, HEAD, OPTIONS, DELETE } = initSegment({
  segmentName: 'admin',
  controllers,
});
```

`segmentName` MUST match folder path. For `src/app/api/foo/bar/[[...vovk]]/route.ts`, `segmentName: 'foo/bar'`.

## Static segments

Pre-renders endpoints to JSON files at build time. Useful for APIs that don't need per-request dynamism.

### 1. `route.ts` with `generateStaticParams`

```ts
// src/app/api/openapi/[[...vovk]]/route.ts
import { initSegment, controllersToStaticParams } from 'vovk';
import HelloController from '../../../../modules/hello/hello-controller';

const controllers = { HelloRPC: HelloController };
export type Controllers = typeof controllers;

export function generateStaticParams() {
  return controllersToStaticParams(controllers);
}

export const { GET } = initSegment({
  segmentName: 'openapi',
  controllers,
});
```

If you've customized slug (not `vovk`), pass it: `controllersToStaticParams(controllers, 'custom')`.

No `dynamic` export: the segment pre-renders with `cacheComponents` on or off, and with it on (create-next-app 16.4+ sets it) Next.js refuses `dynamic = 'force-static'`. `output: 'export'` needs `cacheComponents: false` in next.config.

### 2. Endpoints must be enumerable

Every endpoint in static segment must resolve to finite set of URLs at build time.

**Zero-param endpoint** — give it `.json` suffix so static hosting serves with right content type:

```ts
@prefix('hello')
export default class HelloController {
  @get('greeting.json')
  static async getHello() {
    return { greeting: 'Hello world!' };
  }
}
```

**Parameterized endpoint** — enumerate via `staticParams` on decorator:

```ts
import { z } from 'zod';
import { procedure, get, prefix, operation } from 'vovk';

@prefix('static-params')
export default class StaticParamsController {
  @operation({ summary: 'Static params' })
  @get('{section}/page{page}.json', {
    staticParams: [
      { section: 'a', page: '1' },
      { section: 'a', page: '2' },
      { section: 'b', page: '1' },
      { section: 'b', page: '2' },
    ],
  })
  static getStaticParams = procedure({
    params: z.object({
      section: z.enum(['a', 'b']),
      page: z.enum(['1', '2']),
    }),
  }).handle(async (_req, { section, page }) => {
    return { section, page };
  });
}
```

Pre-renders four JSON files at build time.

### 3. Static export (optional)

If whole Next.js app is exported statically (`next.config.js` → `output: 'export'`), static segments work as-is. Generated RPC client still calls them normal way:

```ts
const resp = await StaticParamsRPC.getStaticParams({
  params: { section: 'a', page: '1' },
});
```

### Rules for static segments

- No per-request state. Every response baked at build time.
- Use `.json` suffixes on endpoint paths for correct `Content-Type` when hosted statically.
- Keep static segments dedicated to static endpoints. Mixing dynamic handlers in static segment defeats pre-render.

## Multi-tenant routing

One named segment per tenant plus a `proxy.ts` with `multitenant()` serves `admin.example.com`, `customer.example.com`, … from one app. This skill creates the segments; everything else → **`multitenant` skill**.

## Per-segment configuration

Configure individual segments in `vovk.config.mjs`:

```ts
/** @type {import('vovk').VovkConfig} */
const config = {
  outputConfig: {
    segments: {
      admin: {
        openAPIObject: {
          info: {
            title: 'Admin API',
            description: 'Internal admin endpoints.',
            version: '1.0.0',
          },
        },
      },
    },
  },
};

export default config;
```

Segment-specific overrides supported: `openAPIObject`, `imports`, other output settings. Segment name key (`admin`) matches `segmentName` in `initSegment()`. Root segment uses key `""`.

## Schema output

Each segment writes one file: `.vovk-schema/root.json` for the root segment, `.vovk-schema/<segmentName>.json` for the others, plus `_meta.json`. Commit `.vovk-schema/`.

## Common flows

### "Add an admin API with a longer timeout"

1. `npx vovk new segment admin`.
2. In generated `src/app/api/admin/[[...vovk]]/route.ts`, add `export const maxDuration = 300;` (or whatever).
3. Controllers go into `src/modules/admin/*` — creating them is `procedure` skill's job. Hand off.

### "Pre-render my OpenAPI spec at build time"

1. `npx vovk new segment openapi --static`.
2. Create controller in `src/modules/openapi/` with `.json`-suffixed endpoint (see static example above). Hand off to `procedure` for controller body.
3. OpenAPI payload itself comes from `openapi` skill.

### "Split `/api/public` and `/api/internal`"

Two named segments (`public`, `internal`). Flag segment priority: any pre-existing root-handled paths under those prefixes will shift.

### "Host `admin.example.com` and `customer.example.com` from one app"

Multi-tenant flow. Hand off to **`multitenant` skill**. Segment side is `npx vovk new segment admin` + `npx vovk new segment customer`; everything else (proxy, `vovk.config.mjs` changes, frontend pages, DNS) belongs to that skill.

### "Change the API root from `/api` to `/rpc`"

1. Move `src/app/api/` to `src/app/rpc/`.
2. Set `rootEntry: 'rpc'` in `vovk.config.mjs`. The CLI looks for segments under `src/app/<rootEntry>`: without it, `vovk generate` leaves them out of the client and `vovk dev` deletes their schema files.
3. Run `vovk dev` once: it rewrites `.vovk-schema/_meta.json`, which the client reads `rootEntry` from. Commit `.vovk-schema/`.

## Gotchas

- **`segmentName` mismatch**: must mirror folder path. `src/app/api/foo/bar/[[...vovk]]/route.ts` → `segmentName: 'foo/bar'`. Mismatch breaks codegen silently.
- **Don't hand-write `route.ts`**: use the CLI. `initSegment` shape and `controllers` object wiring are easy to miscopy.
- **Static segment + dynamic handler**: handler runs at build, not request time. If you need per-request logic, use regular named segment.
- **`controllers` keys vs. controller names**: key (`UserRPC`) is client-side module name, not controller class name. Mismatches here are most common "why doesn't my RPC call work" bug.
- **Removing a segment**: deleting `route.ts` is not enough — also remove folder and any `.vovk-schema/<name>.json` file, then run `vovk generate` to refresh client.

© finom · MIT · finom/vovk

Похожие скиллы

Все скиллы по теме «Бэкенд и API» →
mcp-builder официальный anthropics Скилл проводит через создание MCP-сервера на TypeScript или Python: от изучения протокола до тестов и оценки качества. 130 949установок claude-api официальный anthropics Справочник по Anthropic SDK и API Claude для генерации кода без устаревших параметров и выдуманных методов. 74 198установок lark-im larksuite Скилл подключает Lark IM к агенту: он отправляет сообщения, ищет историю, управляет чатами и файлами. Подойдёт для задач вокруг командных коммуникаций. CX Codex +1 472 900установок lark-event larksuite Слушает события Lark/Feishu и отдаёт их потоком NDJSON. Подходит для ботов, обработчиков сообщений и долгих подписчиков. CX Codex +1 466 800установок caveman-discover JuliusBrussee Находит точки вызова LLM в репозитории и размечает их воркфлоу для Caveman Cloud, чтобы расходы на токены не сливались в одну общую кучу. CX Codex +1 104 400установок migration JuliusBrussee Скилл задаёт правила безопасных миграций схем, данных и API с обязательным откатом. Пригодится при изменениях, где нельзя терять данные или ломать совместимость. CX Codex +1 103 900установок

Из того же набора5

Спонсоры проекта

Компании, которые помогают держать аналитику открытой