This commit is contained in:
oneao committed 2026-06-25 16:47:54 +08:00
1 parent 513a991b57
commit 8f8e8d03c8
22 files changed
+2212 -213

No files matched your search

+141
View File
@@ -0,0 +1,141 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Allapp is a family/space mini-program platform — a main shell with sub-apps inside it. The frontend owns most business logic; the backend is deliberately thin and generic (auth, file storage, ID generation, database access).
- **Backend**: `app-go/` — Go 1.25, Fiber v3.1, pgx (PostgreSQL), JWT, Viper, Zap
- **Frontend**: `app-rn/` — React Native 0.85, Expo 56, Expo Router, Zustand, Alova, HeroUI Native, Uniwind (Tailwind CSS)
- **Database**: PostgreSQL 18.1, database `allapp`, schema `public`
Read `PROJECT_CONTEXT.md` for deeper context; this file focuses on what you need day-to-day.
## Commands
### Backend (`app-go/`)
```bash
cd app-go
go build ./cmd/app # Build
go run ./cmd/app # Run server
go test ./... # Run all tests
go mod tidy # Tidy dependencies
```
### Frontend (`app-rn/`)
```bash
cd app-rn
pnpm start # Expo dev server (port 8083)
pnpm android # Android build
pnpm ios # iOS build
pnpm lint # oxlint
pnpm exec tsc --noEmit # TypeScript type check
pnpm exec oxfmt # Format code
```
WSL-specific: if `node`/`pnpm` are not found, run:
```bash
export PATH="$HOME/.local/share/fnm:$PATH"
eval "$(fnm env --shell bash)"
```
## Architecture
### Bootstrap Flow
```
Backend: config → logger → S3 → Postgres → db.Init → unique ID → JWT → WeChat → Fiber server
Frontend: /index → token check → auth/login or family/entry or /home
```
### Backend Design
**All CRUD goes through 5 generic data APIs.** Never create dedicated REST endpoints for feature-specific operations:
| Endpoint | Purpose |
|---|---|
| `POST /app/data/loadData` | Query by table/view name, conditions, columns, order, args |
| `POST /app/data/loadDataPage` | Paginated query — same as loadData + `page`/`page_size`, returns `{rows, total, page, page_size}` |
| `POST /app/data/loadDataBySql` | Raw SQL query |
| `POST /app/data/saveData` | Batch insert/update/delete by table name and key field |
| `POST /app/data/getUniqueId` | Get snowflake IDs (1–100) |
Auth endpoints: `/app/auth/login/{qq,wechat,test}`, `/app/bind/{qq,wechat}`.
**File endpoints:**
| Endpoint | Purpose |
|---|---|
| `POST /app/s3/upload` | Upload files (multipart form, field name `files`), stored under `YYYY/MM/DD/{uuid}.ext`, returns `string[]` keys |
| `POST /app/s3/delete` | Delete files by keys, body `{keys: string[]}`, failure is logged but still returns success |
On the frontend: `s3UploadFileApi(files[])` wraps files into a `FormData` with key `"files"` and `multipart/form-data` content type.
Auth token is passed in a custom `Token` header. JWT middleware stores `user_id` in context. Audit fields (`create_time`, `update_time`, `create_by`, `update_by`) are auto-injected by `pkg/db/meta_field.go` for all tables except `b_user` and `b_user_oauth`.
### Frontend Design
Expo Router file-based routing under `src/app/`:
- `(main)/(tabs)/` — main shell tabs (home, chat, my)
- `(main)/auth/`, `(main)/family/`, `(main)/tools/`, `(main)/activities/`
- `finance/(tabs)/` — finance sub-app (independent from main)
- Layouts: `AppLayout` for main shell, `ModuleLayout` for sub-app shells, `PageLayout` for simple pages
State: Zustand with `persist` middleware for `user` and `family` (AsyncStorage). Finance store is in-memory only.
API layer: single Alova instance (`src/request/index.ts`), API wrappers in `src/request/api.ts`. Key wrappers: `loadDataApi`, `loadDataPageApi` (paginated, returns `PageData<T>` with `rows`/`total`/`page`/`page_size`), `loadDataBySqlApi`, `saveDataApi`, `getUniqueIdApi`. Response codes: 1000 (success), 1001 (unauthorized → redirect to login), 2000 (business error), 3000 (system error).
Startup flow in `src/app/index.tsx`:
```
no token → /auth/login
token invalid → /auth/login
no family → /family/entry
has family → /home
```
## Critical Conventions
### 1. No New Dedicated API Endpoints
Always reuse the 5 generic data APIs. If you think a new endpoint is needed, **ask the user first**. Even then, new endpoints must be generic helpers, not feature-specific.
### 2. Database Tables Must Include Audit Columns
All new business tables must include: `id BIGINT PRIMARY KEY` (snowflake), `create_time TIMESTAMPTZ`, `update_time TIMESTAMPTZ`, `create_by BIGINT`, `update_by BIGINT`. Do not add new tables to `auditExcludeTables` — only `b_user` and `b_user_oauth` are exempt.
### 3. Family/Space-Centric Data Model
All business data (finance, favorites, etc.) associates with `family_id`. Users link to families via `b_family_member`. Always filter queries by the current user's `family_id`.
### 4. Family Feed Recording
Certain actions must call `recordFeed()` from `@/helpers/feed`. Use `{nickname}` placeholder in content — do NOT hardcode nicknames. The `loadFeeds()` helper replaces it dynamically. Scenarios: creating/joining family (`join`), renaming (`rename`), recording bills (`bill`), favoriting apps (`fav`).
### 5. Frontend: Use Existing Libraries Only
Before writing any page/component, check `app-rn/package.json` for available dependencies. Use HeroUI Native for UI, `@legendapp/list` for long lists, `lucide-react-native` for icons, `sonner-native` for toasts. Use NativeWind `className` for styling, not inline `style={}`.
### 6. Finance Convention
`type = 0` means expense, `type = 1` means income. Category icon names match iconfont names (e.g., `finance_jiaotong`, `finance_canyin`).
## Key Files
| File | Role |
|---|---|
| `PROJECT_CONTEXT.md` | Full project documentation, risks, feature status |
| `app-go/internal/bootstrap/app.go` | Backend initialization flow |
| `app-go/internal/router/router.go` | Route definitions |
| `app-go/pkg/db/meta_field.go` | Audit field auto-injection |
| `app-rn/src/app/index.tsx` | Startup/auth routing logic |
| `app-rn/src/request/index.ts` | Alova instance, auth interceptor |
| `app-rn/src/request/api.ts` | API wrapper functions |
| `app-rn/src/store/` | Zustand stores (user, family, finance, app, favorite) |
| `app-rn/src/layouts/` | Shell layouts (AppLayout, ModuleLayout, PageLayout) |
| `app-rn/src/configs/pages.ts` | Sub-app definitions |
| `app-rn/src/helpers/feed.ts` | Family feed recording |
## Known Risks
- Generic data APIs accept table names and raw SQL from the frontend — needs server-side whitelisting before production.
- `db.local.yml` contains database credentials and should never be committed.
- Finance category queries currently don't filter by `family_id`.
- Main tab `/space` route is missing its page file.
- `GetUniqueIdReq.Count` uses `binding` tag instead of `validate` tag — min/max rules may not run.