- Reorganized admin settings into tabbed interface (General, Security, Payment Methods) - Vertical tabs on desktop, horizontal scrollable on mobile - Moved Payment Methods from separate menu to Settings tab - Fixed admin profile reuse and dashboard blocking - Fixed maintenance mode guard to use AppConfig model - Added admin auto-redirect after login (admins → /admin, users → /) - Reorganized documentation into docs/ folder structure - Created comprehensive README and documentation index - Added PWA and Web Push notifications to to-do list
304 lines
10 KiB
JavaScript
304 lines
10 KiB
JavaScript
"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 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: {},
|
||
create: {
|
||
id: TEMP_USER_ID,
|
||
email: 'temp@example.com',
|
||
},
|
||
});
|
||
const existing = await prisma.wallet.findFirst({});
|
||
if (!existing) {
|
||
await prisma.wallet.create({
|
||
data: {
|
||
userId: user.id,
|
||
kind: 'money',
|
||
name: 'Cash',
|
||
currency: 'IDR',
|
||
},
|
||
});
|
||
}
|
||
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) => {
|
||
console.error(e);
|
||
process.exit(1);
|
||
})
|
||
.finally(async () => {
|
||
await prisma.$disconnect();
|
||
});
|
||
//# sourceMappingURL=seed.js.map
|