432 lines
11 KiB
Markdown
432 lines
11 KiB
Markdown
# Allapp Project Context
|
|
|
|
This file is a compact project memory for future Codex chats. Read it first when working in
|
|
`D:\workspace\code\app`.
|
|
|
|
## Workspace
|
|
|
|
- Root: `D:\workspace\code\app`
|
|
- Git repository root: `D:\workspace`
|
|
- Backend: `app-go`
|
|
- Frontend: `app-rn`
|
|
- Local database memo: `db.local.yml`
|
|
- Treat config files as sensitive. Some local config files may contain real credentials.
|
|
|
|
## Product Mental Model
|
|
|
|
Allapp is shaped more like a mini-program platform than a single linear mobile app.
|
|
|
|
There is a main shell for the family/personal space, and feature modules behave like small apps
|
|
inside it. The frontend owns most product flow and business behavior. The backend is deliberately
|
|
thin and generic, acting mostly as auth, file storage, ID generation, and database access.
|
|
|
|
High-level model:
|
|
|
|
```text
|
|
Allapp main shell
|
|
├── Home / Chat / Tools / My
|
|
├── Auth and family/space management
|
|
└── Sub-apps
|
|
├── Finance
|
|
│ ├── Home
|
|
│ ├── Add record
|
|
│ └── Analysis
|
|
└── Clothes matching
|
|
└── Planned/listed, route not implemented yet
|
|
```
|
|
|
|
Important naming note:
|
|
|
|
- The product often uses "family" and "space" as the same concept.
|
|
- Database tables use `b_family` and `b_family_member`.
|
|
- Main tab config currently includes `/space`, but there is no matching page yet.
|
|
|
|
## Backend: app-go
|
|
|
|
Tech stack:
|
|
|
|
- Go
|
|
- Fiber v3
|
|
- pgx PostgreSQL client
|
|
- JWT
|
|
- Viper config
|
|
- Zap logging
|
|
- S3/RustFS file storage
|
|
- QQ/WeChat login and binding
|
|
- Snowflake-style unique ID generator
|
|
|
|
Important files:
|
|
|
|
- Entry: `app-go/cmd/app/main.go`
|
|
- Bootstrap: `app-go/internal/bootstrap/app.go`
|
|
- Server: `app-go/internal/bootstrap/server.go`
|
|
- Routes: `app-go/internal/router/router.go`
|
|
- Config type: `app-go/internal/config/config.go`
|
|
- Request binding/validation: `app-go/internal/httpx/request.go`
|
|
- Response shape: `app-go/internal/httpx/response.go`
|
|
- Auth middleware: `app-go/internal/middleware/auth.go`
|
|
- Generic DB access: `app-go/pkg/db/*`
|
|
|
|
Bootstrap flow:
|
|
|
|
```text
|
|
config -> logger -> S3 client -> Postgres pool -> db.Init
|
|
-> unique ID -> JWT -> WeChat client -> Fiber server
|
|
```
|
|
|
|
API base path comes from config and is currently:
|
|
|
|
```text
|
|
/app
|
|
```
|
|
|
|
Important endpoints:
|
|
|
|
```text
|
|
POST /app/auth/login/qq
|
|
POST /app/auth/login/wechat
|
|
POST /app/bind/qq
|
|
POST /app/bind/wechat
|
|
|
|
POST /app/data/loadData
|
|
POST /app/data/loadDataBySql
|
|
POST /app/data/saveData
|
|
POST /app/data/getUniqueId
|
|
|
|
POST /app/s3/upload
|
|
POST /app/s3/delete
|
|
```
|
|
|
|
Backend architecture notes:
|
|
|
|
- `loadData` accepts a table/view name, selected columns, condition string, order string, and args.
|
|
- `loadDataBySql` accepts raw SQL and args.
|
|
- `saveData` accepts batches of inserts, updates, and deletes by table name/key field.
|
|
- Insert/update helpers add audit fields for most tables via `applyMetaFields`.
|
|
- `Token` header is parsed by `middleware.Auth()` and stores `user_id` in context.
|
|
- There are no explicit database foreign keys in the inspected schema; relationships are enforced by code and naming conventions.
|
|
|
|
Security/architecture caution:
|
|
|
|
- The generic data API is very flexible but risky.
|
|
- Table names, columns, conditions, ordering, and raw SQL can come from the frontend.
|
|
- If this moves toward production, prioritize server-side table/field whitelists, ownership checks, and removing or restricting raw SQL.
|
|
|
|
Validation notes:
|
|
|
|
- `BindAndValidate` validates structs with `go-playground/validator`.
|
|
- It skips validation for slices.
|
|
- `GetUniqueIdReq.Count` currently uses a `binding` tag, not a `validate` tag, so its min/max rules may not run.
|
|
|
|
## Frontend: app-rn
|
|
|
|
Tech stack:
|
|
|
|
- Expo 55
|
|
- React Native 0.83
|
|
- React 19
|
|
- Expo Router
|
|
- Zustand
|
|
- Alova with Axios adapter
|
|
- HeroUI Native
|
|
- Uniwind / Tailwind-style classes
|
|
- Lucide React Native icons
|
|
- QQ/WeChat native login plugins
|
|
|
|
Important files:
|
|
|
|
- Package: `app-rn/package.json`
|
|
- App config: `app-rn/app.json`
|
|
- Root layout: `app-rn/src/app/_layout.tsx`
|
|
- Startup redirect page: `app-rn/src/app/index.tsx`
|
|
- Request wrapper: `app-rn/src/request/index.ts`
|
|
- API methods: `app-rn/src/request/api.ts`
|
|
- User store: `app-rn/src/store/user.ts`
|
|
- Family store: `app-rn/src/store/family.ts`
|
|
- Finance store: `app-rn/src/store/finance.ts`
|
|
- Main shell layout: `app-rn/src/layouts/AppLayout.tsx`
|
|
- Module shell layout: `app-rn/src/layouts/ModuleLayout.tsx`
|
|
- Shared tabbar: `app-rn/src/components/layout/tabbar.tsx`
|
|
- App/module list config: `app-rn/src/configs/pages.ts`
|
|
|
|
Frontend/backend contract:
|
|
|
|
- Frontend reads `EXPO_PUBLIC_API_URL`.
|
|
- Requests use Alova with Axios adapter.
|
|
- Auth token is sent in a custom `Token` header.
|
|
- Login APIs are whitelisted in the request wrapper.
|
|
- Backend response shape:
|
|
|
|
```ts
|
|
{
|
|
code: number;
|
|
message: string;
|
|
data: unknown;
|
|
track_id?: string;
|
|
}
|
|
```
|
|
|
|
Response codes:
|
|
|
|
```text
|
|
1000 success
|
|
1001 unauthorized/token expired
|
|
2000 business error
|
|
3000 system error
|
|
```
|
|
|
|
State:
|
|
|
|
- `user-storage`: persisted user token/id/nickname/avatar.
|
|
- `family-storage`: persisted current family id.
|
|
- Finance categories are in memory only and loaded by the finance module layout.
|
|
|
|
Startup flow:
|
|
|
|
```text
|
|
/ index
|
|
├── no local token -> /auth/login
|
|
├── token exists but user check fails -> /auth/login
|
|
├── token exists but no family -> /family/entry
|
|
└── token exists and family exists -> /(tabs)/home
|
|
```
|
|
|
|
## Frontend Route Structure
|
|
|
|
Expo Router tree:
|
|
|
|
```text
|
|
src/app
|
|
├── _layout.tsx
|
|
├── index.tsx
|
|
├── +not-found.tsx
|
|
├── auth
|
|
│ └── login.tsx
|
|
├── (tabs)
|
|
│ ├── _layout.tsx
|
|
│ ├── home/index.tsx
|
|
│ ├── chat/index.tsx
|
|
│ ├── my/index.tsx
|
|
│ └── star/index.tsx
|
|
├── tools
|
|
│ └── index.tsx
|
|
├── family
|
|
│ ├── entry.tsx
|
|
│ ├── settings.tsx
|
|
│ ├── user.tsx
|
|
│ └── member/[id].tsx
|
|
└── finance
|
|
├── (tabs)
|
|
│ ├── _layout.tsx
|
|
│ ├── home/index.tsx
|
|
│ └── analysis/index.tsx
|
|
├── add/index.tsx
|
|
└── sub/index.tsx
|
|
```
|
|
|
|
Effective routes:
|
|
|
|
```text
|
|
/ startup redirect
|
|
/auth/login login
|
|
/home main home
|
|
/chat chat/image picker demo
|
|
/my profile tab
|
|
/star placeholder page, not currently in tab config
|
|
/tools app/module list
|
|
/family/entry create or join family
|
|
/family/settings family settings
|
|
/family/user user profile settings
|
|
/family/member/:id family member detail
|
|
/finance/home finance module home
|
|
/finance/add add finance record
|
|
/finance/analysis finance analysis
|
|
/finance/sub test page
|
|
```
|
|
|
|
Main tab config in `src/app/(tabs)/_layout.tsx`:
|
|
|
|
```text
|
|
/home 首页
|
|
/space 空间, but route currently missing
|
|
/tools center app-list button
|
|
/chat 聊天
|
|
/my 我的
|
|
```
|
|
|
|
Finance module tab config in `src/app/finance/(tabs)/_layout.tsx`:
|
|
|
|
```text
|
|
/finance/home 记账
|
|
/finance/add center add button
|
|
/finance/analysis 分析
|
|
```
|
|
|
|
Layout behavior:
|
|
|
|
- Root `_layout.tsx` renders a global Stack with no headers.
|
|
- `(tabs)/_layout.tsx` uses `AppLayout`, which renders `Slot`, top `Navbar`, and bottom `Tabbar`.
|
|
- `finance/(tabs)/_layout.tsx` uses `ModuleLayout`, a module-level shell with its own top bar and tabbar.
|
|
- `ModuleLayout` close action returns to `/(tabs)/home`.
|
|
|
|
Current route mismatches:
|
|
|
|
- Main tab points to `/space`, but no `/space` file exists.
|
|
- `src/app/(tabs)/star/index.tsx` exists but is not in the tab config.
|
|
- `/tools` is outside `(tabs)`, so it is not wrapped by `AppLayout`; decide whether this is intentional.
|
|
- `/finance/add` is outside `finance/(tabs)`, but the finance tabbar points to it. This can be intentional for a modal/subpage style add screen.
|
|
|
|
## Feature Status
|
|
|
|
Implemented or mostly implemented:
|
|
|
|
- QQ login
|
|
- WeChat login
|
|
- Auth persistence
|
|
- Auth-expired redirect
|
|
- Family creation
|
|
- Family joining by invite code
|
|
- Family settings
|
|
- User profile
|
|
- Avatar upload to S3/RustFS
|
|
- QQ/WeChat account binding
|
|
- App/module list page
|
|
|
|
Partially implemented:
|
|
|
|
- Finance module shell
|
|
- Finance category loading
|
|
- Finance add-record form UI
|
|
- Finance analysis placeholder/demo page
|
|
|
|
Not yet complete:
|
|
|
|
- Saving a finance record from `/finance/add`
|
|
- Finance record list on `/finance/home`
|
|
- Finance analysis real data
|
|
- Clothes matching app route
|
|
- `/space` main-tab page
|
|
|
|
## Database: allapp
|
|
|
|
Observed database:
|
|
|
|
- PostgreSQL version observed previously: 18.1
|
|
- Database: `allapp`
|
|
- Schema: `public`
|
|
- Explicit foreign keys: none observed
|
|
|
|
Tables:
|
|
|
|
```text
|
|
b_user
|
|
b_user_oauth
|
|
b_family
|
|
b_family_member
|
|
b_finance
|
|
b_finance_category
|
|
b_finance_category_default
|
|
```
|
|
|
|
Views:
|
|
|
|
```text
|
|
v_family_member
|
|
```
|
|
|
|
Main entities:
|
|
|
|
- `b_user`: user profile, nickname, avatar, last login time, name, phone, birth date.
|
|
- `b_user_oauth`: third-party login bindings; includes `user_id`, `type`, `openid`.
|
|
- `b_family`: family/space; includes `name`, `invite_code`, `owner_id`.
|
|
- `b_family_member`: family membership; includes `family_id`, `user_id`, `role`, `nickname`.
|
|
- `b_finance`: finance records; includes `category_id`, `family_id`, `amount`, `remark`, `record_time`.
|
|
- `b_finance_category_default`: default finance category template.
|
|
- `b_finance_category`: actual finance categories for a family.
|
|
- `v_family_member`: joins `b_family_member` with `b_user`.
|
|
|
|
Finance conventions:
|
|
|
|
```text
|
|
type = 0 expense
|
|
type = 1 income
|
|
```
|
|
|
|
Category icon names match frontend iconfont names, for example:
|
|
|
|
```text
|
|
finance_jiaotong
|
|
finance_canyin
|
|
finance_shicai
|
|
finance_gouwu
|
|
finance_gongzi
|
|
finance_jianzhi
|
|
finance_shouru
|
|
```
|
|
|
|
## Local Environment Notes
|
|
|
|
The Codex shell runs inside WSL2 Ubuntu.
|
|
|
|
WSL has `fnm` installed at:
|
|
|
|
```text
|
|
/home/oneao/.local/share/fnm/fnm
|
|
```
|
|
|
|
Known WSL Node setup:
|
|
|
|
```text
|
|
fnm 1.39.0
|
|
v22.22.3
|
|
v24.16.0 default
|
|
```
|
|
|
|
In non-interactive Codex commands, `~/.bashrc` may not initialize fnm automatically. If `node` is not
|
|
found, temporarily enable it with:
|
|
|
|
```bash
|
|
export PATH="$HOME/.local/share/fnm:$PATH"
|
|
eval "$(fnm env --shell bash)"
|
|
```
|
|
|
|
After fnm init, expected tools:
|
|
|
|
```text
|
|
node v24.16.0
|
|
pnpm 11.5.2
|
|
```
|
|
|
|
Windows-side `nvm` paths may appear in PATH:
|
|
|
|
```text
|
|
/mnt/d/devtool/nvm
|
|
/mnt/d/devtool/nodejs
|
|
```
|
|
|
|
Those are not the right runtime for WSL. Prefer WSL `fnm`.
|
|
|
|
## Known Type/Build Issues
|
|
|
|
Frontend:
|
|
|
|
- `pnpm exec tsc --noEmit` currently fails.
|
|
- `tsconfig.json` includes `**/*.ts` and `**/*.tsx`, pulling in `example`.
|
|
- `tsconfig.json` has a suspicious extra include entry: `src/app/auth/login_2`.
|
|
- Generated iconfont components have `react-native-svg` prop type incompatibilities.
|
|
- `src/app/finance/(tabs)/analysis/index.tsx` has `Surface variant="2"` type mismatch.
|
|
|
|
Backend:
|
|
|
|
- `go` was not available in the earlier command environment, so `go test ./...` could not be rerun there.
|
|
- Prior context noted a possible unique ID package compile issue around `fmt.Println(message)` vs `fmt.Println(message...)`.
|
|
|
|
## Important Current Risks
|
|
|
|
- Generic backend data APIs need server-side permissions before production use.
|
|
- Finance category loading currently queries all `b_finance_category` rows without filtering by current `family_id`.
|
|
- Frontend business logic often trusts local/user-provided family and user IDs.
|
|
- Main tab route `/space` is missing.
|
|
- Some pages are placeholders or demos.
|
|
|