diff --git a/README.md b/README.md index 1fc1c35..774dcd4 100644 --- a/README.md +++ b/README.md @@ -1,207 +1,56 @@ -Welcome to your new TanStack Start app! +# gig-admin -# Getting Started +Standalone admin dashboard for the gig-platform backend (`/api/admin/v1/*`). -To run this application: +React 19 · TanStack Start (SPA mode) · TanStack Query/Table · shadcn/ui · Tailwind v4 · TypeScript. + +## Quick start ```bash +cp .env.example .env # VITE_API_BASE_URL → backend origin pnpm install -pnpm dev +pnpm dev # http://localhost:3000 ``` -# Building For Production - -To build this application for production: +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: ```bash -pnpm build +ddev exec php artisan tinker storage/app/e2e-admin-seed.php +# → admin@gig.local / Admin@12345 ``` -## Testing +## Scripts -This project uses [Vitest](https://vitest.dev/) for testing. You can run the tests with: +| 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/error tests) | +| `pnpm gen:api` | regenerate `src/api/types.gen.ts` from the backend's scribe-admin OpenAPI spec (`../gig-platform/public/api-docs/admin/openapi.yaml`; run `ddev exec php artisan scribe:generate --config scribe-admin` there first) | -```bash -pnpm test -``` +## Architecture notes -## Styling +- **Auth**: Bearer tokens in localStorage (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). +- **Lists**: `useListPage` + `` bind to the backend's + `pagination {current_page, page_size, …}` shape (`page`/`page_size` params). +- **Generated types** (`types.gen.ts`) are reference-only (`@ts-nocheck` — + scribe emits duplicate operationIds); hand-written shapes live in + `src/api/types.ts`. -This project uses [Tailwind CSS](https://tailwindcss.com/) for styling. +## Features (milestone 1) -### Removing Tailwind CSS +- 分类管理:分类树 CRUD、待审核队列(通过/驳回/合并到已有分类) +- 内容工作室:机器人作者(暂停/恢复)、系列、文章、子话题、分类简报、风格预设、 + Agent 接入令牌(签发一次性展示 / 吊销) +- 用户与系统:SID 保留规则、幸运号码、查询/分配;语言设置;推送设备;机器人会话令牌 -If you prefer not to use Tailwind CSS: - -1. Remove the demo pages in `src/routes/demo/` -2. Replace the Tailwind import in `src/styles.css` with your own styles -3. Remove `tailwindcss()` from the plugins array in `vite.config.ts` -4. Uninstall the packages: `pnpm add @tailwindcss/vite tailwindcss --dev` - - -## Deploy with Nitro - -This project uses Nitro as a generic server adapter, so it can run on any Node-compatible host. - -```bash -npm run build -node dist/server/index.mjs -``` - -The build output is a self-contained Node server. To deploy, push the `dist/` directory to your host (Render, Fly.io, your own VPS, etc.) and run the server command above. - -For host-specific presets (Vercel, Netlify, Cloudflare, AWS Lambda, etc.) and tuning, see https://v3.nitro.build/deploy. - - - -## Routing - -This project uses [TanStack Router](https://tanstack.com/router) with file-based routing. Routes are managed as files in `src/routes`. - -### Adding A Route - -To add a new route to your application just add a new file in the `./src/routes` directory. - -TanStack will automatically generate the content of the route file for you. - -Now that you have two routes you can use a `Link` component to navigate between them. - -### Adding Links - -To use SPA (Single Page Application) navigation you will need to import the `Link` component from `@tanstack/react-router`. - -```tsx -import { Link } from "@tanstack/react-router"; -``` - -Then anywhere in your JSX you can use it like so: - -```tsx -About -``` - -This will create a link that will navigate to the `/about` route. - -More information on the `Link` component can be found in the [Link documentation](https://tanstack.com/router/v1/docs/framework/react/api/router/linkComponent). - -### Using A Layout - -In the File Based Routing setup the layout is located in `src/routes/__root.tsx`. Anything you add to the root route will appear in all the routes. The route content will appear in the JSX where you render `{children}` in the `shellComponent`. - -Here is an example layout that includes a header: - -```tsx -import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router' - -export const Route = createRootRoute({ - head: () => ({ - meta: [ - { charSet: 'utf-8' }, - { name: 'viewport', content: 'width=device-width, initial-scale=1' }, - { title: 'My App' }, - ], - }), - shellComponent: ({ children }) => ( - - - - - -
- -
- {children} - - - - ), -}) -``` - -More information on layouts can be found in the [Layouts documentation](https://tanstack.com/router/latest/docs/framework/react/guide/routing-concepts#layouts). - -## Server Functions - -TanStack Start provides server functions that allow you to write server-side code that seamlessly integrates with your client components. - -```tsx -import { createServerFn } from '@tanstack/react-start' - -const getServerTime = createServerFn({ - method: 'GET', -}).handler(async () => { - return new Date().toISOString() -}) - -// Use in a component -function MyComponent() { - const [time, setTime] = useState('') - - useEffect(() => { - getServerTime().then(setTime) - }, []) - - return
Server time: {time}
-} -``` - -## API Routes - -You can create API routes by using the `server` property in your route definitions: - -```tsx -import { createFileRoute } from '@tanstack/react-router' -import { json } from '@tanstack/react-start' - -export const Route = createFileRoute('/api/hello')({ - server: { - handlers: { - GET: () => json({ message: 'Hello, World!' }), - }, - }, -}) -``` - -## Data Fetching - -There are multiple ways to fetch data in your application. You can use TanStack Query to fetch data from a server. But you can also use the `loader` functionality built into TanStack Router to load the data for a route before it's rendered. - -For example: - -```tsx -import { createFileRoute } from '@tanstack/react-router' - -export const Route = createFileRoute('/people')({ - loader: async () => { - const response = await fetch('https://swapi.dev/api/people') - return response.json() - }, - component: PeopleComponent, -}) - -function PeopleComponent() { - const data = Route.useLoaderData() - return ( -
    - {data.results.map((person) => ( -
  • {person.name}
  • - ))} -
- ) -} -``` - -Loaders simplify your data fetching logic dramatically. Check out more information in the [Loader documentation](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#loader-parameters). - -# Demo files - -Files prefixed with `demo` can be safely deleted. They are there to provide a starting point for you to play around with the features you've installed. - -# Learn More - -You can learn more about all of the offerings from TanStack in the [TanStack documentation](https://tanstack.com). - -For TanStack Start specific documentation, visit [TanStack Start](https://tanstack.com/start). +Next milestones: moderation reports (comment / file-x), dashboard stats +(needs backend endpoints).