docs: project README (setup, scripts, architecture)
This commit is contained in:
229
README.md
229
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` + `<DataTable>` 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
|
||||
<Link to="/about">About</Link>
|
||||
```
|
||||
|
||||
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 }) => (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<HeadContent />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav>
|
||||
<Link to="/">Home</Link>
|
||||
<Link to="/about">About</Link>
|
||||
</nav>
|
||||
</header>
|
||||
{children}
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
),
|
||||
})
|
||||
```
|
||||
|
||||
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 <div>Server time: {time}</div>
|
||||
}
|
||||
```
|
||||
|
||||
## 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 (
|
||||
<ul>
|
||||
{data.results.map((person) => (
|
||||
<li key={person.name}>{person.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
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).
|
||||
|
||||
Reference in New Issue
Block a user