From 7bdcde479ca2bb4c5d9c74f216eb2b7de8a92a88 Mon Sep 17 00:00:00 2001 From: Javier Date: Sat, 4 Jul 2026 02:08:23 +0000 Subject: [PATCH 1/6] feat(marketplace): trusted install badge, package download, upvotes & community submit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the marketplace beyond publish/install: - Trusted source: catalog now exposes a `verified` flag (signature + registered publisher key + integrity hash) driving a "Verified" badge; install still re-verifies cryptographically. - Download: GET /extensions/:slug/download bumps download_count and 302s to the signed bundle (?redirect=0 returns metadata JSON). - Voting: POST/DELETE /extensions/:slug/vote — idempotent upvotes backed by a unique (userId, marketplaceSlug) index; catalog carries voteCount/hasVoted. - Community submit: POST /submit creates a global, unpublished `pending` listing; GET /submissions + POST /submissions/:id/review moderate it (extensions:configure). Schema: new extension_votes table + extensions.download_count / submission_status / submitted_by (migration 0043). Studio marketplace page and the public marketplace app get verified badges, vote controls, download buttons and a submit dialog. Also adds scripts/marketplace-submodule-migration.sh + docs to extract apps/marketplace into the lumibase-ai/marketplace submodule (run separately — this scope has no push access to that repo). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01UTMH25d9LHWBjF2z3Ys9Ha --- .../specs/admin-setup-wizard/setup-impact.md | 1 + .../__tests__/marketplace-catalog.test.ts | 60 ++- .../__tests__/marketplace-community.test.ts | 262 ++++++++++++ apps/cms/src/routes/marketplace.ts | 398 +++++++++++++++++- .../src/app/extensions/[slug]/page.tsx | 21 +- apps/marketplace/src/lib/api.ts | 7 + apps/marketplace/src/lib/types.ts | 4 + .../src/modules/settings/marketplace-page.tsx | 232 +++++++++- docs/en/features/marketplace.md | 57 ++- docs/en/marketplace-submodule-migration.md | 53 +++ .../0003_marketplace_votes_downloads.sql | 34 ++ packages/database/drizzle/meta/_journal.json | 7 + packages/database/src/schema/platform.ts | 40 ++ scripts/marketplace-submodule-migration.sh | 78 ++++ 14 files changed, 1221 insertions(+), 33 deletions(-) create mode 100644 apps/cms/src/routes/__tests__/marketplace-community.test.ts create mode 100644 docs/en/marketplace-submodule-migration.md create mode 100644 packages/database/drizzle/0003_marketplace_votes_downloads.sql create mode 100755 scripts/marketplace-submodule-migration.sh diff --git a/.kiro/specs/admin-setup-wizard/setup-impact.md b/.kiro/specs/admin-setup-wizard/setup-impact.md index 157185f2..49212d0f 100644 --- a/.kiro/specs/admin-setup-wizard/setup-impact.md +++ b/.kiro/specs/admin-setup-wizard/setup-impact.md @@ -88,6 +88,7 @@ Trạng thái: `pending` (chưa làm) · `in-progress` · `done` (setup + backfi | 33 | collection-create-modes | v0.9.x (proposal) | Bước chọn chế độ tạo collection (View / DB View / Flexible View) + Default_Field_Catalogue + Localize_Dropdown dùng chung. View_Mode không cần khởi tạo. DB/Flexible mode đề xuất 2 cột mới `collections.read_only`/`source_object` | pending | [collection-create-modes/tasks.md](../collection-create-modes/tasks.md) Phase 5.1 | Rà soát 2026-06-29 (PROPOSAL, chưa code). (1) Có thể cần seed `localize` field type khi nền tảng field-localization xong (chờ ADR). (2) Localize_Dropdown đọc Tenant_Locales từ feature #34 — chưa có nguồn truth chính thức (fallback `['en','vi']` hard-code hiện tại). (4) Bước UI mới = mode selector TRƯỚC wizard (không thuộc setup wizard). (6) DB/Flexible mode cần migration thủ công 2 cột (`read_only`,`source_object`) → backfill default an toàn (`false`/`null`); View_Mode KHÔNG migration. Phụ thuộc #34, #35 | | 34 | tenant-localization-config | v0.9.x (proposal) | Nguồn truth Tenant_Locales (khuyến nghị `settings.key='locales'`) + UI Settings → Languages + sửa Admin_Path. Lấp GAP: hiện không có bảng/API available-locales, `settings.get('locales')` fallback hard-code `['en','vi']` | pending | [tenant-localization-config/tasks.md](../tenant-localization-config/tasks.md) Phase 5.1 | Rà soát 2026-06-29 (PROPOSAL, chưa code). (1) Setup KHỞI TẠO `settings.locales=[default_language]` khi xong (Req 4.2). (2) Settings key `locales` mới — operator cần biết. (4) Tùy chọn thêm bước "ngôn ngữ" vào setup wizard; nếu không thì default `[default_language]`. (6) Nếu dùng `settings` (khuyến nghị) → KHÔNG migration; instance cũ thiếu key → fallback `[default_language]`. Admin_Path từ `/setup/path` thành giá trị sửa-được. Phụ thuộc lẫn nhau với #33 | | 35 | db-view-introspection | v0.9.x (proposal) | Endpoint introspection DB (`/db/objects`, `/collections/:name/introspect`) + chấm than (⚠) cho Uncatalogued_Field + bootstrap-on-click tạo record `fields`. Lấp GAP: hiện không có introspection, field chỉ đọc từ bảng `fields` | pending | [db-view-introspection/tasks.md](../db-view-introspection/tasks.md) Phase 5.1 | Rà soát 2026-06-29 (PROPOSAL, chưa code). (1) KHÔNG seed. (2) KHÔNG settings key. (3) Quyền dùng = quyền quản trị schema sẵn có; bootstrap qua agent cần HITL `ai_approvals` (rule #4). (4) KHÔNG bước setup wizard mới. (5) Có thể cần capability flag báo runtime hỗ trợ introspection. (6) KHÔNG bảng mới của riêng nó (đọc `information_schema`/`PRAGMA`); dùng chung 2 cột với #33. Adapter introspect qua runtime abstraction (rule #3). Phụ thuộc #33 | +| 36 | (marketplace community: install-trust/download/vote/submit) | v0.16.x | Đã rà soát: mở rộng marketplace — badge `verified` (trusted source: signature + publisher key + hash) trên catalog, nút download package (`GET /extensions/:slug/download`, bump `downloadCount`, 302 → bundle), upvote (`POST`/`DELETE /extensions/:slug/vote`, idempotent qua unique `(userId, marketplaceSlug)`), community submit (`POST /submit` → row global `pending`/unpublished) + moderation (`GET /submissions`, `POST /submissions/:id/review` cần `extensions:configure`). Thêm cột `extensions.download_count`/`submission_status`/`submitted_by` + bảng mới `extension_votes` (migration `0003_marketplace_votes_downloads`) | n/a | — | Rà soát 2026-07-04. (1) KHÔNG seed: votes/submissions tạo theo nhu cầu; `download_count` mặc định 0. (2) KHÔNG feature-flag/settings key mới. (3) KHÔNG policy/grant DB mới — vote/submit chỉ cần `withAuth` (user đã đăng nhập); moderation dùng lại capability `extensions:configure` sẵn có (không role mặc định nào cần bổ sung ngoài admin đã có). (4) KHÔNG bước UI wizard mới — thao tác ở Studio → Marketplace / site công khai sau setup. (5) KHÔNG capability `/setup/capabilities` mới. (6) KHÔNG cần backfill dữ liệu: migration `0003` chỉ `ADD COLUMN` (có default `0`/nullable) + `CREATE TABLE extension_votes` (forward-only qua journal); instance cũ nhận `download_count=0`, bảng votes rỗng, listing chưa ký hiện `verified=false`. **Submodule move** của `apps/marketplace` → `lumibase-ai/marketplace` là thao tác git thuần (script `scripts/marketplace-submodule-migration.sh`), KHÔNG ảnh hưởng setup/DB | | 37 | (security hardening: file upload) | v0.17.x | Đã rà soát: mở rộng `withFileUploadPolicy` để phủ luôn `POST /api/v1/media/:key` (trước đây chỉ phủ `/files`): chặn public role đẩy bytes, cap size theo bytes THẬT (không chỉ `Content-Length`), allowlist MIME, đối chiếu đuôi↔MIME, content-sniff magic bytes, và chặn SVG chứa mã động (`