v0.2.0 — English first, TypeScript throughout
English first and TypeScript throughout: the specs, docs and tools speak English, the admin frontend is TypeScript end to end, and the OpenAPI doc is kept in sync with the backend by a check instead of by hand.
Highlights
- English first.
AGENTS.md,CLAUDE.md,docs/, the skills, the MCP tool descriptions and every developer tool (pnpm verify,pnpm scaffold,pnpm openapi:generate, the setup wizard) are in English; the docs site defaults to English (Chinese at/zh/, Japanese at/ja/); English is the fallback UI / API language. - TypeScript frontend.
apps/web(source, tests and configs) is TypeScript with the same strict settings as the API, checked bypnpm typecheckand theverifygate;pnpm scaffoldgenerates typed TSX pages and TS API files. - API types from the OpenAPI doc. The frontend's API types are generated from
docs/apifox-full.openapi.json, and a newbody-syncrule keeps every documented request body in line with the backend's Zod declarations.
Added
routeBody(schema, 'create' | 'patch' | 'array')(@/common/validation): a route declares its JSON body once —.routegoes into the route options (Fastify routeconfig, so nothing runs before the login and permission checks),.parse(request)validates after the permission check. All 79 body-reading routes, the backend template andpnpm scaffolduse it;test/conventions.test.tsrejects a directparseBody/parsePatch/parseArrayBodyin aroutes.ts.body-syncOpenAPI rule (apps/api/scripts/lib/openapi-body-sync.ts): compares each documented JSON request body with the route's declaration — nullability, requiredness, types and enums per property, nested objects and array items included — wherever the doc rules run (pnpm openapi:generate --strict, verify'sopenapi_sync,test/openapi-doc.test.ts). Exportfields[]/file_typeenums are the contract by design; other intentional differences live inBODY_SYNC_ALLOWLISTwith a reason each, and a stale entry fails.- Generated frontend API types:
apps/web/src/shared/api/openapi.d.ts(byapps/web/scripts/api-types.mjs) withApiItem/ApiResponse/ApiQuery/ApiBodyhelpers in@/shared/api/types;pnpm openapi:generateregenerates it andtest/api-types.test.tsfails when it is stale. - Traffic flow in the component gallery (
/component-center/dataviz/traffic-flow, permissioncc_dataviz_traffic_flow): a Sankey diagram of visits (source → landing page → outcome) and a conversion funnel, replacing the map heatmap. Migration0001_traffic_flow_menurenames the existing menu in place, so role grants carry over. docs/shadcn-changes.md: every project change to an upstream shadcn / AI Elements component, to re-apply after re-adding one.- Component layer boundaries enforced by a test: shadcn primitives import only primitives; shared components get data through props instead of calling the API or reading app context.
Changed
- Frontend in TypeScript (plan and details in
docs/roadmap.md"TypeScript frontend"):apps/web/tsconfig.jsonis strict (same options as the API:noUncheckedIndexedAccess,verbatimModuleSyntax);srcis TypeScript only (test/typescript-only.test.ts), and tests and the Vite / Vitest configs are checked bytsconfig.test.json.pnpm lintlints the web app too.- Everything is typed: shadcn primitives (
components.jsontsx: true), shared components (DataTable<Row>with typed columns, FormFields / FormDialog over react-hook-form, generic trees and selects,Chartover echarts'EChartsOption), contexts (useAuth()/useTagsView()return non-null values), hooks (useCrudList<Row>), every module API file and every page. pnpm scaffoldwritesapi/<name>.tstyped from the module's OpenAPI entries and a list pageindex.tsxwithFormValuesandDataTableColumn<Row>[], so a form that doesn't match the documented body failstsc; it regeneratesopenapi.d.tsitself.docs/templates/frontend/is TSX.- Idiomatic cleanup: casts and non-null assertions replaced by narrowing, type guards and precise generics (the few left are commented); naming and export conventions documented in AGENTS.md "TypeScript".
- English first:
- Developer specs, skills and MCP tool descriptions in English; UI copy is still Chinese source text as the i18n key (
t('中文原文')) with English and Japanese translations. - English is the fallback: the UI uses it when neither a saved choice nor the browser language matches; the API answers in English when a request has no supported
Accept-Language(curl, API-token clients). Page title and<html lang>are English. - Tool output in English (
pnpm verify,pnpm scaffoldincl. spec validation anddocs/spec.schema.jsonhints,pnpm openapi:generate,pnpm seed:rbac, setup / seed scripts,scripts/setup.sh). Generated code keeps Chinese UI copy as the i18n key, and generated OpenAPI text stays Chinese. - Docs site: English at the root (
/guide/…), Chinese at/zh/, Japanese at/ja/; old/en/…links redirect.
- Developer specs, skills and MCP tool descriptions in English; UI copy is still Chinese source text as the i18n key (
- Repository root tidied: the Docker setup wizard is
bash scripts/setup.sh(entry pointscripts/docker-entrypoint.sh);README.zh-CN.md;.env.production.example;llms.txtserved at/llms.txt; one sharedAGENTS.md(+CLAUDE.md) instead of per-tool rule copies. - Faster first page opens: ECharts registered on demand (chart pages load about 40% less code); sign-in, reset-password and profile pages lazy-loaded (first download about a fifth smaller); page code prefetched on menu hover / focus and, for light pages, while the browser is idle (skipped in data-saver mode).
- Scaffolded modules document export
ids/fields/file_typeas nullable, and only required fields without a default are non-null and listed inrequired.
Fixed
- OpenAPI request side matches the backend: 332 differences between documented request bodies and the Zod
field.*declarations fixed (nullable fields with their defaults,''= "all" filters,export_mode: all, validated enums on announcements / menus, required webhook fields, descriptions that promised lenient parsing where the API returns 400). - Dashboard network tiles always showed 0.00 (they read fields the API doesn't return); they now show cumulative traffic since boot with a readable unit.
- Card list: a card with no
is_activevalue showed the switch off but was saved as enabled; edits sentid/ timestamps along with the form. - Heatmap dates were a day off before 08:00 in UTC+8; times on the dashboard, perf monitor and WebSocket pages ignored the UI language; the code editor reported success for languages it can't format; the AI SQL schema sheet showed "no tables" after a failed load; the prompt studio kept untrimmed values after saving; kanban sent
board_codeon update; untranslated list-page section titles and image-upload hint; Three.js pages didn't resize with their container; smaller fixes inDataTablekeys, zero page size, the particle canvas and the code highlighter. - Tags view: even spacing between tabs (the close button on inactive tabs no longer leaves an invisible gap).
Upgrading from 0.1.0
- Run
pnpm db:migrate(migration0001_traffic_flow_menu) andpnpm seed:rbac -- --incremental. - Frontend pages must be
index.tsx: page routing no longer findsindex.jsx, andapps/web/srcaccepts no.js/.jsxfiles. Convert custom pages and components to TypeScript (see AGENTS.md "TypeScript" anddocs/templates/frontend/). - Backend routes read JSON bodies through
routeBody(...)instead of callingparseBody/parsePatch/parseArrayBodydirectly (enforced bytest/conventions.test.ts), andpnpm openapi:generate -- --strictnow also checks request bodies against the Zod declarations. - API clients that send no
Accept-Languagenow get English messages; sendAccept-Language: zh-CNfor Chinese. - Docs site links: English pages moved from
/en/…to the root (old links redirect), Chinese pages from the root to/zh/…. - Moved at the repo root:
setup.sh→scripts/setup.sh,docker-entrypoint.sh→scripts/docker-entrypoint.sh,README_CN.md→README.zh-CN.md, the production env reference.env.example→.env.production.example(local development still usesapps/api/.env.example).