13 KiB
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:
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_familyandb_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:
config -> logger -> S3 client -> Postgres pool -> db.Init
-> unique ID -> JWT -> WeChat client -> Fiber server
API base path comes from config and is currently:
/app
Important endpoints:
POST /app/auth/login/qq
POST /app/auth/login/wechat
POST /app/auth/login/test
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:
loadDataaccepts a table/view name, selected columns, condition string, order string, and args.loadDataBySqlaccepts raw SQL and args.saveDataaccepts batches of inserts, updates, and deletes by table name/key field.- Insert/update helpers add audit fields for most tables via
applyMetaFields. Tokenheader is parsed bymiddleware.Auth()and storesuser_idin 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:
BindAndValidatevalidates structs withgo-playground/validator.- It skips validation for slices.
GetUniqueIdReq.Countcurrently uses abindingtag, not avalidatetag, 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
Tokenheader. - Login APIs are whitelisted in the request wrapper.
- Backend response shape:
{
code: number;
message: string;
data: unknown;
track_id?: string;
}
Response codes:
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:
/ 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:
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:
/ 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:
/home 首页
/space 空间, but route currently missing
/tools center app-list button
/chat 聊天
/my 我的
Finance module tab config in src/app/finance/(tabs)/_layout.tsx:
/finance/home 记账
/finance/add center add button
/finance/analysis 分析
Layout behavior:
- Root
_layout.tsxrenders a global Stack with no headers. (tabs)/_layout.tsxusesAppLayout, which rendersSlot, topNavbar, and bottomTabbar.finance/(tabs)/_layout.tsxusesModuleLayout, a module-level shell with its own top bar and tabbar.ModuleLayoutclose action returns to/(tabs)/home.
Current route mismatches:
- Main tab points to
/space, but no/spacefile exists. src/app/(tabs)/star/index.tsxexists but is not in the tab config./toolsis outside(tabs), so it is not wrapped byAppLayout; decide whether this is intentional./finance/addis outsidefinance/(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
/spacemain-tab page
Database: allapp
Observed database:
- PostgreSQL version observed previously: 18.1
- Database:
allapp - Schema:
public - Explicit foreign keys: none observed
Tables:
b_user
b_user_oauth
b_family
b_family_member
b_finance
b_finance_category
b_finance_category_default
b_app_favorite
Views:
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; includesuser_id,type,openid.b_family: family/space; includesname,invite_code,owner_id.b_family_member: family membership; includesfamily_id,user_id,role,nickname.b_finance: finance records; includescategory_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: joinsb_family_memberwithb_user.
Finance conventions:
type = 0 expense
type = 1 income
Category icon names match frontend iconfont names, for example:
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:
/home/oneao/.local/share/fnm/fnm
Known WSL Node setup:
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:
export PATH="$HOME/.local/share/fnm:$PATH"
eval "$(fnm env --shell bash)"
After fnm init, expected tools:
node v24.16.0
pnpm 11.5.2
Windows-side nvm paths may appear in PATH:
/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 --noEmitcurrently fails.tsconfig.jsonincludes**/*.tsand**/*.tsx, pulling inexample.tsconfig.jsonhas a suspicious extra include entry:src/app/auth/login_2.- Generated iconfont components have
react-native-svgprop type incompatibilities. src/app/finance/(tabs)/analysis/index.tsxhasSurface variant="2"type mismatch.
Backend:
gowas not available in the earlier command environment, sogo test ./...could not be rerun there.- Prior context noted a possible unique ID package compile issue around
fmt.Println(message)vsfmt.Println(message...).
Important Current Risks
- Generic backend data APIs need server-side permissions before production use.
- Finance category loading currently queries all
b_finance_categoryrows without filtering by currentfamily_id. - Frontend business logic often trusts local/user-provided family and user IDs.
- Main tab route
/spaceis missing. - Some pages are placeholders or demos.
Development Conventions
These rules MUST be followed. They exist to keep the codebase consistent and avoid unnecessary duplication.
API — No New Dedicated Endpoints
The project already has a set of generic data APIs. Do NOT create dedicated REST endpoints for CRUD operations. Always use the existing generic APIs instead:
| Generic API | Usage |
|---|---|
POST /data/loadData |
Query with view_name (table/view), search_condition, order_by, search_columns, args |
POST /data/loadDataBySql |
Raw SQL query with sql and args |
POST /data/saveData |
Batch insert/update/delete by table_name and key_field |
POST /data/getUniqueId |
Get snowflake IDs, count param (1–100) |
If you genuinely believe a new endpoint is needed, ask the user first. Even then, new endpoints should be generic (e.g. a new generic helper), not dedicated to a single feature.
Database — Standard Audit Columns
All business tables MUST include these four standard columns:
create_time TIMESTAMPTZ -- auto-set by applyMetaFields on insert
update_time TIMESTAMPTZ -- auto-set by applyMetaFields on insert & update
create_by BIGINT -- auto-set by applyMetaFields on insert (from JWT user_id)
update_by BIGINT -- auto-set by applyMetaFields on update (from JWT user_id)
The applyMetaFields function in pkg/db/meta_field.go injects these automatically for all tables
except those in the auditExcludeTables list (b_user, b_user_oauth).
When creating a new table:
- Include all four columns
- Do NOT add the table to
auditExcludeTablesunless it is a system-level table (user/auth) - Primary key
idshould be a snowflake BIGINT, obtained viagetUniqueIdApion the frontend oruniqueid.NextId()on the backend
Frontend State — Reuse Existing Stores
Before creating a new Zustand store or API wrapper, check whether the data can be fetched via the
existing loadDataApi / saveDataApi from the @/request/api module. New API wrapper functions
should only wrap these generic endpoints — never introduce feature-specific RPC-style endpoints.