@seasonkoh/webaz 0.1.23 → 0.1.25
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/README.md +2 -0
- package/dist/layer0-foundation/L0-1-database/db-backends/pg-backend.js +51 -0
- package/dist/layer0-foundation/L0-1-database/db-backends/sql-dialect-datetime.js +437 -0
- package/dist/layer0-foundation/L0-1-database/db-backends/sql-placeholders.js +98 -0
- package/dist/layer0-foundation/L0-1-database/db.js +65 -0
- package/dist/layer0-foundation/L0-2-state-machine/order-chain.js +13 -11
- package/dist/layer0-foundation/L0-2-state-machine/transitions.js +1 -1
- package/dist/layer0-foundation/L0-5-manifest/manifest.js +13 -11
- package/dist/layer1-agent/L1-1-mcp-server/server.js +198 -83
- package/dist/layer1-agent/L1-2-external-anchor/anchor-engine.js +14 -12
- package/dist/layer2-business/L2-6-notifications/notification-engine.js +8 -5
- package/dist/layer2-business/L2-7-snf/snf-engine.js +16 -14
- package/dist/layer2-business/L2-8-feedback/build-feedback-engine.js +18 -10
- package/dist/layer2-business/L2-9-contribution/build-reputation-engine.js +37 -23
- package/dist/layer2-business/L2-9-contribution/build-task-agent-metadata-store.js +173 -0
- package/dist/layer2-business/L2-9-contribution/build-task-participation.js +47 -0
- package/dist/layer2-business/L2-9-contribution/build-task-read.js +222 -0
- package/dist/layer2-business/L2-9-contribution/build-tasks-engine.js +10 -2
- package/dist/layer2-business/L2-9-contribution/canonical-contribution-target.js +16 -0
- package/dist/layer2-business/L2-9-contribution/contribution-display-envelope.js +40 -0
- package/dist/layer2-business/L2-9-contribution/contribution-score-contract.js +36 -0
- package/dist/layer2-business/L2-9-contribution/contribution-score-evidence.js +61 -0
- package/dist/layer2-business/L2-9-contribution/github-credential/canonical.js +60 -0
- package/dist/layer2-business/L2-9-contribution/github-credential/github-credential.schema.js +140 -0
- package/dist/layer2-business/L2-9-contribution/github-credential/github-fetch-adapter.js +437 -0
- package/dist/layer2-business/L2-9-contribution/github-credential/self-consistency.js +38 -0
- package/dist/layer2-business/L2-9-contribution/github-credential/verifier.js +231 -0
- package/dist/layer2-business/L2-9-contribution/github-credential-ingestion-engine.js +145 -0
- package/dist/layer2-business/L2-9-contribution/github-credential-store.js +115 -0
- package/dist/layer2-business/L2-9-contribution/identity-binding-engine.js +134 -0
- package/dist/layer2-business/L2-9-contribution/identity-binding-store.js +101 -0
- package/dist/layer2-business/L2-9-contribution/identity-claim-challenge-engine.js +126 -0
- package/dist/layer2-business/L2-9-contribution/identity-claim-challenge-store.js +30 -0
- package/dist/layer2-business/L2-9-contribution/identity-claim-engine.js +109 -0
- package/dist/layer2-business/L2-9-contribution/identity-claim-fact-precondition.js +22 -0
- package/dist/layer2-business/L2-9-contribution/identity-claim-proof-verifier.js +97 -0
- package/dist/layer2-business/L2-9-contribution/identity-claim-read.js +59 -0
- package/dist/layer2-business/L2-9-contribution/task-proposal-store.js +129 -0
- package/dist/layer2-business/L2-notes/note-photo-storage.js +4 -2
- package/dist/layer3-trust/L3-1-dispute-engine/dispute-engine.js +17 -15
- package/dist/layer3-trust/L3-1-dispute-engine/evidence-storage.js +11 -8
- package/dist/layer4-economics/L4-3-reputation/reputation-engine.js +9 -8
- package/dist/layer4-economics/L4-4-skill-market/skill-engine.js +11 -8
- package/dist/layer4-economics/L4-4-skill-market/skill-listing-engine.js +22 -16
- package/dist/pwa/acp-feed.js +13 -1
- package/dist/pwa/contract-fingerprint.js +2 -0
- package/dist/pwa/endpoint-actions.js +5 -1
- package/dist/pwa/goal-index.js +8 -8
- package/dist/pwa/human-presence.js +62 -0
- package/dist/pwa/public/app.js +575 -68
- package/dist/pwa/public/i18n.js +29 -20
- package/dist/pwa/public/index.html +1 -0
- package/dist/pwa/public/openapi.json +2 -2
- package/dist/pwa/rate-limit.js +22 -0
- package/dist/pwa/routes/account-deletion.js +15 -13
- package/dist/pwa/routes/addresses.js +10 -9
- package/dist/pwa/routes/admin-admins.js +13 -14
- package/dist/pwa/routes/admin-analytics.js +109 -69
- package/dist/pwa/routes/admin-catalog.js +13 -11
- package/dist/pwa/routes/admin-editor-picks.js +15 -10
- package/dist/pwa/routes/admin-events.js +5 -3
- package/dist/pwa/routes/admin-health.js +2 -1
- package/dist/pwa/routes/admin-moderation.js +26 -29
- package/dist/pwa/routes/admin-ops.js +22 -21
- package/dist/pwa/routes/admin-protocol-params.js +16 -19
- package/dist/pwa/routes/admin-reports.js +23 -21
- package/dist/pwa/routes/admin-tokenomics.js +26 -25
- package/dist/pwa/routes/admin-users-lifecycle.js +37 -40
- package/dist/pwa/routes/admin-users-query.js +54 -53
- package/dist/pwa/routes/admin-verifier-flow.js +82 -41
- package/dist/pwa/routes/admin-verifier-whitelist.js +55 -27
- package/dist/pwa/routes/admin-wallet-ops.js +7 -5
- package/dist/pwa/routes/agent-buy.js +46 -22
- package/dist/pwa/routes/agent-governance.js +52 -56
- package/dist/pwa/routes/ai.js +7 -5
- package/dist/pwa/routes/analytics.js +43 -41
- package/dist/pwa/routes/anchors.js +19 -20
- package/dist/pwa/routes/announcements.js +13 -13
- package/dist/pwa/routes/arbitrator.js +97 -31
- package/dist/pwa/routes/auction.js +153 -114
- package/dist/pwa/routes/auth-login.js +6 -4
- package/dist/pwa/routes/auth-read.js +11 -9
- package/dist/pwa/routes/auth-register.js +35 -20
- package/dist/pwa/routes/auth-sessions.js +12 -11
- package/dist/pwa/routes/blocklist.js +16 -15
- package/dist/pwa/routes/build-feedback.js +10 -9
- package/dist/pwa/routes/build-reputation.js +6 -2
- package/dist/pwa/routes/build-tasks.js +45 -13
- package/dist/pwa/routes/buyer-feeds.js +27 -25
- package/dist/pwa/routes/cart.js +16 -15
- package/dist/pwa/routes/charity.js +212 -150
- package/dist/pwa/routes/chat.js +42 -43
- package/dist/pwa/routes/checkin-tasks.js +10 -9
- package/dist/pwa/routes/checkout-helpers.js +12 -10
- package/dist/pwa/routes/claim-initiators.js +34 -14
- package/dist/pwa/routes/claim-verify.js +86 -53
- package/dist/pwa/routes/claim-voting.js +43 -18
- package/dist/pwa/routes/contribution-identity.js +147 -0
- package/dist/pwa/routes/contribution-score.js +19 -0
- package/dist/pwa/routes/coupons.js +19 -16
- package/dist/pwa/routes/dashboards.js +18 -16
- package/dist/pwa/routes/dispute-cases.js +25 -24
- package/dist/pwa/routes/disputes-read.js +45 -51
- package/dist/pwa/routes/disputes-write.js +124 -61
- package/dist/pwa/routes/evidence.js +9 -9
- package/dist/pwa/routes/external-anchors.js +13 -12
- package/dist/pwa/routes/feedback.js +29 -33
- package/dist/pwa/routes/flash-sales.js +18 -16
- package/dist/pwa/routes/follows.js +25 -24
- package/dist/pwa/routes/governance-auto-deactivate.js +21 -9
- package/dist/pwa/routes/governance-onboarding.js +70 -59
- package/dist/pwa/routes/group-buys.js +22 -22
- package/dist/pwa/routes/growth.js +33 -30
- package/dist/pwa/routes/import-product.js +12 -10
- package/dist/pwa/routes/kyc.js +9 -8
- package/dist/pwa/routes/leaderboard.js +20 -18
- package/dist/pwa/routes/listings.js +23 -22
- package/dist/pwa/routes/logistics.js +10 -8
- package/dist/pwa/routes/manifests.js +27 -27
- package/dist/pwa/routes/me-data.js +23 -21
- package/dist/pwa/routes/notifications.js +7 -6
- package/dist/pwa/routes/offers.js +30 -12
- package/dist/pwa/routes/orders-action.js +33 -17
- package/dist/pwa/routes/orders-create.js +75 -20
- package/dist/pwa/routes/orders-read.js +21 -20
- package/dist/pwa/routes/p2p-products.js +30 -18
- package/dist/pwa/routes/payments-governance.js +61 -56
- package/dist/pwa/routes/peers.js +9 -8
- package/dist/pwa/routes/pin-receipts.js +13 -13
- package/dist/pwa/routes/products-aliases.js +12 -10
- package/dist/pwa/routes/products-claims.js +36 -17
- package/dist/pwa/routes/products-create.js +53 -38
- package/dist/pwa/routes/products-crud.js +17 -16
- package/dist/pwa/routes/products-links.js +49 -26
- package/dist/pwa/routes/products-list.js +6 -4
- package/dist/pwa/routes/products-meta.js +40 -39
- package/dist/pwa/routes/products-update.js +19 -5
- package/dist/pwa/routes/profile-credentials.js +14 -16
- package/dist/pwa/routes/profile-identity.js +14 -13
- package/dist/pwa/routes/profile-location.js +7 -6
- package/dist/pwa/routes/profile-placement.js +19 -17
- package/dist/pwa/routes/profile-prefs.js +11 -11
- package/dist/pwa/routes/promoter.js +55 -49
- package/dist/pwa/routes/public-build-tasks.js +19 -0
- package/dist/pwa/routes/public-utils.js +108 -46
- package/dist/pwa/routes/push.js +16 -15
- package/dist/pwa/routes/ratings.js +30 -30
- package/dist/pwa/routes/recover-key.js +13 -12
- package/dist/pwa/routes/referral.js +37 -32
- package/dist/pwa/routes/reputation.js +3 -2
- package/dist/pwa/routes/returns.js +76 -73
- package/dist/pwa/routes/reviews.js +41 -18
- package/dist/pwa/routes/rewards-apply.js +16 -15
- package/dist/pwa/routes/rewards-auto-downgrade.js +9 -7
- package/dist/pwa/routes/rewards-escrow-expire.js +7 -5
- package/dist/pwa/routes/rfqs.js +163 -85
- package/dist/pwa/routes/search.js +16 -14
- package/dist/pwa/routes/secondhand.js +25 -22
- package/dist/pwa/routes/seller-quota.js +24 -26
- package/dist/pwa/routes/share-redirects.js +59 -55
- package/dist/pwa/routes/shareables-interactions.js +34 -35
- package/dist/pwa/routes/shareables.js +55 -51
- package/dist/pwa/routes/shop-referral.js +57 -0
- package/dist/pwa/routes/shops.js +20 -18
- package/dist/pwa/routes/signaling.js +10 -9
- package/dist/pwa/routes/skill-market.js +16 -16
- package/dist/pwa/routes/skills.js +15 -14
- package/dist/pwa/routes/snf.js +14 -13
- package/dist/pwa/routes/tags.js +10 -9
- package/dist/pwa/routes/task-proposals.js +45 -0
- package/dist/pwa/routes/trial.js +69 -51
- package/dist/pwa/routes/trusted-kpi.js +20 -18
- package/dist/pwa/routes/url-claim.js +67 -28
- package/dist/pwa/routes/users-public.js +62 -60
- package/dist/pwa/routes/variants.js +12 -13
- package/dist/pwa/routes/verifier-user.js +61 -21
- package/dist/pwa/routes/verify-tasks.js +49 -25
- package/dist/pwa/routes/waitlist.js +16 -15
- package/dist/pwa/routes/wallet-read.js +74 -36
- package/dist/pwa/routes/wallet-write.js +12 -9
- package/dist/pwa/routes/webauthn.js +25 -26
- package/dist/pwa/routes/webhooks.js +26 -26
- package/dist/pwa/routes/welcome.js +45 -50
- package/dist/pwa/routes/wishlist-qa.js +29 -32
- package/dist/pwa/server.js +237 -81
- package/dist/version.js +1 -1
- package/package.json +47 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { dbOne, dbAll } from '../../layer0-foundation/L0-1-database/db.js'; // RFC-016 异步 DB seam
|
|
1
2
|
export function registerAdminOpsRoutes(app, deps) {
|
|
2
3
|
const { db, auth, requireUsersAdmin, hasAdminPermission, INTERNAL_AUDITOR_ID, ADMIN_EXPORT_LIMIT, csvEscapeAdmin, anthropic, applyDecayIfDue, computeValueBadges } = deps;
|
|
3
|
-
app.get('/api/admin/export/:kind', (req, res) => {
|
|
4
|
+
app.get('/api/admin/export/:kind', async (req, res) => {
|
|
4
5
|
const admin = requireUsersAdmin(req, res);
|
|
5
6
|
if (!admin)
|
|
6
7
|
return;
|
|
@@ -9,23 +10,23 @@ export function registerAdminOpsRoutes(app, deps) {
|
|
|
9
10
|
let rows = [];
|
|
10
11
|
if (kind === 'users') {
|
|
11
12
|
headers = ['id', 'name', 'handle', 'role', 'region', 'email_verified', 'created_at'];
|
|
12
|
-
rows =
|
|
13
|
+
rows = await dbAll(`SELECT id, name, handle, role, region, email_verified, created_at FROM users WHERE id NOT IN ('sys_protocol', ?) ORDER BY created_at DESC LIMIT ?`, [INTERNAL_AUDITOR_ID, ADMIN_EXPORT_LIMIT]);
|
|
13
14
|
}
|
|
14
15
|
else if (kind === 'orders') {
|
|
15
16
|
headers = ['id', 'product_id', 'buyer_id', 'seller_id', 'status', 'total_amount', 'quantity', 'created_at'];
|
|
16
|
-
rows =
|
|
17
|
+
rows = await dbAll(`SELECT id, product_id, buyer_id, seller_id, status, total_amount, quantity, created_at FROM orders ORDER BY created_at DESC LIMIT ?`, [ADMIN_EXPORT_LIMIT]);
|
|
17
18
|
}
|
|
18
19
|
else if (kind === 'disputes') {
|
|
19
20
|
headers = ['id', 'order_id', 'initiator_id', 'defendant_id', 'status', 'ruling_type', 'created_at', 'resolved_at'];
|
|
20
|
-
rows =
|
|
21
|
+
rows = await dbAll(`SELECT id, order_id, initiator_id, defendant_id, status, ruling_type, created_at, resolved_at FROM disputes ORDER BY created_at DESC LIMIT ?`, [ADMIN_EXPORT_LIMIT]);
|
|
21
22
|
}
|
|
22
23
|
else if (kind === 'reward_log') {
|
|
23
24
|
headers = ['id', 'user_id', 'amount', 'source', 'ref', 'created_at'];
|
|
24
|
-
rows =
|
|
25
|
+
rows = await dbAll(`SELECT id, user_id, amount, source, ref, created_at FROM platform_reward_log ORDER BY created_at DESC LIMIT ?`, [ADMIN_EXPORT_LIMIT]);
|
|
25
26
|
}
|
|
26
27
|
else if (kind === 'feedback') {
|
|
27
28
|
headers = ['id', 'user_id', 'category', 'severity', 'subject', 'status', 'created_at'];
|
|
28
|
-
rows =
|
|
29
|
+
rows = await dbAll(`SELECT id, user_id, category, severity, subject, status, created_at FROM feedback_tickets ORDER BY created_at DESC LIMIT ?`, [ADMIN_EXPORT_LIMIT]);
|
|
29
30
|
}
|
|
30
31
|
else {
|
|
31
32
|
return void res.status(400).json({ error: 'kind 必须 users/orders/disputes/reward_log/feedback' });
|
|
@@ -49,14 +50,14 @@ export function registerAdminOpsRoutes(app, deps) {
|
|
|
49
50
|
if (!admin)
|
|
50
51
|
return;
|
|
51
52
|
const uid = req.params.user_id;
|
|
52
|
-
const u =
|
|
53
|
+
const u = await dbOne("SELECT id, name, handle, role, created_at FROM users WHERE id = ?", [uid]);
|
|
53
54
|
if (!u)
|
|
54
55
|
return void res.status(404).json({ error: '用户不存在' });
|
|
55
|
-
const orders =
|
|
56
|
-
const completed =
|
|
57
|
-
const disputes =
|
|
58
|
-
const withdrawals =
|
|
59
|
-
const repNegEvents =
|
|
56
|
+
const orders = (await dbOne(`SELECT COUNT(*) as n, COALESCE(SUM(total_amount),0) as gmv FROM orders WHERE buyer_id=? OR seller_id=?`, [uid, uid]));
|
|
57
|
+
const completed = (await dbOne(`SELECT COUNT(*) as n FROM orders WHERE (buyer_id=? OR seller_id=?) AND status='completed'`, [uid, uid])).n;
|
|
58
|
+
const disputes = (await dbOne(`SELECT COUNT(*) as n FROM disputes WHERE initiator_id=? OR defendant_id=?`, [uid, uid])).n;
|
|
59
|
+
const withdrawals = (await dbOne(`SELECT COUNT(*) as n, COALESCE(SUM(amount),0) as t FROM withdrawal_requests WHERE user_id=?`, [uid]));
|
|
60
|
+
const repNegEvents = (await dbOne(`SELECT COUNT(*) as n FROM reputation_events WHERE user_id=? AND points < 0`, [uid])).n;
|
|
60
61
|
const accountAgeDays = u.created_at ? Math.floor((Date.now() - new Date(u.created_at).getTime()) / 86400_000) : 0;
|
|
61
62
|
try {
|
|
62
63
|
const message = await anthropic.messages.create({
|
|
@@ -109,7 +110,7 @@ export function registerAdminOpsRoutes(app, deps) {
|
|
|
109
110
|
const r = applyDecayIfDue(db, { force: !!req.body?.force });
|
|
110
111
|
res.json(r);
|
|
111
112
|
});
|
|
112
|
-
app.get('/api/admin/errors', (req, res) => {
|
|
113
|
+
app.get('/api/admin/errors', async (req, res) => {
|
|
113
114
|
const user = auth(req, res);
|
|
114
115
|
if (!user)
|
|
115
116
|
return;
|
|
@@ -119,18 +120,18 @@ export function registerAdminOpsRoutes(app, deps) {
|
|
|
119
120
|
const source = req.query.source ? String(req.query.source) : '';
|
|
120
121
|
const where = source ? 'WHERE source = ?' : '';
|
|
121
122
|
const args = source ? [source, limit] : [limit];
|
|
122
|
-
const rows =
|
|
123
|
+
const rows = await dbAll(`SELECT * FROM error_log ${where} ORDER BY id DESC LIMIT ?`, args);
|
|
123
124
|
res.json({ items: rows });
|
|
124
125
|
});
|
|
125
126
|
// Tier 1 #5: 错误聚合 view(24h / 1h 趋势 + top by source + top messages + burst alert)
|
|
126
|
-
app.get('/api/admin/errors/aggregate', (req, res) => {
|
|
127
|
+
app.get('/api/admin/errors/aggregate', async (req, res) => {
|
|
127
128
|
const user = auth(req, res);
|
|
128
129
|
if (!user)
|
|
129
130
|
return;
|
|
130
131
|
if (!hasAdminPermission(user, 'protocol'))
|
|
131
132
|
return void res.status(403).json({ error: 'forbidden' });
|
|
132
133
|
// 24h 按 source 聚合 + 1h 数 + 最近时间(COALESCE 防 SUM null)
|
|
133
|
-
const bySource =
|
|
134
|
+
const bySource = await dbAll(`
|
|
134
135
|
SELECT source,
|
|
135
136
|
COUNT(*) as cnt_24h,
|
|
136
137
|
COALESCE(SUM(CASE WHEN created_at > datetime('now', '-1 hour') THEN 1 ELSE 0 END), 0) as cnt_1h,
|
|
@@ -140,24 +141,24 @@ export function registerAdminOpsRoutes(app, deps) {
|
|
|
140
141
|
WHERE created_at > datetime('now', '-24 hours')
|
|
141
142
|
GROUP BY source
|
|
142
143
|
ORDER BY cnt_24h DESC
|
|
143
|
-
`)
|
|
144
|
+
`);
|
|
144
145
|
// top 10 重复错误(前 100 字符聚合)
|
|
145
|
-
const topMessages =
|
|
146
|
+
const topMessages = await dbAll(`
|
|
146
147
|
SELECT substr(message, 1, 100) as msg, source, COUNT(*) as cnt, MAX(created_at) as last_seen
|
|
147
148
|
FROM error_log
|
|
148
149
|
WHERE created_at > datetime('now', '-24 hours')
|
|
149
150
|
GROUP BY substr(message, 1, 100), source
|
|
150
151
|
ORDER BY cnt DESC LIMIT 10
|
|
151
|
-
`)
|
|
152
|
+
`);
|
|
152
153
|
// 总数
|
|
153
|
-
const totals =
|
|
154
|
+
const totals = (await dbOne(`
|
|
154
155
|
SELECT
|
|
155
156
|
COUNT(*) as total_24h,
|
|
156
157
|
COALESCE(SUM(CASE WHEN created_at > datetime('now', '-1 hour') THEN 1 ELSE 0 END), 0) as total_1h,
|
|
157
158
|
COALESCE(SUM(CASE WHEN created_at > datetime('now', '-10 minutes') THEN 1 ELSE 0 END), 0) as total_10m
|
|
158
159
|
FROM error_log
|
|
159
160
|
WHERE created_at > datetime('now', '-24 hours')
|
|
160
|
-
`)
|
|
161
|
+
`));
|
|
161
162
|
// burst alert: 1h 内任一 source > 50,或 10min > 20 → 标红
|
|
162
163
|
const BURST_1H = 50;
|
|
163
164
|
const BURST_10M = 20;
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
+
import { dbOne, dbAll, dbRun } from '../../layer0-foundation/L0-1-database/db.js'; // RFC-016 异步 DB seam
|
|
1
2
|
export function registerAdminProtocolParamsRoutes(app, deps) {
|
|
2
3
|
const { db, generateId, requireAdmin, requireProtocolAdmin } = deps;
|
|
3
|
-
app.get('/api/admin/protocol-params', (req, res) => {
|
|
4
|
+
app.get('/api/admin/protocol-params', async (req, res) => {
|
|
4
5
|
const admin = requireAdmin(req, res);
|
|
5
6
|
if (!admin)
|
|
6
7
|
return;
|
|
7
|
-
const rows =
|
|
8
|
-
FROM protocol_params ORDER BY category, key
|
|
8
|
+
const rows = await dbAll(`SELECT key, value, type, description, category, default_value, min_value, max_value, updated_at, updated_by
|
|
9
|
+
FROM protocol_params ORDER BY category, key`, []);
|
|
9
10
|
res.json({ items: rows });
|
|
10
11
|
});
|
|
11
12
|
// H-2 P1-2: 协议参数是全局配置,需 protocol 权限(区域 admin 不能改)
|
|
12
13
|
// 2026-06-03 #1095: + constitutional only-increase 守护
|
|
13
|
-
app.patch('/api/admin/protocol-params/:key', (req, res) => {
|
|
14
|
+
app.patch('/api/admin/protocol-params/:key', async (req, res) => {
|
|
14
15
|
const admin = requireProtocolAdmin(req, res);
|
|
15
16
|
if (!admin)
|
|
16
17
|
return;
|
|
17
|
-
const param =
|
|
18
|
+
const param = await dbOne('SELECT type, min_value, max_value, category, value, requires_meta_rule_change FROM protocol_params WHERE key = ?', [req.params.key]);
|
|
18
19
|
if (!param)
|
|
19
20
|
return void res.status(404).json({ error: '参数不存在' });
|
|
20
21
|
const { value } = req.body || {};
|
|
@@ -41,8 +42,7 @@ export function registerAdminProtocolParamsRoutes(app, deps) {
|
|
|
41
42
|
// #1096 audit:拒绝时也写 protocol_params_log(meta-rule #1 "当一切可见")
|
|
42
43
|
// 谁尝试降低宪法保护要留痕,即便 attempt 失败
|
|
43
44
|
try {
|
|
44
|
-
|
|
45
|
-
.run(generateId('ppl'), req.params.key, param.value, strVal, admin.id);
|
|
45
|
+
await dbRun(`INSERT INTO protocol_params_log (id, key, old_value, new_value, changed_by, action) VALUES (?,?,?,?,?,'constitutional_reject_patch')`, [generateId('ppl'), req.params.key, param.value, strVal, admin.id]);
|
|
46
46
|
}
|
|
47
47
|
catch (_e) { /* log 失败不阻塞 reject 决定 */ }
|
|
48
48
|
return void res.status(403).json({
|
|
@@ -60,8 +60,7 @@ export function registerAdminProtocolParamsRoutes(app, deps) {
|
|
|
60
60
|
const oldNum = Number(param.value);
|
|
61
61
|
if (Number.isFinite(oldNum) && n < oldNum) {
|
|
62
62
|
try {
|
|
63
|
-
|
|
64
|
-
.run(generateId('ppl'), req.params.key, param.value, strVal, admin.id);
|
|
63
|
+
await dbRun(`INSERT INTO protocol_params_log (id, key, old_value, new_value, changed_by, action) VALUES (?,?,?,?,?,'meta_rule_reject_patch')`, [generateId('ppl'), req.params.key, param.value, strVal, admin.id]);
|
|
65
64
|
}
|
|
66
65
|
catch (_e) { /* log 失败不阻塞 */ }
|
|
67
66
|
return void res.status(403).json({
|
|
@@ -77,7 +76,7 @@ export function registerAdminProtocolParamsRoutes(app, deps) {
|
|
|
77
76
|
return void res.status(400).json({ error: '类型不匹配(需 boolean)' });
|
|
78
77
|
}
|
|
79
78
|
// A-3: 变更前快照旧值
|
|
80
|
-
const oldRow =
|
|
79
|
+
const oldRow = await dbOne('SELECT value FROM protocol_params WHERE key = ?', [req.params.key]);
|
|
81
80
|
db.transaction(() => {
|
|
82
81
|
db.prepare(`UPDATE protocol_params SET value = ?, updated_at = datetime('now'), updated_by = ? WHERE key = ?`)
|
|
83
82
|
.run(strVal, admin.id, req.params.key);
|
|
@@ -86,11 +85,11 @@ export function registerAdminProtocolParamsRoutes(app, deps) {
|
|
|
86
85
|
})();
|
|
87
86
|
res.json({ success: true });
|
|
88
87
|
});
|
|
89
|
-
app.post('/api/admin/protocol-params/:key/reset', (req, res) => {
|
|
88
|
+
app.post('/api/admin/protocol-params/:key/reset', async (req, res) => {
|
|
90
89
|
const admin = requireProtocolAdmin(req, res);
|
|
91
90
|
if (!admin)
|
|
92
91
|
return;
|
|
93
|
-
const param =
|
|
92
|
+
const param = await dbOne('SELECT default_value, value, category, type, requires_meta_rule_change FROM protocol_params WHERE key = ?', [req.params.key]);
|
|
94
93
|
if (!param || param.default_value == null)
|
|
95
94
|
return void res.status(404).json({ error: '参数不存在或无默认值' });
|
|
96
95
|
// #1095 CHARTER §4 I-4: constitutional reset 走 same only-increase
|
|
@@ -101,8 +100,7 @@ export function registerAdminProtocolParamsRoutes(app, deps) {
|
|
|
101
100
|
if (Number.isFinite(cur) && Number.isFinite(def) && def < cur) {
|
|
102
101
|
// #1096 audit:reset 拒绝同样留痕
|
|
103
102
|
try {
|
|
104
|
-
|
|
105
|
-
.run(generateId('ppl'), req.params.key, param.value, param.default_value, admin.id);
|
|
103
|
+
await dbRun(`INSERT INTO protocol_params_log (id, key, old_value, new_value, changed_by, action) VALUES (?,?,?,?,?,'constitutional_reject_reset')`, [generateId('ppl'), req.params.key, param.value, param.default_value, admin.id]);
|
|
106
104
|
}
|
|
107
105
|
catch (_e) { /* log 失败不阻塞 */ }
|
|
108
106
|
return void res.status(403).json({
|
|
@@ -119,8 +117,7 @@ export function registerAdminProtocolParamsRoutes(app, deps) {
|
|
|
119
117
|
const def = Number(param.default_value);
|
|
120
118
|
if (Number.isFinite(cur) && Number.isFinite(def) && def < cur) {
|
|
121
119
|
try {
|
|
122
|
-
|
|
123
|
-
.run(generateId('ppl'), req.params.key, param.value, param.default_value, admin.id);
|
|
120
|
+
await dbRun(`INSERT INTO protocol_params_log (id, key, old_value, new_value, changed_by, action) VALUES (?,?,?,?,?,'meta_rule_reject_reset')`, [generateId('ppl'), req.params.key, param.value, param.default_value, admin.id]);
|
|
124
121
|
}
|
|
125
122
|
catch (_e) { /* log 失败不阻塞 */ }
|
|
126
123
|
return void res.status(403).json({
|
|
@@ -140,18 +137,18 @@ export function registerAdminProtocolParamsRoutes(app, deps) {
|
|
|
140
137
|
res.json({ success: true });
|
|
141
138
|
});
|
|
142
139
|
// A-3: 变更历史
|
|
143
|
-
app.get('/api/admin/protocol-params/:key/history', (req, res) => {
|
|
140
|
+
app.get('/api/admin/protocol-params/:key/history', async (req, res) => {
|
|
144
141
|
const admin = requireProtocolAdmin(req, res);
|
|
145
142
|
if (!admin)
|
|
146
143
|
return;
|
|
147
|
-
const rows =
|
|
144
|
+
const rows = await dbAll(`
|
|
148
145
|
SELECT l.id, l.old_value, l.new_value, l.changed_by, l.action, l.created_at,
|
|
149
146
|
u.name as changed_by_name, u.handle as changed_by_handle
|
|
150
147
|
FROM protocol_params_log l
|
|
151
148
|
LEFT JOIN users u ON u.id = l.changed_by
|
|
152
149
|
WHERE l.key = ?
|
|
153
150
|
ORDER BY l.created_at DESC LIMIT 100
|
|
154
|
-
|
|
151
|
+
`, [req.params.key]);
|
|
155
152
|
res.json({ items: rows });
|
|
156
153
|
});
|
|
157
154
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { dbOne, dbAll } from '../../layer0-foundation/L0-1-database/db.js'; // RFC-016 异步 DB seam
|
|
1
2
|
export function registerAdminReportsRoutes(app, deps) {
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
// db 已全量走 RFC-016 异步 seam(dbOne/dbAll),不再直接用 deps.db
|
|
4
|
+
const { requireContentAdmin, requireArbitrationAdmin, requireProtocolAdmin } = deps;
|
|
5
|
+
app.get('/api/admin/orders', async (req, res) => {
|
|
4
6
|
const admin = requireContentAdmin(req, res);
|
|
5
7
|
if (!admin)
|
|
6
8
|
return;
|
|
@@ -19,13 +21,13 @@ export function registerAdminReportsRoutes(app, deps) {
|
|
|
19
21
|
params.push(status);
|
|
20
22
|
}
|
|
21
23
|
sql += ` ORDER BY o.created_at DESC LIMIT 100`;
|
|
22
|
-
res.json({ orders:
|
|
24
|
+
res.json({ orders: await dbAll(sql, params) });
|
|
23
25
|
});
|
|
24
|
-
app.get('/api/admin/disputes', (req, res) => {
|
|
26
|
+
app.get('/api/admin/disputes', async (req, res) => {
|
|
25
27
|
const admin = requireArbitrationAdmin(req, res);
|
|
26
28
|
if (!admin)
|
|
27
29
|
return;
|
|
28
|
-
const rows =
|
|
30
|
+
const rows = await dbAll(`
|
|
29
31
|
SELECT d.id, d.order_id, d.initiator_id, d.defendant_id, d.reason, d.status,
|
|
30
32
|
d.created_at, d.respond_deadline, d.arbitrate_deadline, d.resolved_at,
|
|
31
33
|
u1.name as initiator_name, u2.name as defendant_name,
|
|
@@ -37,10 +39,10 @@ export function registerAdminReportsRoutes(app, deps) {
|
|
|
37
39
|
LEFT JOIN orders o ON d.order_id = o.id
|
|
38
40
|
LEFT JOIN products p ON o.product_id = p.id
|
|
39
41
|
ORDER BY d.created_at DESC LIMIT 100
|
|
40
|
-
`)
|
|
42
|
+
`);
|
|
41
43
|
res.json({ disputes: rows });
|
|
42
44
|
});
|
|
43
|
-
app.get('/api/admin/verify-tasks', (req, res) => {
|
|
45
|
+
app.get('/api/admin/verify-tasks', async (req, res) => {
|
|
44
46
|
const admin = requireArbitrationAdmin(req, res);
|
|
45
47
|
if (!admin)
|
|
46
48
|
return;
|
|
@@ -57,21 +59,21 @@ export function registerAdminReportsRoutes(app, deps) {
|
|
|
57
59
|
params.push(status);
|
|
58
60
|
}
|
|
59
61
|
sql += ` ORDER BY vt.created_at DESC LIMIT 100`;
|
|
60
|
-
res.json({ tasks:
|
|
62
|
+
res.json({ tasks: await dbAll(sql, params) });
|
|
61
63
|
});
|
|
62
64
|
// 双引擎收入治理视图 — 三级奖励(推土机) vs PV 对碰(原子能) 协议级聚合
|
|
63
65
|
// 治理依据:根据两引擎实际拨付量决定费率/阈值/拨出率等调参方案
|
|
64
66
|
// 隐私第一:运营财务,仅 protocol admin 可见(详见 docs/REWARD-ENGINES-DECOUPLING.md)
|
|
65
|
-
app.get('/api/admin/economic-summary', (req, res) => {
|
|
67
|
+
app.get('/api/admin/economic-summary', async (req, res) => {
|
|
66
68
|
const admin = requireProtocolAdmin(req, res);
|
|
67
69
|
if (!admin)
|
|
68
70
|
return;
|
|
69
71
|
const r2 = (n) => Math.round(Number(n || 0) * 100) / 100;
|
|
70
72
|
// 引擎 A:三级奖励(commission_records 实际分账,按 level)
|
|
71
|
-
const commByLevel =
|
|
73
|
+
const commByLevel = await dbAll(`
|
|
72
74
|
SELECT level, COUNT(*) AS cnt, COALESCE(SUM(amount),0) AS total
|
|
73
75
|
FROM commission_records GROUP BY level
|
|
74
|
-
`)
|
|
76
|
+
`);
|
|
75
77
|
const engineA = { l1: { count: 0, total: 0 }, l2: { count: 0, total: 0 }, l3: { count: 0, total: 0 }, distributed_total: 0 };
|
|
76
78
|
for (const r of commByLevel) {
|
|
77
79
|
const k = `l${r.level}`;
|
|
@@ -83,15 +85,15 @@ export function registerAdminReportsRoutes(app, deps) {
|
|
|
83
85
|
engineA.distributed_total = r2(engineA.distributed_total);
|
|
84
86
|
// 2026-06-04 三科目解耦:引擎 A 所有 redirect 去向统一 → commission_pool(三级公池,只进不出)。
|
|
85
87
|
// charity_fund 自此纯净(仅捐款/还愿/拨款),不再承接佣金兜底。
|
|
86
|
-
const charity =
|
|
87
|
-
const cpool =
|
|
88
|
+
const charity = await dbOne(`SELECT balance, total_donated, total_disbursed, total_redirected FROM charity_fund WHERE id='main'`);
|
|
89
|
+
const cpool = await dbOne(`SELECT balance, total_chain_gap, total_orphan_sponsor, total_region_cap FROM commission_reserve WHERE id='main'`);
|
|
88
90
|
// 引擎 B:PV 对碰(binary_score_records 现金拨付 + 待拨 Score)
|
|
89
|
-
const binarySettled =
|
|
90
|
-
const binaryPending =
|
|
91
|
-
const periods =
|
|
92
|
-
const gfund =
|
|
91
|
+
const binarySettled = (await dbOne(`SELECT COUNT(*) AS cnt, COALESCE(SUM(waz_amount),0) AS waz FROM binary_score_records WHERE settled_at IS NOT NULL`));
|
|
92
|
+
const binaryPending = (await dbOne(`SELECT COUNT(*) AS cnt, COALESCE(SUM(score),0) AS score FROM binary_score_records WHERE settled_at IS NULL`));
|
|
93
|
+
const periods = (await dbOne(`SELECT COUNT(*) AS cnt, COALESCE(SUM(cash_distributed),0) AS dist, COALESCE(SUM(cash_retained),0) AS retained FROM settlement_periods WHERE status='completed'`));
|
|
94
|
+
const gfund = await dbOne(`SELECT pool_balance, total_scores_pending, current_n, pv_escrow_reserve FROM global_fund WHERE id=1`);
|
|
93
95
|
// 资金管道:global_fund 蓄水来源(fund_base 1% + commission region_cap redirect)
|
|
94
|
-
const pipe =
|
|
96
|
+
const pipe = (await dbOne(`SELECT COALESCE(SUM(amount_base),0) AS base, COALESCE(SUM(amount_l3),0) AS redirect FROM fund_deposits`));
|
|
95
97
|
res.json({
|
|
96
98
|
engine_a_commission: {
|
|
97
99
|
...engineA,
|
|
@@ -133,17 +135,17 @@ export function registerAdminReportsRoutes(app, deps) {
|
|
|
133
135
|
generated_at: new Date().toISOString(),
|
|
134
136
|
});
|
|
135
137
|
});
|
|
136
|
-
app.get('/api/admin/audit-log', (req, res) => {
|
|
138
|
+
app.get('/api/admin/audit-log', async (req, res) => {
|
|
137
139
|
const admin = requireProtocolAdmin(req, res);
|
|
138
140
|
if (!admin)
|
|
139
141
|
return;
|
|
140
|
-
const rows =
|
|
142
|
+
const rows = await dbAll(`
|
|
141
143
|
SELECT al.id, al.admin_id, al.action, al.target_type, al.target_id, al.detail, al.created_at,
|
|
142
144
|
u.name as admin_name
|
|
143
145
|
FROM admin_audit_log al
|
|
144
146
|
LEFT JOIN users u ON u.id = al.admin_id
|
|
145
147
|
ORDER BY al.created_at DESC LIMIT 50
|
|
146
|
-
`)
|
|
148
|
+
`);
|
|
147
149
|
res.json({
|
|
148
150
|
entries: rows.map(r => ({
|
|
149
151
|
...r,
|
|
@@ -1,33 +1,35 @@
|
|
|
1
|
+
import { dbOne, dbAll, dbRun } from '../../layer0-foundation/L0-1-database/db.js'; // RFC-016 异步 DB seam
|
|
1
2
|
export function registerAdminTokenomicsRoutes(app, deps) {
|
|
2
|
-
|
|
3
|
+
// db 已走 RFC-016 异步 seam(dbOne/dbAll/dbRun),不再直接用 deps.db
|
|
4
|
+
const { requireProtocolAdmin, logAdminAction } = deps;
|
|
3
5
|
// Tokenomics 详细数据 + Tier 配置 + 高额榜
|
|
4
|
-
app.get('/api/admin/tokenomics', (req, res) => {
|
|
6
|
+
app.get('/api/admin/tokenomics', async (req, res) => {
|
|
5
7
|
const admin = requireProtocolAdmin(req, res);
|
|
6
8
|
if (!admin)
|
|
7
9
|
return;
|
|
8
|
-
const tiers =
|
|
9
|
-
const topComm =
|
|
10
|
+
const tiers = await dbAll("SELECT * FROM binary_tier_config ORDER BY tier ASC");
|
|
11
|
+
const topComm = await dbAll(`
|
|
10
12
|
SELECT cr.beneficiary_id, u.name, COUNT(*) as records, COALESCE(SUM(cr.amount),0) as earned
|
|
11
13
|
FROM commission_records cr LEFT JOIN users u ON u.id = cr.beneficiary_id
|
|
12
14
|
WHERE cr.beneficiary_id != 'sys_protocol'
|
|
13
15
|
GROUP BY cr.beneficiary_id ORDER BY earned DESC LIMIT 10
|
|
14
|
-
`)
|
|
15
|
-
const topBinary =
|
|
16
|
+
`);
|
|
17
|
+
const topBinary = await dbAll(`
|
|
16
18
|
SELECT bsr.user_id, u.name,
|
|
17
19
|
COUNT(*) as hits,
|
|
18
20
|
COALESCE(SUM(CASE WHEN settled_at IS NOT NULL THEN waz_amount ELSE 0 END),0) as waz_total,
|
|
19
21
|
COALESCE(SUM(score),0) as score_total
|
|
20
22
|
FROM binary_score_records bsr LEFT JOIN users u ON u.id = bsr.user_id
|
|
21
23
|
GROUP BY bsr.user_id ORDER BY waz_total DESC LIMIT 10
|
|
22
|
-
`)
|
|
23
|
-
const gf =
|
|
24
|
-
const mb =
|
|
25
|
-
const pvLedger =
|
|
24
|
+
`);
|
|
25
|
+
const gf = await dbOne("SELECT * FROM global_fund WHERE id=1");
|
|
26
|
+
const mb = await dbOne("SELECT balance FROM management_bonus_pool WHERE id=1");
|
|
27
|
+
const pvLedger = await dbOne(`
|
|
26
28
|
SELECT COUNT(*) as total,
|
|
27
29
|
SUM(CASE WHEN processed=0 THEN 1 ELSE 0 END) as pending,
|
|
28
30
|
COALESCE(SUM(CASE WHEN processed=0 THEN pv ELSE 0 END),0) as pending_pv
|
|
29
31
|
FROM pv_ledger
|
|
30
|
-
`)
|
|
32
|
+
`);
|
|
31
33
|
res.json({
|
|
32
34
|
global_fund: gf,
|
|
33
35
|
management_bonus_pool: mb,
|
|
@@ -38,7 +40,7 @@ export function registerAdminTokenomicsRoutes(app, deps) {
|
|
|
38
40
|
});
|
|
39
41
|
});
|
|
40
42
|
// 调整 Tier 配置
|
|
41
|
-
app.post('/api/admin/tokenomics/tier', (req, res) => {
|
|
43
|
+
app.post('/api/admin/tokenomics/tier', async (req, res) => {
|
|
42
44
|
const admin = requireProtocolAdmin(req, res);
|
|
43
45
|
if (!admin)
|
|
44
46
|
return;
|
|
@@ -47,50 +49,49 @@ export function registerAdminTokenomicsRoutes(app, deps) {
|
|
|
47
49
|
return void res.json({ error: 'tier 无效' });
|
|
48
50
|
if (Number(pv_threshold) <= 0 || Number(score_per_hit) <= 0)
|
|
49
51
|
return void res.json({ error: '阈值/分数必须 > 0' });
|
|
50
|
-
|
|
51
|
-
.run(tier, Number(pv_threshold), Number(score_per_hit), active ? 1 : 0);
|
|
52
|
+
await dbRun(`INSERT OR REPLACE INTO binary_tier_config (tier, pv_threshold, score_per_hit, active) VALUES (?,?,?,?)`, [tier, Number(pv_threshold), Number(score_per_hit), active ? 1 : 0]);
|
|
52
53
|
logAdminAction(admin.id, 'tokenomics_tier_update', 'tier', String(tier), { pv_threshold, score_per_hit, active });
|
|
53
54
|
res.json({ success: true });
|
|
54
55
|
});
|
|
55
56
|
// 管理津贴资格列表 + 开关
|
|
56
|
-
app.get('/api/admin/tokenomics/mgmt-bonus', (req, res) => {
|
|
57
|
+
app.get('/api/admin/tokenomics/mgmt-bonus', async (req, res) => {
|
|
57
58
|
const admin = requireProtocolAdmin(req, res);
|
|
58
59
|
if (!admin)
|
|
59
60
|
return;
|
|
60
|
-
const enabled =
|
|
61
|
-
const eligible =
|
|
61
|
+
const enabled = (await dbOne("SELECT value FROM system_state WHERE key='mgmt_bonus_enabled'"))?.value === '1';
|
|
62
|
+
const eligible = await dbAll(`
|
|
62
63
|
SELECT u.id, u.name, u.created_at,
|
|
63
64
|
(SELECT COUNT(*) FROM users WHERE sponsor_id = u.id) as l1_count,
|
|
64
65
|
COALESCE((SELECT SUM(amount) FROM commission_records WHERE beneficiary_id = u.id),0) as total_commission
|
|
65
66
|
FROM users u WHERE u.mgmt_bonus_eligible = 1
|
|
66
67
|
ORDER BY u.created_at DESC LIMIT 100
|
|
67
|
-
`)
|
|
68
|
+
`);
|
|
68
69
|
res.json({ enabled, eligible_users: eligible, eligible_count: eligible.length });
|
|
69
70
|
});
|
|
70
71
|
// 注册必须 ref 开关
|
|
71
|
-
app.post('/api/admin/tokenomics/require-ref/toggle', (req, res) => {
|
|
72
|
+
app.post('/api/admin/tokenomics/require-ref/toggle', async (req, res) => {
|
|
72
73
|
const admin = requireProtocolAdmin(req, res);
|
|
73
74
|
if (!admin)
|
|
74
75
|
return;
|
|
75
76
|
const { enabled } = req.body;
|
|
76
77
|
const v = enabled ? '1' : '0';
|
|
77
|
-
|
|
78
|
+
await dbRun("INSERT OR REPLACE INTO system_state (key, value) VALUES ('require_ref_to_register', ?)", [v]);
|
|
78
79
|
logAdminAction(admin.id, 'require_ref_toggle', 'system', 'require_ref_to_register', { value: v });
|
|
79
80
|
res.json({ success: true, enabled: !!enabled });
|
|
80
81
|
});
|
|
81
82
|
// 管理津贴池开关
|
|
82
|
-
app.post('/api/admin/tokenomics/mgmt-bonus/toggle', (req, res) => {
|
|
83
|
+
app.post('/api/admin/tokenomics/mgmt-bonus/toggle', async (req, res) => {
|
|
83
84
|
const admin = requireProtocolAdmin(req, res);
|
|
84
85
|
if (!admin)
|
|
85
86
|
return;
|
|
86
87
|
const { enabled } = req.body;
|
|
87
88
|
const v = enabled ? '1' : '0';
|
|
88
|
-
|
|
89
|
+
await dbRun("INSERT OR REPLACE INTO system_state (key, value) VALUES ('mgmt_bonus_enabled', ?)", [v]);
|
|
89
90
|
logAdminAction(admin.id, 'mgmt_bonus_toggle', 'system', 'mgmt_bonus_enabled', { value: v });
|
|
90
91
|
res.json({ success: true, enabled: !!enabled });
|
|
91
92
|
});
|
|
92
93
|
// 池注资
|
|
93
|
-
app.post('/api/admin/tokenomics/inject', (req, res) => {
|
|
94
|
+
app.post('/api/admin/tokenomics/inject', async (req, res) => {
|
|
94
95
|
const admin = requireProtocolAdmin(req, res);
|
|
95
96
|
if (!admin)
|
|
96
97
|
return;
|
|
@@ -99,10 +100,10 @@ export function registerAdminTokenomicsRoutes(app, deps) {
|
|
|
99
100
|
if (!(n > 0))
|
|
100
101
|
return void res.json({ error: '金额必须 > 0' });
|
|
101
102
|
if (pool === 'global_fund') {
|
|
102
|
-
|
|
103
|
+
await dbRun("UPDATE global_fund SET pool_balance = pool_balance + ? WHERE id=1", [n]);
|
|
103
104
|
}
|
|
104
105
|
else if (pool === 'management_bonus') {
|
|
105
|
-
|
|
106
|
+
await dbRun("UPDATE management_bonus_pool SET balance = balance + ? WHERE id=1", [n]);
|
|
106
107
|
}
|
|
107
108
|
else {
|
|
108
109
|
return void res.json({ error: 'pool 名称无效(global_fund / management_bonus)' });
|