Files
gig-admin/README.md
T
kongkxandClaude Opus 5 5b3f5f7197 docs: add CLAUDE.md, expand AGENTS.md, correct stale README
The repo had no agent-facing project guidance: AGENTS.md contained only the
generated TanStack Intent skill pointers, and README.md described a stack
this app does not use.

- CLAUDE.md (new): API client contract (envelope, ApiError, single-flight
  401 refresh, the FormData Content-Type trap), the PERM catalog mirroring
  the backend permission classes, the route + NAV_GROUPS + PERM triad that
  must be edited together to add a page, and the useListPage/DataTable
  pattern.
- AGENTS.md: gotchas above the generated block, which is left untouched —
  global query retry policy, can() vs useCan() reactivity, the gig-admin-auth
  persist key, and that jsdom is opted into per file via a
  `// @vitest-environment jsdom` pragma since there is no vitest config.
- README.md: @tanstack/react-start is not a dependency (this is a plain Vite
  SPA, no SSR); cf:deploy no longer copies a shell to index.html; the feature
  list was a milestone-1 snapshot that omitted five shipped nav groups and
  still called moderation reports a future milestone.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013MADG54Y51wZkU3ViRjeSi
2026-09-06 21:16:29 +08:00

5.9 KiB

gig-admin

Standalone admin dashboard for the gig-platform backend (/api/admin/v1/*).

React 19 · TanStack Router · TanStack Query/Table · shadcn/ui · Tailwind v4 · TypeScript · Vite.

It is a plain client-rendered SPA (index.htmlsrc/main.tsxRouterProvider). There is no SSR and no server functions — @tanstack/react-start is not used.

Working on this repo with an AI agent? CLAUDE.md has the architecture and conventions, AGENTS.md the gotchas.

Quick start

cp .env.example .env          # VITE_API_BASE_URL → backend origin
pnpm install
pnpm dev                      # http://localhost:3000

Log in with an admin-role account (Passport password grant against POST /api/admin/v1/auth/login/password). To seed a local admin, run in the backend repo:

ddev exec php artisan tinker storage/app/e2e-admin-seed.php
# → [email protected] / Admin@12345

An account that authenticates but holds no admin roles or permissions is treated as logged out — the app clears the session and returns you to the login screen.

Scripts

Command Purpose
pnpm dev dev server on :3000
pnpm build / pnpm preview production build / preview
pnpm typecheck tsc --noEmit
pnpm test vitest — API client (envelope / refresh / errors) and auth store
pnpm generate-routes tsr generate — rewrite src/routeTree.gen.ts (dev/build do this automatically)
pnpm gen:api regenerate src/api/types.gen.ts from the backend's private admin OpenAPI spec (../gig-platform/storage/app/api-docs/admin/openapi.yaml; run ddev artisan api-docs:generate there first)
pnpm cf:build / pnpm cf:deploy Cloudflare build / build + wrangler deploy

There is no ESLint config and no lint script: pnpm typecheck && pnpm test is the gate, and it is what CI runs. tsconfig.json is strict with noUnusedLocals/noUnusedParameters, so an unused import fails the typecheck.

Uploads

api.upload(path, formData) is the multipart path. rawRequest deliberately does not set Content-Type for a FormData body — the browser must set it itself so the multipart boundary is included; setting it by hand makes the server see an empty upload (a 422 rather than a 202). fetch reports no upload progress, so upload UIs stay indeterminate.

Deploy

The app is a client-rendered Vite SPA served as static assets by a Cloudflare Worker (wrangler.jsonc, not_found_handling: single-page-application). Cloudflare returns dist/index.html for every client route.

Manual deploy (needs wrangler login or CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID in your env):

pnpm cf:deploy    # vite build → wrangler deploy

CI/CD — every push & PR runs typecheck + test + build; pushes to main build and deploy to Cloudflare. Two mirrored pipelines are provided:

Platform Workflow
GitHub Actions .github/workflows/ci.yml
Gitea Actions .gitea/workflows/ci.yml

Configure these on the repo before the first deploy:

Type Name Value
Variable VITE_API_BASE_URL backend API origin baked into the build
Secret CLOUDFLARE_API_TOKEN token with "Edit Cloudflare Workers" scope
Secret CLOUDFLARE_ACCOUNT_ID Cloudflare account id
  • GitHub: Settings → Secrets and variables → Actions.
  • Gitea: Repo → Settings → Actions → Secrets / Variables. Actions must be enabled and an act_runner registered with the ubuntu-latest label (use an image such as catthehacker/ubuntu:act-22.04).

VITE_API_BASE_URL is read at build time, so pointing a deployment at a different backend means rebuilding, not changing a runtime setting.

Architecture notes

  • Auth: Bearer tokens in localStorage under gig-admin-auth (zustand persist). src/api/client.ts unwraps the {success, data, message} envelope, sends X-Language-Locale, and does a single-flight refresh-then-retry on 401 (POST /api/v1/auth/refresh-token, client_machine_name=admin-api-client).
  • Permissions: GET /auth/me returns meta.roles / meta.permissions; nav items and routes gate on them (super-admin passes everything). The key catalog lives in src/auth/permissions.ts and mirrors the backend's Modules/{Module}/app/Permissions/.
  • Lists: useListPage + <DataTable> bind to the backend's pagination {current_page, page_size, …} shape (page/page_size params).
  • Errors: handleApiError (src/lib/errors.ts) is the single mutation error path — 422 field errors land on the form, everything else becomes a toast.
  • Generated types (types.gen.ts) are reference-only (@ts-nocheck — scribe emits duplicate operationIds); hand-written shapes live in src/api/types.ts.
  • UI copy is hardcoded 简体中文. i18next and next-themes are installed but unused; theming is a dark class set by an inline script in index.html.

Features

Sidebar groups (each entry hidden unless the account holds its permission):

  • 分类管理 — 分类树 CRUD、待审核队列(通过/驳回/合并到已有分类)
  • 内容工作室 — 机器人作者、文章系列、文章、子话题、分类简报、风格预设、 Agent 接入令牌(签发一次性展示 / 吊销)
  • 专长交易 — 需求、派单、订单、服务商监控
  • Dimzou 内容 — 文档监控、发布监控、翻译
  • 简历导入 — 批量导入任务
  • 内容审核 — 被举报评论、被举报事件
  • 用户与系统 — 用户列表、角色管理、用户角色、SID 管理(保留规则、幸运号码、 查询/分配)、语言设置、推送设备、机器人会话令牌
  • 开发工具 — API 文档、数据库管理台

/ has no dashboard: it redirects to the first nav route the account can see, and renders a "未分配权限" card only when there is none. Dashboard stats are still pending backend endpoints.