# EDU-026 — Activate native Mall Promotion coupons - **Status:** done — tenant-owned native coupon templates/instances, existing APIs/UI, RBAC, and PostgreSQL evidence delivered - **Type:** native module takeover / coupon lifecycle / tenant isolation - **Phase:** 5 / commercialization foundation - **Blockers:** EDU-025, PostgreSQL Flyway ## Problem RuoYi Vue Pro already provides coupon-template and issued-coupon controllers, services, Product-scope validation, Member lookup, registration issuance, expiry processing, permissions, and Vben pages. The Promotion server dependency was disabled and its two coupon records inherited only `BaseDO`, so reimplementing coupons inside Education would create a second marketing ledger without fixing tenant ownership. Legacy `public.coupons` are code-based campaign rules with plan/region restrictions, first-order rules, usage counters, and `coupon_redemptions`. Native Promotion coupons are templates that issue member-owned coupon instances before order use. They are not losslessly interchangeable. ## Delivered contract - `yudao-server` now activates `yudao-module-promotion` in addition to Product; Trade and Statistics remain disabled until their own ledger slices are verified. - Existing native `/promotion/coupon-template`, `/promotion/coupon`, `/app-api/promotion/coupon-template`, and `/app-api/promotion/coupon` contracts remain authoritative. Education adds no coupon controller or duplicate service. - `CouponTemplateDO` and `CouponDO` extend `TenantBaseDO`, so native mapper/service access participates in the framework tenant interceptor. - Native template creation reuses Product SPU/category validation. Native coupon administration reuses Member lookup, direct/admin/registration issuance, expiry processing, use/return, and soft-delete recovery rules. - Promotion's unrelated bargain/combination beans require `TradeOrderApi`. EDU-027 now activates the native Trade implementation and removes the temporary fail-closed adapter that was used while Trade was absent. - V4380 mounts the existing Vben template and issued-coupon pages below an Education `优惠券中心` using the original seven controller permissions and unique component names. ## Database contract V4380 creates tenant-scoped PostgreSQL tables: - `promotion_coupon_template` - `promotion_coupon` Both use `(tenant_id,id)` ownership keys and explicitly named identity sequences. Coupon → Template is a tenant-qualified composite foreign key, so an identifier valid in another tenant cannot be referenced. Checks enforce native status/take/scope/validity/discount enums, fixed-date or relative-term validity, non-negative thresholds and discounts, issue/use counter consistency, positive members/orders, and complete used-coupon state. Indexes support template discovery, member/status lookup, template issuance lookup, and expiry jobs. Existing global coupon tables fail closed instead of being silently assigned to a tenant. V4380 seeds menu IDs 6950–6959 for the coupon root, template page, issued-coupon page, and exact query/create/update/delete/send permissions. ## Legacy data decision V4380 starts the native coupon ledger empty. It does not reinterpret a legacy code campaign as a pre-issued member coupon, invent template/instance IDs, discard plan/region/first-order semantics, or attach historical redemptions to unverified native orders and members. A later compatibility/import slice must explicitly decide whether to preserve code redemption as a separate adapter or transform reviewed campaigns and redemption history. ## Verification - The Promotion coupon tenant contract proves both native coupon records inherit `TenantBaseDO`; EDU-027 separately verifies the native Trade dependency that replaced the temporary fallback. - The focused V4380 Flyway scenario passes and proves same IDs can exist across tenants, cross-tenant template references fail, invalid counters/discounts/used state fail, explicit sequences exist, exact menus/permissions are installed, and global-table adoption fails closed. - All 45 PostgreSQL Flyway integration tests pass. - `mvn -pl yudao-server -am -DskipTests compile` succeeds with Product and Promotion enabled. - `@vben/web-antd` typecheck and scoped Coupon oxlint/oxfmt checks pass. ## Explicitly open - Legacy code-campaign and redemption compatibility/import remains a separate mapping slice. - EDU-027 activates the tenant-scoped normal-order core. Coupon-to-special-order and refund composition still depend on deferred Promotion and Trade after-sale slices. - Discount/reward/seckill/combination/bargain/point/Diy/KeFu Promotion families are not activated at the database/menu level by this slice. - Target-environment role grants, browser/API smoke evidence, and deliberate template population remain operational work.