Files
goodgo-platform/scripts/seed-plans.ts
Ho Ngoc Hai cc5c81904b fix(lint): resolve all 49 lint warnings and errors across codebase
- Remove unused imports/variables in seed scripts and test files
- Replace console.log with console.warn in seed/utility scripts
- Replace `as any` with proper Prisma types (InputJsonValue, PaymentStatus, Plan, UserWhereInput)
- Fix import-x/no-named-as-default-member warnings in logger, mapbox, eslint config
- Prefix unused callback params with underscore in e2e tests

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-08 13:22:07 +07:00

134 lines
3.2 KiB
TypeScript

/**
* Seed subscription plans (FREE, AGENT_PRO, INVESTOR, ENTERPRISE).
*
* Usage: npx tsx scripts/seed-plans.ts
* Idempotent: uses upsert on PlanTier unique constraint.
*/
import { PrismaPg } from '@prisma/adapter-pg';
import { PrismaClient, PlanTier } from '@prisma/client';
import pg from 'pg';
const pool = new pg.Pool({ connectionString: process.env['DATABASE_URL'] });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });
export const PLANS = [
{
tier: PlanTier.FREE,
name: 'Miễn phí',
priceMonthlyVND: BigInt(0),
priceYearlyVND: BigInt(0),
maxListings: 3,
maxSavedSearches: 5,
features: {
basicSearch: true,
listingPost: true,
maxPhotos: 5,
analytics: false,
prioritySupport: false,
aiValuation: false,
featuredListing: false,
},
},
{
tier: PlanTier.AGENT_PRO,
name: 'Agent Pro',
priceMonthlyVND: BigInt(499_000),
priceYearlyVND: BigInt(4_990_000),
maxListings: 50,
maxSavedSearches: 30,
features: {
basicSearch: true,
listingPost: true,
maxPhotos: 30,
analytics: true,
prioritySupport: true,
aiValuation: true,
featuredListing: true,
leadManagement: true,
agentProfile: true,
},
},
{
tier: PlanTier.INVESTOR,
name: 'Investor',
priceMonthlyVND: BigInt(999_000),
priceYearlyVND: BigInt(9_990_000),
maxListings: 20,
maxSavedSearches: 100,
features: {
basicSearch: true,
listingPost: true,
maxPhotos: 15,
analytics: true,
prioritySupport: true,
aiValuation: true,
featuredListing: false,
marketReports: true,
priceAlerts: true,
portfolioTracking: true,
},
},
{
tier: PlanTier.ENTERPRISE,
name: 'Enterprise',
priceMonthlyVND: BigInt(4_990_000),
priceYearlyVND: BigInt(49_900_000),
maxListings: null,
maxSavedSearches: null,
features: {
basicSearch: true,
listingPost: true,
maxPhotos: 100,
analytics: true,
prioritySupport: true,
aiValuation: true,
featuredListing: true,
leadManagement: true,
agentProfile: true,
marketReports: true,
priceAlerts: true,
portfolioTracking: true,
apiAccess: true,
whiteLabel: true,
dedicatedSupport: true,
},
},
];
async function seedPlans() {
console.warn('Seeding subscription plans...\n');
for (const plan of PLANS) {
const _result = await prisma.plan.upsert({
where: { tier: plan.tier },
update: {
name: plan.name,
priceMonthlyVND: plan.priceMonthlyVND,
priceYearlyVND: plan.priceYearlyVND,
maxListings: plan.maxListings,
maxSavedSearches: plan.maxSavedSearches,
features: plan.features,
},
create: plan,
});
const monthly = Number(plan.priceMonthlyVND).toLocaleString('vi-VN');
console.warn(` ${plan.tier.padEnd(12)} ${plan.name.padEnd(14)} ${monthly} VND/tháng`);
}
console.warn(`\n${PLANS.length} plans seeded.`);
}
if (require.main === module) {
seedPlans()
.catch((e) => {
console.error('Seed plans failed:', e);
process.exit(1);
})
.finally(() => prisma.$disconnect());
}
export { seedPlans };