chore: relocate backend into apps/api ahead of monorepo merge

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-24 12:20:40 +08:00
co-authored by Claude Sonnet 5
parent af44598df6
commit eaa6d2276a
388 changed files with 0 additions and 13998 deletions
@@ -0,0 +1,38 @@
'use strict';
// Tier Plans v2: item-specific entitlement means two DIFFERENT plans at the
// SAME tier slug (e.g. two separate Premium bundles) must be able to stay
// concurrently active for one user, each governing its own distinct
// user_tier_grants snapshot — buying a second Premium bundle must not just
// extend the first one's expiry (see captureOrder in
// controllers/client/tiers.controller.js).
//
// The old partial unique index (20270101000075) enforced "one active row per
// (user_id, tier)", which blocks that. Replace it with "one active row per
// (user_id, plan_id)" — still prevents accidentally double-purchasing/
// double-granting the exact same plan concurrently, but allows multiple
// plans at the same tier to coexist. NULL plan_id rows (admin-granted
// tiers with no backing plan) are never considered equal to one another by
// a unique index, so they're unaffected.
//
// NOT auto-run — do not execute against the shared dev/prod database without
// explicit confirmation.
module.exports = {
async up(queryInterface) {
await queryInterface.removeIndex('user_tiers', 'user_tiers_one_active_per_user_tier');
await queryInterface.addIndex('user_tiers', ['user_id', 'plan_id'], {
unique: true,
where: { status: 'active' },
name: 'user_tiers_one_active_per_user_plan',
});
},
async down(queryInterface) {
await queryInterface.removeIndex('user_tiers', 'user_tiers_one_active_per_user_plan');
await queryInterface.addIndex('user_tiers', ['user_id', 'tier'], {
unique: true,
where: { status: 'active' },
name: 'user_tiers_one_active_per_user_tier',
});
},
};