@posx/core 5.5.576 → 5.5.577
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +23 -23
- package/LICENSE +21 -21
- package/README.md +85 -85
- package/build/index.d.ts +15 -6
- package/build/index.js +4 -4
- package/dev/.stfolder/syncthing-folder-9a95b7.txt +5 -0
- package/dev/98894488.xlsx +0 -0
- package/dev/HappyThaiSembawang.csv +336 -0
- package/dev/KB/create-new-model.md +34 -0
- package/dev/KB/markdown-lint.md +14 -0
- package/dev/KB/object-clone-pitfalls.md +52 -0
- package/dev/KB/readmefirst.md +8 -0
- package/dev/KB/stock-deduction-logic.md +61 -0
- package/dev/Merchants/HappyThaiSembawang.csv +400 -0
- package/dev/Merchants/HappyThaiSembawang.xlsx +0 -0
- package/dev/Merchants/charen_thai/category.csv +20 -0
- package/dev/Merchants/charen_thai/charen_thai_xpos.csv +1021 -0
- package/dev/Merchants/charen_thai/convert.cjs +194 -0
- package/dev/Merchants/charen_thai/item.csv +183 -0
- package/dev/Merchants/charen_thai/modifier.csv +664 -0
- package/dev/Product_Import_Template.xlsx +0 -0
- package/dev/XPOS Invoice Module.pdf +232 -0
- package/dev/convert_menu.cjs +134 -0
- package/dev/convert_menu.py +127 -0
- package/dev/data/invoice.json +1 -0
- package/dev/escpos/receipt.bin +0 -0
- package/dev/escpos/receipt.hex +1 -0
- package/dev/escpos/receipt.json +1 -0
- package/dev/escpos-cli-usage.md +103 -0
- package/dev/export/xpos_menu.csv +1021 -0
- package/dev/export/xpos_menu_bilingual.csv +1021 -0
- package/dev/harbor-harness-deployment.md +78 -0
- package/dev/incidents/2026-04-01-reprint-timeout.md +33 -0
- package/dev/incidents/2026-05-06-searchable-field-design-pitfall.md +37 -0
- package/dev/nginx-harbor-harness.conf +84 -0
- package/dev/px-cli.md +97 -0
- package/dev/test-logs/2026-02.md +5 -0
- package/dev/tmp/xpos_product_import(1).csv +338 -0
- package/dev/tmp/xpos_product_import_fixed.csv +338 -0
- package/dev//344/272/247/345/223/201/345/257/274/345/205/245/346/250/241/346/235/277.xlsx +0 -0
- package/jest.config.cjs +36 -36
- package/jest.setup.cjs +91 -91
- package/package.json +1 -1
- package/package.publish.json +121 -121
- package/tsdown.config.ts +21 -21
- package/vite.config.ts +86 -86
- package/AGENTS.md +0 -24
- package/memo/technical-docs/01_ARCHITECTURE.md +0 -147
- package/memo/technical-docs/02_CORE_BUSINESS.md +0 -292
- package/memo/technical-docs/03_UI_COMPONENTS.md +0 -59
- package/memo/technical-docs/04_VIEWS.md +0 -82
- package/memo/technical-docs/05_DATA_LAYER.md +0 -375
- package/memo/technical-docs/06_CROSS_PLATFORM.md +0 -246
- package/memo/technical-docs/07_SIMILARITY_INDEX.md +0 -195
- package/memo/technical-docs/CHECKPOINT.md +0 -46
- package/memo/technical-docs/PROJECT_OVERVIEW.md +0 -122
- package/memo/technical-docs/TECHNICAL_DOCS_PLAN.md +0 -77
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Harbor + Harness 部署总结
|
|
2
|
+
|
|
3
|
+
## 服务端口
|
|
4
|
+
|
|
5
|
+
| 服务 | 端口 | 说明 |
|
|
6
|
+
|-------------|------|----------------|
|
|
7
|
+
| Harbor | 8081 | 容器镜像仓库 |
|
|
8
|
+
| Harness | 8082 | Git 代码托管 |
|
|
9
|
+
| Harness SSH | 3022 | Git SSH |
|
|
10
|
+
| PostgreSQL | 5433 | 数据库 |
|
|
11
|
+
| Redis | 6380 | 缓存 |
|
|
12
|
+
|
|
13
|
+
## 外部访问
|
|
14
|
+
|
|
15
|
+
| 服务 | 外部地址 | 内部地址 |
|
|
16
|
+
|---------|-------------------------|--------------|
|
|
17
|
+
| Harbor | https://harbor.wyo.sg | LAN_IP:8081 |
|
|
18
|
+
| Harness | https://harness.wyo.sg | LAN_IP:8082 |
|
|
19
|
+
|
|
20
|
+
## Harbor 登录
|
|
21
|
+
|
|
22
|
+
- URL: https://harbor.wyo.sg
|
|
23
|
+
- 用户名: `admin`
|
|
24
|
+
- 密码: `Harbor@2024!`
|
|
25
|
+
|
|
26
|
+
## Harness 登录
|
|
27
|
+
|
|
28
|
+
- URL: https://harness.wyo.sg
|
|
29
|
+
- 用户名: `admin@harness.local`
|
|
30
|
+
- 密码: `Harness@2024!`
|
|
31
|
+
|
|
32
|
+
## PostgreSQL
|
|
33
|
+
|
|
34
|
+
Host: `127.0.0.1:5433`
|
|
35
|
+
|
|
36
|
+
| 数据库 | 用户名 | 密码 |
|
|
37
|
+
|----------|----------|----------------|
|
|
38
|
+
| postgres | postgres | Postgres@2024! |
|
|
39
|
+
| harbor | harbor | Harbor@2024! |
|
|
40
|
+
| harness | harness | Harness@2024! |
|
|
41
|
+
|
|
42
|
+
## Redis
|
|
43
|
+
|
|
44
|
+
- Host: `127.0.0.1:6380`
|
|
45
|
+
- 密码: (无)
|
|
46
|
+
- Harbor DB Index: 1, 2, 5, 6, 7
|
|
47
|
+
|
|
48
|
+
## 文件位置
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
/opt/infra/docker-compose.yml # PostgreSQL + Redis
|
|
52
|
+
/opt/infra/config/postgresql.conf # PostgreSQL 配置
|
|
53
|
+
/opt/infra/config/redis.conf # Redis 配置
|
|
54
|
+
/opt/harbor/harbor.yml # Harbor 配置
|
|
55
|
+
/opt/harness/docker-compose.yml # Harness 配置
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 管理命令
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# 基础设施
|
|
62
|
+
cd /opt/infra && docker compose up -d
|
|
63
|
+
cd /opt/infra && docker compose down
|
|
64
|
+
|
|
65
|
+
# Harbor
|
|
66
|
+
cd /opt/harbor && docker compose up -d
|
|
67
|
+
cd /opt/harbor && docker compose down
|
|
68
|
+
|
|
69
|
+
# Harness
|
|
70
|
+
cd /opt/harness && docker compose up -d
|
|
71
|
+
cd /opt/harness && docker compose down
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Docker 登录 Harbor
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
docker login harbor.wyo.sg
|
|
78
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Incident: 重打收据超时失败
|
|
2
|
+
|
|
3
|
+
- **日期:** 2026-04-01
|
|
4
|
+
- **Issue:** #91
|
|
5
|
+
- **Commit:** `441ec0c`
|
|
6
|
+
- **影响范围:** 所有超过 1 小时的订单重打收据/厨房单
|
|
7
|
+
|
|
8
|
+
## 现象
|
|
9
|
+
|
|
10
|
+
用户在 12:27 重打一张 07:54 创建的订单收据,打印机无响应,PrintJob 被 worker 直接标记为 Failed。
|
|
11
|
+
|
|
12
|
+
## 根因
|
|
13
|
+
|
|
14
|
+
`reprintReceipt()` 和 `printLastKitchenSlips()` 从 DB 取出原始 PrintJob 复用,重置了 `uid`, `status`, `retries` 等字段,但**遗漏了 `created_at_timestamp`**。
|
|
15
|
+
|
|
16
|
+
新 job 携带原始订单的创建时间 (07:54),被 App 端 worker 的超时逻辑判定为超过 1 小时,直接标记 Failed。
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
原始 PrintJob (07:54) → 复制 → 换 uid → 重置 status=Queued
|
|
20
|
+
❌ created_at_timestamp 仍为 07:54
|
|
21
|
+
→ worker: 距今 > 1h → Failed
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 修复
|
|
25
|
+
|
|
26
|
+
在两处 clone 路径中重置时间戳:
|
|
27
|
+
|
|
28
|
+
- `invoice.service.ts` `reprintReceipt()`: `printJob.created_at_timestamp = Date.now()`
|
|
29
|
+
- `invoice.service.ts` `printLastKitchenSlips()`: `updatedJob.created_at_timestamp = Date.now()`
|
|
30
|
+
|
|
31
|
+
## 相关知识
|
|
32
|
+
|
|
33
|
+
- [对象复用的隐式状态泄漏](../KB/object-clone-pitfalls.md)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Boolean 字段默认值设计陷阱
|
|
2
|
+
|
|
3
|
+
**日期:** 2026-05-06
|
|
4
|
+
**类型:** 设计审查
|
|
5
|
+
**严重程度:** 高(若未发现会导致生产事故)
|
|
6
|
+
|
|
7
|
+
## 问题描述
|
|
8
|
+
|
|
9
|
+
在为 Category 和 Item 添加 `is_searchable` 字段时,若设计为:
|
|
10
|
+
- `is_searchable: boolean` 默认 `true`
|
|
11
|
+
|
|
12
|
+
会导致兼容性问题:
|
|
13
|
+
- 现有数据库记录没有此字段
|
|
14
|
+
- JavaScript 读取时值为 `undefined`
|
|
15
|
+
- `undefined` 是 falsy,逻辑上等同于 `false`
|
|
16
|
+
- **结果:所有现有 item/category 突然变得不可搜索**
|
|
17
|
+
|
|
18
|
+
## 正确方案
|
|
19
|
+
|
|
20
|
+
使用**反向布尔字段**:`is_not_searchable`
|
|
21
|
+
- 默认值:`false`(可搜索)
|
|
22
|
+
- 现有数据无此字段 = `undefined` = falsy = 可搜索
|
|
23
|
+
- 显式设为 `true` 才会排除搜索
|
|
24
|
+
|
|
25
|
+
## 通用规则
|
|
26
|
+
|
|
27
|
+
新增布尔字段时,确保:
|
|
28
|
+
- `undefined`/缺失值 = 系统原有行为
|
|
29
|
+
- 新行为需要显式设置 `true`
|
|
30
|
+
|
|
31
|
+
**命名模式:**
|
|
32
|
+
- 原行为是 X → 新字段应为 `is_not_X` 或 `disable_X`
|
|
33
|
+
- 这样 `undefined` = 保持原行为
|
|
34
|
+
|
|
35
|
+
## 相关文件
|
|
36
|
+
|
|
37
|
+
- `src/types/product.type.ts` - ICategory, IItem 接口
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Harbor - 容器镜像仓库
|
|
2
|
+
server {
|
|
3
|
+
listen 80;
|
|
4
|
+
server_name harbor.wyo.sg;
|
|
5
|
+
return 301 https://$server_name$request_uri;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
server {
|
|
9
|
+
listen 443 ssl http2;
|
|
10
|
+
server_name harbor.wyo.sg;
|
|
11
|
+
|
|
12
|
+
ssl_certificate /etc/nginx/ssl/wyo.sg/fullchain.pem;
|
|
13
|
+
ssl_certificate_key /etc/nginx/ssl/wyo.sg/privkey.pem;
|
|
14
|
+
|
|
15
|
+
# SSL 配置
|
|
16
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
17
|
+
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
|
18
|
+
ssl_prefer_server_ciphers off;
|
|
19
|
+
ssl_session_cache shared:SSL:10m;
|
|
20
|
+
ssl_session_timeout 1d;
|
|
21
|
+
|
|
22
|
+
# 重要:Docker 镜像上传无大小限制
|
|
23
|
+
client_max_body_size 0;
|
|
24
|
+
chunked_transfer_encoding on;
|
|
25
|
+
|
|
26
|
+
# 禁用缓冲,支持大文件流式传输
|
|
27
|
+
proxy_buffering off;
|
|
28
|
+
proxy_request_buffering off;
|
|
29
|
+
|
|
30
|
+
location / {
|
|
31
|
+
proxy_pass http://LAN_IP:8081;
|
|
32
|
+
proxy_set_header Host $host;
|
|
33
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
34
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
35
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
36
|
+
|
|
37
|
+
# 超时设置(镜像推送可能耗时较长)
|
|
38
|
+
proxy_connect_timeout 900;
|
|
39
|
+
proxy_send_timeout 900;
|
|
40
|
+
proxy_read_timeout 900;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Harness - Git 代码托管
|
|
45
|
+
server {
|
|
46
|
+
listen 80;
|
|
47
|
+
server_name harness.wyo.sg;
|
|
48
|
+
return 301 https://$server_name$request_uri;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
server {
|
|
52
|
+
listen 443 ssl http2;
|
|
53
|
+
server_name harness.wyo.sg;
|
|
54
|
+
|
|
55
|
+
ssl_certificate /etc/nginx/ssl/wyo.sg/fullchain.pem;
|
|
56
|
+
ssl_certificate_key /etc/nginx/ssl/wyo.sg/privkey.pem;
|
|
57
|
+
|
|
58
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
59
|
+
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
|
60
|
+
ssl_prefer_server_ciphers off;
|
|
61
|
+
ssl_session_cache shared:SSL:10m;
|
|
62
|
+
ssl_session_timeout 1d;
|
|
63
|
+
|
|
64
|
+
# Git 仓库可能较大
|
|
65
|
+
client_max_body_size 0;
|
|
66
|
+
|
|
67
|
+
location / {
|
|
68
|
+
proxy_pass http://LAN_IP:8082;
|
|
69
|
+
proxy_set_header Host $host;
|
|
70
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
71
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
72
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
73
|
+
|
|
74
|
+
# WebSocket 支持(实时日志、通知等)
|
|
75
|
+
proxy_http_version 1.1;
|
|
76
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
77
|
+
proxy_set_header Connection "upgrade";
|
|
78
|
+
|
|
79
|
+
# 超时设置
|
|
80
|
+
proxy_connect_timeout 300;
|
|
81
|
+
proxy_send_timeout 300;
|
|
82
|
+
proxy_read_timeout 300;
|
|
83
|
+
}
|
|
84
|
+
}
|
package/dev/px-cli.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# px-cli
|
|
2
|
+
|
|
3
|
+
Bun CLI project to interact with server using x-api-key method
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd px
|
|
9
|
+
bun install
|
|
10
|
+
cp .env.example .env # fill in PX_BASE_URL, PX_API_KEY, PX_MERCHANT_UID
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
px/
|
|
17
|
+
├── package.json # bun project, depends on @posx/core
|
|
18
|
+
├── tsconfig.json
|
|
19
|
+
├── .env.example
|
|
20
|
+
├── index.ts # entry point & router (cac)
|
|
21
|
+
├── http.ts # HTTP client with x-api-key auth
|
|
22
|
+
└── commands/
|
|
23
|
+
├── category.ts # Category CRUD (types: ICategory)
|
|
24
|
+
└── product.ts # Product CRUD (types: IItem)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Dependencies
|
|
28
|
+
|
|
29
|
+
- `@posx/core` — import types only (no service layer — no Dexie/IndexedDB in Bun):
|
|
30
|
+
- `IServiceOptions` — config typing in `http.ts`
|
|
31
|
+
- `ICategory` — category request/response typing
|
|
32
|
+
- `IItem` — product request/response typing
|
|
33
|
+
- `@litepos/autoquery` — `QueryBuilder` for `list` action (autoquery via `sapi` endpoint)
|
|
34
|
+
- `cac` — lightweight CLI framework (arg parsing, help text, subcommands)
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Read (immediate)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# List via autoquery (sapi)
|
|
42
|
+
px category list
|
|
43
|
+
px category list --nameContains Drinks --take 10
|
|
44
|
+
px product list
|
|
45
|
+
px product list --nameContains Latte --take 10
|
|
46
|
+
|
|
47
|
+
# Get by ID
|
|
48
|
+
px category get --id 123
|
|
49
|
+
px product get --id 456
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### CUD — direct execution with dry-run
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Add
|
|
56
|
+
px category add --name "Drinks" --type product --color "#ff0000" --icon "🍹"
|
|
57
|
+
px category add --name "Drinks" --dry-run # preview only
|
|
58
|
+
|
|
59
|
+
# Update (always fetches first: GET → show diff → PATCH)
|
|
60
|
+
px category update --id 123 --name "Beverages"
|
|
61
|
+
px product update --id 456 --price 6.00 --dry-run # preview diff
|
|
62
|
+
|
|
63
|
+
# Delete
|
|
64
|
+
px category delete --id 123
|
|
65
|
+
px product delete --id 456 --dry-run # preview record to be removed
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Update flow
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
1. GET /api/v5/merchants/{uid}/product/456
|
|
72
|
+
2. Show diff:
|
|
73
|
+
- price: 5.00 → 6.00
|
|
74
|
+
3. PATCH (or skip if --dry-run)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`--dry-run` 和正常执行都会先 GET,区别只在是否发送 PATCH。
|
|
78
|
+
|
|
79
|
+
## API
|
|
80
|
+
|
|
81
|
+
- **Base**: `https://lite-dev.posx.ai`
|
|
82
|
+
- **Auth**: `x-api-key` header
|
|
83
|
+
|
|
84
|
+
| Method | Route | Action |
|
|
85
|
+
|----------|-----------------------------------------------------|------------------|
|
|
86
|
+
| `GET` | `sapi/v5/merchants/{merchant_uid}/{module}` | list (autoquery) |
|
|
87
|
+
| `GET` | `api/v5/merchants/{merchant_uid}/{module}/{id}` | get |
|
|
88
|
+
| `PUT` | `api/v5/merchants/{merchant_uid}/{module}/{method}` | add |
|
|
89
|
+
| `PATCH` | `api/v5/merchants/{merchant_uid}/{module}/{id}` | update |
|
|
90
|
+
| `DELETE` | `api/v5/merchants/{merchant_uid}/{module}/{id}` | delete |
|
|
91
|
+
|
|
92
|
+
## Ref
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
curl -H "x-api-key: p8Hwl4A7ewynszODOOc05SJcqSP6YZDo2pevtZ" \
|
|
96
|
+
"https://lite-dev.posx.ai/api/v5/merchants/by-whatsapp-jid/6590992059@s.whatsapp.net"
|
|
97
|
+
```
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# 2026-02 测试日志
|
|
2
|
+
|
|
3
|
+
| # | 分支 | 时间 | 变更 | 测试 | 🌐 | 问题 | 状态 |
|
|
4
|
+
|---|------|------|------|------|:--:|------|------|
|
|
5
|
+
| 1 | bugfix/rounding-half-up-51 | 02-03 10:45 | roundingStep 实现 round half up | 19/20 passed | ✗ | `service-charge-and-tax-exempt.test.ts` 期望值需更新 5877→5876.9 | 🔧 需修复 |
|