feat: M0 monorepo skeleton with services, clients, deploy and CI
ci / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 3m55s
ci / api (push) Successful in 51s
ci / mobile (Metro-бандл Android) (push) Canceled after 0s
release / images (services/api/Dockerfile, storage-agent, storage-agent) (push) Canceled after 0s
release / images (services/recommender/Dockerfile, recommender, ) (push) Canceled after 0s
ci / recommender (push) Successful in 1m11s
ci / ts (packages + web) (push) Canceled after 3s
release / verify (push) Successful in 1m16s
release / images (apps/web/Dockerfile, web, ) (push) Failing after 2m40s
release / android + release (push) Skipped
release / images (services/api/Dockerfile, api, api) (push) Canceled after 1s
ci / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 3m55s
ci / api (push) Successful in 51s
ci / mobile (Metro-бандл Android) (push) Canceled after 0s
release / images (services/api/Dockerfile, storage-agent, storage-agent) (push) Canceled after 0s
release / images (services/recommender/Dockerfile, recommender, ) (push) Canceled after 0s
ci / recommender (push) Successful in 1m11s
ci / ts (packages + web) (push) Canceled after 3s
release / verify (push) Successful in 1m16s
release / images (apps/web/Dockerfile, web, ) (push) Failing after 2m40s
release / android + release (push) Skipped
release / images (services/api/Dockerfile, api, api) (push) Canceled after 1s
- api/openapi.yaml: contract with /healthz, /readyz, /api/v1/server-info - services/api (Go): api with oapi-codegen strict server, goose migrations, readiness checks for Postgres/Redis; storage-agent stub with internal token - services/recommender (Python, uv): FastAPI health/readiness/internal status, `pipu-rec serve` and `pipu-rec analyze` entrypoints - packages: generated api-client, core (server URL + server check), i18n (ru/en + dictionary check), design-tokens (CSS vars + TS from tokens.json) - apps/web: Vite + React shell showing server status, language switch - apps/mobile: Expo (SDK 53) Android app with server connect screen - deploy: Dockerfiles, compose (prod + dev), nginx template, install/update scripts - .gitea/workflows: ci.yml and tag-based release.yml (images, signed APK, release) - scripts/version.mjs: version and Android versionCode from git tag - tests/fixtures/music/generate.sh: synthetic test library via ffmpeg - docs: versionCode formula, OpenAPI 3.0.3, dev instructions in README Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9eb1c25147
commit
ebf296542c
98 files changed
+12130
-4
No files matched your search
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@pipu/api-client",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": { ".": "./src/index.ts" },
|
||||
"scripts": {
|
||||
"generate": "openapi-typescript ../../api/openapi.yaml -o src/generated/schema.ts",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"openapi-fetch": "^0.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"openapi-typescript": "^7.8.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* This file was auto-generated by openapi-typescript.
|
||||
* Do not make direct changes to the file.
|
||||
*/
|
||||
|
||||
export interface paths {
|
||||
"/healthz": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Живость процесса */
|
||||
get: operations["getHealthz"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/readyz": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Готовность обслуживать запросы (зависимости доступны) */
|
||||
get: operations["getReadyz"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/server-info": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Сведения о сервере для клиентов
|
||||
* @description Вызывается без аутентификации: веб и Android проверяют версию сервера,
|
||||
* совместимость клиента и поддерживаемые языки (экран подключения).
|
||||
*/
|
||||
get: operations["getServerInfo"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
}
|
||||
export type webhooks = Record<string, never>;
|
||||
export interface components {
|
||||
schemas: {
|
||||
HealthStatus: {
|
||||
/** @enum {string} */
|
||||
status: "ok";
|
||||
};
|
||||
ReadyStatus: {
|
||||
/** @enum {string} */
|
||||
status: "ok" | "degraded";
|
||||
/** @description Результат проверки каждой зависимости */
|
||||
checks: {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
ServerInfo: {
|
||||
/** @example pipu-music */
|
||||
name: string;
|
||||
/**
|
||||
* @description Версия сервера (SemVer)
|
||||
* @example 0.1.0
|
||||
*/
|
||||
version: string;
|
||||
/** @example v1 */
|
||||
api_version: string;
|
||||
/**
|
||||
* @example [
|
||||
* "ru",
|
||||
* "en"
|
||||
* ]
|
||||
*/
|
||||
supported_locales: string[];
|
||||
/**
|
||||
* @description Минимальный versionCode Android-приложения, которое поддерживает сервер
|
||||
* @example 10099
|
||||
*/
|
||||
min_android_version_code: number;
|
||||
};
|
||||
Problem: {
|
||||
/** @default about:blank */
|
||||
type: string;
|
||||
status: number;
|
||||
/** @description Машинный код ошибки для i18n, например `auth.invalid_credentials` */
|
||||
code: string;
|
||||
/** @description Пояснение для логов (не для показа пользователю) */
|
||||
detail?: string;
|
||||
params?: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Ошибка (RFC 9457) */
|
||||
Problem: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/problem+json": components["schemas"]["Problem"];
|
||||
};
|
||||
};
|
||||
};
|
||||
parameters: never;
|
||||
requestBodies: never;
|
||||
headers: never;
|
||||
pathItems: never;
|
||||
}
|
||||
export type $defs = Record<string, never>;
|
||||
export interface operations {
|
||||
getHealthz: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Процесс жив */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HealthStatus"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
getReadyz: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Все зависимости доступны */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ReadyStatus"];
|
||||
};
|
||||
};
|
||||
/** @description Одна или несколько зависимостей недоступны */
|
||||
503: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ReadyStatus"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
getServerInfo: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Сведения о сервере */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ServerInfo"];
|
||||
};
|
||||
};
|
||||
default: components["responses"]["Problem"];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import createClient, { type Client } from 'openapi-fetch';
|
||||
|
||||
import type { components, paths } from './generated/schema';
|
||||
|
||||
export type { components, paths };
|
||||
export type ServerInfo = components['schemas']['ServerInfo'];
|
||||
export type Problem = components['schemas']['Problem'];
|
||||
export type ApiClient = Client<paths>;
|
||||
|
||||
export interface ApiClientOptions {
|
||||
/** Адрес сервера без завершающего слеша; пусто — тот же origin (веб). */
|
||||
baseUrl?: string;
|
||||
fetch?: typeof globalThis.fetch;
|
||||
}
|
||||
|
||||
/** Создаёт типизированный клиент публичного API (контракт — api/openapi.yaml). */
|
||||
export function createApiClient(opts: ApiClientOptions = {}): ApiClient {
|
||||
return createClient<paths>({ baseUrl: opts.baseUrl ?? '', fetch: opts.fetch });
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{ "extends": "../../tsconfig.base.json", "compilerOptions": { "lib": ["ES2022", "DOM"] }, "include": ["src"] }
|
||||
Reference in new issue
Block a user