pivot: migrate V1 mobile from Docker to Netlify serverless

- Switch Prisma schema from SQLite to PostgreSQL
- Add netlify.toml for Netlify deployment config
- Add @netlify/plugin-nextjs for serverless Next.js
- Remove Docker build files (Dockerfile, docker-compose, start.sh)
- Remove auto-healer and scripts directories
- Update next.config.ts (remove standalone output)
- Database: falah_mobile_v1 on Contabo Postgres
This commit is contained in:
2026-06-28 23:02:48 +02:00
parent 5b08f8b041
commit a1c5fecd83
117 changed files with 8619 additions and 2837 deletions
+305
View File
@@ -0,0 +1,305 @@
/**
* seed-data.mjs — Seed V1 Mobile SQLite DB with courses, forum, and Islamic finance data
* Idempotent: safe to run multiple times (upserts/checks before creating)
* Run via: docker cp seed-data.mjs falah_falah-mobile.X:/app/data/ && docker exec falah_falah-mobile.X node /app/data/seed-data.mjs
*/
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
const DEMO_EMAIL = "demo@falahos.my";
async function seed() {
console.log("🌱 Starting V1 Mobile seed...");
// ═══════════════════════════════════════════
// 1. FORUM CATEGORIES
// ═══════════════════════════════════════════
const categories = [
{ name: "General Discussion", description: "General Islamic discussions and community topics", icon: "MessageSquare", order: 1 },
{ name: "Quran & Hadith", description: "Study and discussion of Quranic verses and hadith", icon: "BookOpen", order: 2 },
{ name: "Fiqh & Rulings", description: "Islamic jurisprudence and daily rulings", icon: "Scale", order: 3 },
{ name: "Family & Marriage", description: "Family relationships, marriage, and parenting in Islam", icon: "Heart", order: 4 },
{ name: "Finance & Economy", description: "Islamic finance, halal investing, and economic topics", icon: "TrendingUp", order: 5 },
{ name: "Announcements", description: "Official Falah platform announcements", icon: "Megaphone", order: 0 },
];
let categoryIds = {};
for (const cat of categories) {
const existing = await prisma.forumCategory.findUnique({ where: { name: cat.name } });
if (existing) {
categoryIds[cat.name] = existing.id;
console.log(` ️ Forum category "${cat.name}" already exists (id: ${existing.id})`);
} else {
const created = await prisma.forumCategory.create({ data: cat });
categoryIds[cat.name] = created.id;
console.log(` ✅ Created forum category: "${cat.name}"`);
}
}
// ═══════════════════════════════════════════
// 2. DEMO USER (ensure exists with proper balance)
// ═══════════════════════════════════════════
let demoUser = await prisma.user.findUnique({ where: { email: DEMO_EMAIL } });
if (!demoUser) {
demoUser = await prisma.user.create({
data: {
email: DEMO_EMAIL,
name: "Demo User",
flhBalance: 100000,
isPremium: true,
isPro: true,
},
});
console.log(` ✅ Created demo user: ${DEMO_EMAIL} (id: ${demoUser.id})`);
} else {
// Update premium status and balance
demoUser = await prisma.user.update({
where: { email: DEMO_EMAIL },
data: { flhBalance: 100000, isPremium: true, isPro: true },
});
console.log(` ️ Demo user exists: balance=${demoUser.flhBalance}, premium=${demoUser.isPremium}`);
}
// ═══════════════════════════════════════════
// 3. FORUM THREADS
// ═══════════════════════════════════════════
const threads = [
{
title: "Welcome to Falah Community!",
content: "Assalamu alaikum! Welcome to our community forum. This is a place for meaningful discussions, seeking knowledge, and supporting one another. Please introduce yourself!",
category: "General Discussion",
pinned: true,
},
{
title: "The Importance of Daily Dhikr",
content: "Seeking reminders on the importance of daily remembrance of Allah. What are your favorite adhkar and how do you maintain consistency?",
category: "General Discussion",
pinned: false,
},
{
title: "Tips for Memorizing Juz Amma",
content: "I have started memorizing Juz Amma and would love to hear tips and techniques that worked for others. Jazakum Allah khair!",
category: "Quran & Hadith",
pinned: false,
},
{
title: "Ruling on Cryptocurrency in Islam",
content: "Assalamu alaikum, I would like to understand the Islamic ruling on cryptocurrency trading. Is it considered halal? What do the scholars say about Bitcoin and other digital assets?",
category: "Fiqh & Rulings",
pinned: false,
},
{
title: "Strengthening Family Bonds in Islam",
content: "How do we strengthen our family relationships according to Islamic teachings? Looking for practical advice on being better spouses and parents.",
category: "Family & Marriage",
pinned: false,
},
];
for (const t of threads) {
const catId = categoryIds[t.category];
if (!catId) continue;
// Check if a thread with this title already exists
const existing = await prisma.forumThread.findFirst({ where: { title: t.title } });
if (existing) {
console.log(` ️ Forum thread "${t.title}" already exists`);
continue;
}
await prisma.forumThread.create({
data: {
title: t.title,
content: t.content,
categoryId: catId,
authorId: demoUser.id,
pinned: t.pinned,
shariahStatus: "approved",
},
});
console.log(` ✅ Created forum thread: "${t.title}"`);
}
// ═══════════════════════════════════════════
// 4. LEARN COURSES
// ═══════════════════════════════════════════
const courses = [
{
slug: "intro-islamic-finance",
title: "Introduction to Islamic Finance",
author: "Falah Academy",
description: "Learn the fundamentals of Islamic finance including the prohibition of riba (interest), the principles of halal investing, and the key contracts used in Islamic banking and finance.",
difficulty: "beginner",
published: true,
moduleCount: 4,
totalMinutes: 30,
giteaPath: "courses/intro-islamic-finance",
},
{
slug: "zakat-made-easy",
title: "Zakat Made Easy",
author: "Falah Academy",
description: "A comprehensive guide to understanding and calculating Zakat. Learn about nisab thresholds, different types of wealth, and how to fulfill this important pillar of Islam.",
difficulty: "beginner",
subscriptionOnly: false,
published: true,
moduleCount: 5,
totalMinutes: 40,
giteaPath: "courses/zakat-made-easy",
},
{
slug: "fiqh-of-salah",
title: "Fiqh of Salah",
author: "Falah Academy",
description: "A detailed study of the Islamic prayer (salah) according to the Quran and Sunnah. Covers conditions, pillars, obligations, and common mistakes in prayer.",
difficulty: "intermediate",
published: true,
moduleCount: 6,
totalMinutes: 50,
giteaPath: "courses/fiqh-of-salah",
},
{
slug: "waqf-endowment-guide",
title: "Waqf Endowment Guide",
author: "Falah Academy",
description: "Understand the concept of Waqf (Islamic endowment) and how to set up perpetual charitable endowments that generate ongoing rewards.",
difficulty: "intermediate",
published: true,
moduleCount: 3,
totalMinutes: 25,
giteaPath: "courses/waqf-endowment-guide",
},
{
slug: "sadaqah-and-community",
title: "Sadaqah & Community Giving",
author: "Falah Academy",
description: "Explore the virtues of voluntary charity (sadaqah) in Islam and learn how to make the most impact through strategic community giving.",
difficulty: "beginner",
published: true,
moduleCount: 3,
totalMinutes: 20,
giteaPath: "courses/sadaqah-and-community",
},
];
for (const course of courses) {
const existing = await prisma.learnCourse.findUnique({ where: { slug: course.slug } });
if (existing) {
console.log(` ️ Course "${course.title}" already exists`);
continue;
}
await prisma.learnCourse.create({ data: course });
console.log(` ✅ Created course: "${course.title}"`);
}
// ═══════════════════════════════════════════
// 5. AUTO-ENROLL DEMO USER IN ALL COURSES
// ═══════════════════════════════════════════
const allCourses = await prisma.learnCourse.findMany({ where: { published: true } });
for (const course of allCourses) {
const existing = await prisma.learnEnrollment.findUnique({
where: { userId_courseId: { userId: demoUser.id, courseId: course.id } },
});
if (!existing) {
await prisma.learnEnrollment.create({
data: {
userId: demoUser.id,
courseId: course.id,
purchaseType: "free",
},
});
console.log(` ✅ Enrolled demo user in course: \"${course.title}\"`);
} else {
console.log(` ️ Demo already enrolled in: \"${course.title}\"`);
}
}
// ═══════════════════════════════════════════
// 6. LEARN MODULES (for each course)
// ═══════════════════════════════════════════
const modules = {
"intro-islamic-finance": [
{ slug: "what-is-riba", title: "What is Riba?", keyTakeaway: "Riba (interest) is strictly prohibited in Islam. Understand the different types and why it matters.", duration: 8 },
{ slug: "halal-investing", title: "Halal Investing Principles", keyTakeaway: "Investments must avoid riba, gharar (excessive uncertainty), and haram industries.", duration: 7 },
{ slug: "islamic-contracts", title: "Islamic Contracts Overview", keyTakeaway: "Key contracts include Murabaha (cost-plus), Musharakah (partnership), and Ijarah (leasing).", duration: 8 },
{ slug: "modern-fintech", title: "Modern Islamic Fintech", keyTakeaway: "Technology is making Islamic finance more accessible through digital wallets, tokenization, and smart contracts.", duration: 7 },
],
"zakat-made-easy": [
{ slug: "what-is-zakat", title: "What is Zakat?", keyTakeaway: "Zakat is the third pillar of Islam — an obligatory charity on wealth that meets nisab threshold.", duration: 8 },
{ slug: "calculating-nisab", title: "Calculating Nisab", keyTakeaway: "Nisab is the minimum amount of wealth before Zakat is due, equivalent to 85g of gold or 595g of silver.", duration: 8 },
{ slug: "types-of-wealth", title: "Types of Zakatable Wealth", keyTakeaway: "Zakat applies to cash, gold/silver, business inventory, agricultural produce, livestock, and investments.", duration: 8 },
{ slug: "zakat-calculation", title: "Calculating Your Zakat", keyTakeaway: "Zakat is 2.5% of qualifying wealth held for one lunar year (hawl).", duration: 8 },
{ slug: "distributing-zakat", title: "Distributing Your Zakat", keyTakeaway: "Zakat must be given to 8 eligible categories, prioritizing local needs.", duration: 8 },
],
"fiqh-of-salah": [
{ slug: "conditions-of-salah", title: "Conditions of Salah", keyTakeaway: "Salah has 9 preconditions including purity, facing qibla, and proper covering.", duration: 8 },
{ slug: "pillars-of-salah", title: "Pillars of Salah", keyTakeaway: "The 14 pillars of salah are essential — missing any invalidates the prayer.", duration: 8 },
{ slug: "obligations-of-salah", title: "Obligations of Salah", keyTakeaway: "The wajibaat (obligatory acts) of salah must be performed; intentional omission requires sujud al-sahw.", duration: 8 },
{ slug: "sunnah-practices", title: "Sunnah Practices", keyTakeaway: "Following the sunnah practices of the Prophet ﷺ in salah increases reward and perfects the prayer.", duration: 9 },
{ slug: "common-mistakes", title: "Common Mistakes in Salah", keyTakeaway: "Common errors include rushing, incorrect recitation, and improper movements — learn to avoid them.", duration: 9 },
{ slug: "congregational-prayer", title: "Congregational Prayer", keyTakeaway: "Praying in congregation (jama'ah) is 27 times more rewarding than praying alone.", duration: 8 },
],
"waqf-endowment-guide": [
{ slug: "what-is-waqf", title: "What is Waqf?", keyTakeaway: "Waqf is a perpetual charitable endowment where the principal is preserved and benefits are continuously given.", duration: 8 },
{ slug: "types-of-waqf", title: "Types of Waqf", keyTakeaway: "Waqf can be for family (waqf dhurri), charitable (waqf khayri), or combined purposes.", duration: 8 },
{ slug: "digital-waqf", title: "Waqf in the Digital Age", keyTakeaway: "Digital waqf allows perpetual endowments using FLH tokens with automated yield distribution.", duration: 9 },
],
"sadaqah-and-community": [
{ slug: "virtue-of-sadaqah", title: "The Virtue of Sadaqah", keyTakeaway: "Sadaqah purifies wealth, wards off calamities, and brings immense reward, especially when given secretly.", duration: 7 },
{ slug: "types-of-sadaqah", title: "Types of Sadaqah", keyTakeaway: "Sadaqah includes both monetary giving and non-monetary acts like a smile or kind word (sadaqah jariyah).", duration: 7 },
{ slug: "maximizing-impact", title: "Maximizing Community Impact", keyTakeaway: "Strategic giving through categorized causes (water, education, food, health) amplifies community benefit.", duration: 6 },
],
};
for (const [courseSlug, courseModules] of Object.entries(modules)) {
const course = await prisma.learnCourse.findUnique({ where: { slug: courseSlug } });
if (!course) {
console.log(` ⚠️ Course "${courseSlug}" not found, skipping modules`);
continue;
}
for (let i = 0; i < courseModules.length; i++) {
const mod = courseModules[i];
const existing = await prisma.learnModule.findUnique({
where: { courseId_slug: { courseId: course.id, slug: mod.slug } },
});
if (existing) {
continue;
}
await prisma.learnModule.create({
data: {
courseId: course.id,
order: i,
title: mod.title,
slug: mod.slug,
keyTakeaway: mod.keyTakeaway,
duration: mod.duration,
content: `# ${mod.title}\n\n${mod.keyTakeaway}\n\n<!-- Full lesson content to be added in future updates -->`,
},
});
}
console.log(` ✅ Created ${courseModules.length} modules for "${course.title}"`);
}
// ═══════════════════════════════════════════
// SUMMARY
// ═══════════════════════════════════════════
const courseCount = await prisma.learnCourse.count();
const moduleCount = await prisma.learnModule.count();
const threadCount = await prisma.forumThread.count();
const categoryCount = await prisma.forumCategory.count();
const userCount = await prisma.user.count();
console.log("\n📊 Seed Summary:");
console.log(` Users: ${userCount}`);
console.log(` Forum Categories: ${categoryCount}`);
console.log(` Forum Threads: ${threadCount}`);
console.log(` Courses: ${courseCount}`);
console.log(` Course Modules: ${moduleCount}`);
console.log("✅ Seed complete!");
}
seed()
.catch((e) => {
console.error("❌ Seed failed:", e.message);
process.exit(1);
})
.finally(() => prisma.$disconnect());