feat: add admin dashboard schema and seeder
- Add Plan, Subscription, Payment, PaymentMethod, Coupon models - Add ApiKey, Webhook models for API access - Add AppConfig model for dynamic configuration - Add role, suspendedAt fields to User model - Create comprehensive seeder with: - Admin user (dwindi.ramadhana@gmail.com) - Default plans (Free, Pro Monthly, Pro Yearly) - Payment methods (BCA, Mandiri, GoPay) - App config (maintenance mode) - Zero data loss migration strategy
This commit is contained in:
238
apps/api/dist/seed.js
vendored
238
apps/api/dist/seed.js
vendored
@@ -1,13 +1,233 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const client_1 = require("@prisma/client");
|
||||
const bcrypt = __importStar(require("bcrypt"));
|
||||
const prisma = new client_1.PrismaClient();
|
||||
const adminSeeder = {
|
||||
email: 'dwindi.ramadhana@gmail.com',
|
||||
password: 'tabungin2k25!@#',
|
||||
};
|
||||
const TEMP_USER_ID = process.env.TEMP_USER_ID || '16b74848-daa3-4dc9-8de2-3cf59e08f8e3';
|
||||
const ADMIN_EMAIL = 'dwindi.ramadhana@gmail.com';
|
||||
const ADMIN_PASSWORD = 'tabungin2k25!@#';
|
||||
async function main() {
|
||||
console.log('🌱 Starting seed...');
|
||||
console.log('\n👤 Creating admin user...');
|
||||
const passwordHash = await bcrypt.hash(ADMIN_PASSWORD, 10);
|
||||
const admin = await prisma.user.upsert({
|
||||
where: { email: ADMIN_EMAIL },
|
||||
update: {
|
||||
role: 'admin',
|
||||
passwordHash,
|
||||
emailVerified: true,
|
||||
},
|
||||
create: {
|
||||
email: ADMIN_EMAIL,
|
||||
passwordHash,
|
||||
name: 'Dwindi Ramadhana',
|
||||
role: 'admin',
|
||||
emailVerified: true,
|
||||
},
|
||||
});
|
||||
console.log('✅ Admin user created:', admin.email);
|
||||
console.log('\n💰 Creating default plans...');
|
||||
const freePlan = await prisma.plan.upsert({
|
||||
where: { slug: 'free' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Free',
|
||||
slug: 'free',
|
||||
description: 'Perfect for getting started',
|
||||
price: 0,
|
||||
currency: 'IDR',
|
||||
durationType: 'lifetime',
|
||||
durationDays: null,
|
||||
trialDays: 0,
|
||||
features: {
|
||||
wallets: { limit: 5, label: '5 wallets' },
|
||||
goals: { limit: 3, label: '3 goals' },
|
||||
team: { enabled: false, label: 'No team feature' },
|
||||
api: { enabled: false, label: 'No API access' },
|
||||
support: { level: 'basic', label: 'Basic support' },
|
||||
export: { enabled: true, formats: ['csv'], label: 'CSV export' },
|
||||
},
|
||||
badge: null,
|
||||
sortOrder: 1,
|
||||
isActive: true,
|
||||
isVisible: true,
|
||||
isFeatured: false,
|
||||
maxWallets: 5,
|
||||
maxGoals: 3,
|
||||
maxTeamMembers: 0,
|
||||
apiEnabled: false,
|
||||
apiRateLimit: null,
|
||||
},
|
||||
});
|
||||
const proMonthly = await prisma.plan.upsert({
|
||||
where: { slug: 'pro-monthly' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Pro Monthly',
|
||||
slug: 'pro-monthly',
|
||||
description: 'Perfect for individuals and small teams',
|
||||
price: 49000,
|
||||
currency: 'IDR',
|
||||
durationType: 'monthly',
|
||||
durationDays: 30,
|
||||
trialDays: 7,
|
||||
features: {
|
||||
wallets: { limit: null, label: 'Unlimited wallets' },
|
||||
goals: { limit: null, label: 'Unlimited goals' },
|
||||
team: { enabled: true, maxMembers: 10, label: 'Team feature (10 members)' },
|
||||
api: { enabled: true, rateLimit: 1000, label: 'API access (1000 req/hr)' },
|
||||
support: { level: 'priority', label: 'Priority support' },
|
||||
export: { enabled: true, formats: ['csv', 'excel', 'pdf'], label: 'All export formats' },
|
||||
},
|
||||
badge: 'Popular',
|
||||
badgeColor: 'blue',
|
||||
highlightColor: '#3B82F6',
|
||||
sortOrder: 2,
|
||||
isActive: true,
|
||||
isVisible: true,
|
||||
isFeatured: true,
|
||||
maxWallets: null,
|
||||
maxGoals: null,
|
||||
maxTeamMembers: 10,
|
||||
apiEnabled: true,
|
||||
apiRateLimit: 1000,
|
||||
},
|
||||
});
|
||||
const proYearly = await prisma.plan.upsert({
|
||||
where: { slug: 'pro-yearly' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Pro Yearly',
|
||||
slug: 'pro-yearly',
|
||||
description: 'Best value - Save 17% with annual billing',
|
||||
price: 490000,
|
||||
currency: 'IDR',
|
||||
durationType: 'yearly',
|
||||
durationDays: 365,
|
||||
trialDays: 7,
|
||||
features: {
|
||||
wallets: { limit: null, label: 'Unlimited wallets' },
|
||||
goals: { limit: null, label: 'Unlimited goals' },
|
||||
team: { enabled: true, maxMembers: 10, label: 'Team feature (10 members)' },
|
||||
api: { enabled: true, rateLimit: 1000, label: 'API access (1000 req/hr)' },
|
||||
support: { level: 'priority', label: 'Priority support' },
|
||||
export: { enabled: true, formats: ['csv', 'excel', 'pdf'], label: 'All export formats' },
|
||||
discount: { value: '17%', label: 'Save 17% (2 months free)' },
|
||||
},
|
||||
badge: 'Best Value',
|
||||
badgeColor: 'green',
|
||||
highlightColor: '#10B981',
|
||||
sortOrder: 3,
|
||||
isActive: true,
|
||||
isVisible: true,
|
||||
isFeatured: true,
|
||||
maxWallets: null,
|
||||
maxGoals: null,
|
||||
maxTeamMembers: 10,
|
||||
apiEnabled: true,
|
||||
apiRateLimit: 1000,
|
||||
},
|
||||
});
|
||||
console.log('✅ Plans created:', [freePlan.name, proMonthly.name, proYearly.name]);
|
||||
console.log('\n💳 Creating default payment methods...');
|
||||
const bcaMethod = await prisma.paymentMethod.upsert({
|
||||
where: { id: 'bca-method' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'bca-method',
|
||||
type: 'bank_transfer',
|
||||
provider: 'BCA',
|
||||
accountName: 'PT Tabungin Indonesia',
|
||||
accountNumber: '1234567890',
|
||||
displayName: 'BCA Virtual Account',
|
||||
logoUrl: '/logos/bca.png',
|
||||
instructions: 'Transfer to the account above and upload proof of payment.',
|
||||
isActive: true,
|
||||
sortOrder: 1,
|
||||
},
|
||||
});
|
||||
const mandiriMethod = await prisma.paymentMethod.upsert({
|
||||
where: { id: 'mandiri-method' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'mandiri-method',
|
||||
type: 'bank_transfer',
|
||||
provider: 'Mandiri',
|
||||
accountName: 'PT Tabungin Indonesia',
|
||||
accountNumber: '9876543210',
|
||||
displayName: 'Mandiri Virtual Account',
|
||||
logoUrl: '/logos/mandiri.png',
|
||||
instructions: 'Transfer to the account above and upload proof of payment.',
|
||||
isActive: true,
|
||||
sortOrder: 2,
|
||||
},
|
||||
});
|
||||
const gopayMethod = await prisma.paymentMethod.upsert({
|
||||
where: { id: 'gopay-method' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'gopay-method',
|
||||
type: 'e-wallet',
|
||||
provider: 'GoPay',
|
||||
accountName: 'Dwindi Ramadhana',
|
||||
accountNumber: '081234567890',
|
||||
displayName: 'GoPay',
|
||||
logoUrl: '/logos/gopay.png',
|
||||
instructions: 'Send payment to the number above and upload proof.',
|
||||
isActive: true,
|
||||
sortOrder: 3,
|
||||
},
|
||||
});
|
||||
console.log('✅ Payment methods created:', [bcaMethod.displayName, mandiriMethod.displayName, gopayMethod.displayName]);
|
||||
console.log('\n⚙️ Creating app config...');
|
||||
await prisma.appConfig.upsert({
|
||||
where: { key: 'MAINTENANCE_MODE' },
|
||||
update: {},
|
||||
create: {
|
||||
key: 'MAINTENANCE_MODE',
|
||||
value: 'false',
|
||||
category: 'general',
|
||||
label: 'Maintenance Mode',
|
||||
description: 'Enable to show maintenance page to users',
|
||||
type: 'boolean',
|
||||
isSecret: false,
|
||||
},
|
||||
});
|
||||
console.log('✅ App config created');
|
||||
console.log('\n🔧 Creating temp user (legacy)...');
|
||||
const user = await prisma.user.upsert({
|
||||
where: { id: TEMP_USER_ID },
|
||||
update: {},
|
||||
@@ -27,7 +247,15 @@ async function main() {
|
||||
},
|
||||
});
|
||||
}
|
||||
console.log('Seed complete. TEMP_USER_ID=', user.id);
|
||||
console.log('✅ Temp user created:', user.id);
|
||||
console.log('\n🎉 Seed complete!');
|
||||
console.log('\n📋 Summary:');
|
||||
console.log(' Admin Email:', ADMIN_EMAIL);
|
||||
console.log(' Admin Password:', ADMIN_PASSWORD);
|
||||
console.log(' Plans:', [freePlan.name, proMonthly.name, proYearly.name].join(', '));
|
||||
console.log(' Payment Methods:', [bcaMethod.displayName, mandiriMethod.displayName, gopayMethod.displayName].join(', '));
|
||||
console.log('\n⚠️ IMPORTANT: Change admin password after first login!');
|
||||
console.log('\n🔗 Login at: http://localhost:5174/auth/login');
|
||||
}
|
||||
main()
|
||||
.catch((e) => {
|
||||
|
||||
Reference in New Issue
Block a user