cfff74e2db
Souq Marketplace: - Native souq pages: browse+filters, create listing, detail+seller profile, orders+chat - New API: reviews (POST), sellers/[id], upload (multipart), polar-checkout webhook - Listings API enhanced: minPrice, maxPrice, sortBy, deliveryDays filters - Seller workflow: start order, mark delivered, upload files, confirm delivery - Wallet: 5 Polar.sh FLH tiers, production checkout, mock fallback, success banner - Fix: order redirect /souq/history → /souq/orders Auth System: - Unified auth page, removed OAuth provider routing (2 files deleted) - Deleted oauth.ts (319 lines) — simplified auth chain - Streamlined login/register API routes Prisma Schema (+179 lines): - New models: Listing, Purchase, Review, Group/GroupMember - Gamification: DailyStreak, XpTransaction, Achievement, UserLevel - Learning: LearnCourse/Module/Enrollment/Certificate - Notifications, Referrals, Dhikr, PremiumBenefits Deleted legacy code: - src/app/api/marketplace/* (3 files) — replaced by /api/souq/* - src/app/api/files/[listingId]/route.ts — replaced by /api/souq/upload - src/app/api/seller/[sellerId]/route.ts — replaced by /api/souq/sellers/[id] Infrastructure: - Dockerfile: standalone output, Prisma runtime migration - docker-compose.yml: Polar env vars, healthcheck fix - docker-compose.staging.yml: staging on port 4014 - .gitea/workflows/ci.yml: CI pipeline
297 lines
10 KiB
TypeScript
297 lines
10 KiB
TypeScript
/**
|
|
* seed-courses.ts — Seed initial micro learning courses into the database.
|
|
*
|
|
* Run: npx tsx scripts/seed-courses.ts
|
|
* Or via curl: POST /api/learn/seed (for production use)
|
|
*
|
|
* This seeds the first published courses from the Gitea content repo,
|
|
* or directly defines course/module structure for the MVP.
|
|
*/
|
|
|
|
import { PrismaClient } from "@prisma/client";
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
const COURSES = [
|
|
{
|
|
slug: "atomic-habits",
|
|
title: "Atomic Habits",
|
|
author: "James Clear",
|
|
description:
|
|
"Master the science of habit formation in just 25 minutes. Learn how small daily changes compound into remarkable results through the 1% rule, identity-based habits, and the 4 laws of behavior change.",
|
|
imageUrl: null,
|
|
moduleCount: 5,
|
|
totalMinutes: 25,
|
|
difficulty: "beginner",
|
|
giteaPath: "courses/atomic-habits",
|
|
priceFlh: 499, // 4.99 in FLH cents
|
|
priceUsd: 4.99,
|
|
subscriptionOnly: false,
|
|
published: true,
|
|
modules: [
|
|
{
|
|
order: 1,
|
|
title: "The 1% Rule",
|
|
slug: "the-1-percent-rule",
|
|
keyTakeaway:
|
|
"Small habits don't just add up — they compound. Improving just 1% every day leads to being 37x better after one year.",
|
|
duration: 5,
|
|
content: `# The 1% Rule
|
|
|
|
Habits are the compound interest of self-improvement. The same way that money multiplies through compound interest, the effects of your habits multiply as you repeat them.
|
|
|
|
## The Math of Small Changes
|
|
|
|
If you get 1% better each day for one year, you'll end up 37 times better. Conversely, getting 1% worse each day for a year will decline you nearly to zero.
|
|
|
|
Success is the product of daily habits — not once-in-a-lifetime transformations.
|
|
|
|
## Why We Ignore Small Changes
|
|
|
|
We expect linear progress but live in a world of delayed returns. The most powerful outcomes are invisible during the early stages. This is the "Valley of Disappointment" — you do the right things but don't see results immediately.
|
|
|
|
## The Plateau of Latent Potential
|
|
|
|
Just like a ice cube melts at 32°F after hours of warming from 20°F to 31°F, your habits break through when you cross a critical threshold. Don't judge your success by what you see today. Your work is accumulating.
|
|
|
|
## Your Action Step
|
|
|
|
Identify one habit you want to build. Ask: "Can I make it 1% better today?"`,
|
|
quizData: JSON.stringify([
|
|
{
|
|
question: "If you get 1% better every day, how much better will you be after one year?",
|
|
options: ["About 3x better", "About 37x better", "About 10x better", "About 100x better"],
|
|
correctIndex: 1,
|
|
},
|
|
{
|
|
question: "What is the 'Valley of Disappointment'?",
|
|
options: [
|
|
"A period where habits feel boring",
|
|
"The phase where you work but see no results",
|
|
"The time between starting a new habit",
|
|
"When you lose motivation completely",
|
|
],
|
|
correctIndex: 1,
|
|
},
|
|
{
|
|
question: "At what temperature does ice melt?",
|
|
options: ["30°F", "32°F", "35°F", "40°F"],
|
|
correctIndex: 1,
|
|
},
|
|
]),
|
|
},
|
|
{
|
|
order: 2,
|
|
title: "Identity-Based Habits",
|
|
slug: "identity-based-habits",
|
|
keyTakeaway:
|
|
"The most effective way to change your habits is to focus on who you want to become, not what you want to achieve.",
|
|
duration: 5,
|
|
content: `# Identity-Based Habits
|
|
|
|
There are three levels of change: outcomes, processes, and identity. Most people focus on outcomes (what you get) instead of identity (who you are).
|
|
|
|
## The Two-Step Process
|
|
|
|
1. **Decide the type of person you want to be.**
|
|
2. **Prove it to yourself with small wins.**
|
|
|
|
Your identity emerges from your habits. Every action is a vote for the type of person you wish to become.
|
|
|
|
## The Habit Loop
|
|
|
|
Every habit follows a four-step loop:
|
|
- **Cue** — The trigger that initiates the behavior
|
|
- **Craving** — The motivational force behind the habit
|
|
- **Response** — The actual habit you perform
|
|
- **Reward** — The benefit you gain from the habit
|
|
|
|
## Your Action Step
|
|
|
|
Instead of saying "I want to run a marathon," say "I am a runner." Then go for a 5-minute jog.`,
|
|
quizData: JSON.stringify([
|
|
{
|
|
question: "What are the three levels of change mentioned?",
|
|
options: [
|
|
"Outcomes, Processes, Identity",
|
|
"Goals, Actions, Results",
|
|
"Start, Middle, End",
|
|
"Mind, Body, Soul",
|
|
],
|
|
correctIndex: 0,
|
|
},
|
|
{
|
|
question: "Each action is a ___ for the type of person you wish to become.",
|
|
options: ["Reminder", "Vote", "Proof", "Promise"],
|
|
correctIndex: 1,
|
|
},
|
|
]),
|
|
},
|
|
{
|
|
order: 3,
|
|
title: "The 4 Laws of Behavior Change",
|
|
slug: "the-4-laws",
|
|
keyTakeaway:
|
|
"To build a good habit: make it obvious, attractive, easy, and satisfying. To break a bad habit: invert each law.",
|
|
duration: 5,
|
|
content: `# The 4 Laws of Behavior Change
|
|
|
|
## Law 1: Make It Obvious
|
|
Design your environment so the cues for good habits are visible and the cues for bad habits are invisible.
|
|
|
|
## Law 2: Make It Attractive
|
|
Use temptation bundling — pair an action you want to do with an action you need to do.
|
|
|
|
## Law 3: Make It Easy
|
|
The most effective form of learning is practice, not planning. Reduce friction. The Two-Minute Rule: when you start a new habit, it should take less than two minutes.
|
|
|
|
## Law 4: Make It Satisfying
|
|
Use immediate rewards. What is immediately rewarded is repeated. What is immediately punished is avoided.
|
|
|
|
## The Inversion (Breaking Bad Habits)
|
|
- Make it **invisible**
|
|
- Make it **unattractive**
|
|
- Make it **difficult**
|
|
- Make it **unsatisfying**`,
|
|
quizData: JSON.stringify([
|
|
{
|
|
question: "What is Law 1 of behavior change?",
|
|
options: ["Make It Easy", "Make It Obvious", "Make It Attractive", "Make It Satisfying"],
|
|
correctIndex: 1,
|
|
},
|
|
{
|
|
question: "The Two-Minute Rule states that a new habit should take:",
|
|
options: ["Less than 5 minutes", "Less than 2 minutes", "Exactly 2 minutes", "As long as needed"],
|
|
correctIndex: 1,
|
|
},
|
|
]),
|
|
},
|
|
{
|
|
order: 4,
|
|
title: "Habit Stacking",
|
|
slug: "habit-stacking",
|
|
keyTakeaway:
|
|
"The best way to build a new habit is to anchor it to an existing one using the formula: After [CURRENT HABIT], I will [NEW HABIT].",
|
|
duration: 5,
|
|
content: `# Habit Stacking
|
|
|
|
One of the best ways to build a new habit is to identify a current habit you already do each day and then stack your new behavior on top.
|
|
|
|
## The Formula
|
|
|
|
> After [CURRENT HABIT], I will [NEW HABIT].
|
|
|
|
## Examples
|
|
- After I pour my morning coffee, I will meditate for 60 seconds.
|
|
- After I sit down to dinner, I will say one thing I'm grateful for.
|
|
- After I take off my work shoes, I will change into my workout clothes.
|
|
|
|
## The Key: Pairing Specificity
|
|
|
|
The more specific your plan, the more likely you are to follow through. Use implementation intentions:
|
|
> "I will [BEHAVIOR] at [TIME] in [LOCATION]."`,
|
|
quizData: JSON.stringify([
|
|
{
|
|
question: "What is habit stacking?",
|
|
options: [
|
|
"Doing multiple habits at once",
|
|
"Anchoring a new habit to an existing one",
|
|
"Stacking rewards on top of each other",
|
|
"Creating a list of habits",
|
|
],
|
|
correctIndex: 1,
|
|
},
|
|
]),
|
|
},
|
|
{
|
|
order: 5,
|
|
title: "Design Your Environment",
|
|
slug: "design-your-environment",
|
|
keyTakeaway:
|
|
"Your surroundings shape your behavior more than willpower. Design your environment for success by reducing friction for good habits and increasing it for bad ones.",
|
|
duration: 5,
|
|
content: `# Design Your Environment
|
|
|
|
Willpower is overrated. The most reliable way to stick to good habits is to design your environment so that the right choice is the easy choice.
|
|
|
|
## Friction
|
|
|
|
Every habit is initiated by a cue. If you want to make a habit a big part of your life, make the cue a big part of your environment.
|
|
|
|
- Want to read more? Keep a book on your pillow.
|
|
- Want to drink more water? Fill a bottle and place it on your desk.
|
|
- Want to practice guitar? Leave it in the middle of the room.
|
|
|
|
## One Space, One Use
|
|
|
|
Don't mix contexts. Your bed is for sleep. Your desk is for work. When you mix contexts, you mix habits.
|
|
|
|
## Commitment Devices
|
|
|
|
A commitment device is a choice you make in the present that locks in better behavior in the future. Delete the games from your phone. Unsubscribe from junk food delivery.
|
|
|
|
## Your Final Action Step
|
|
|
|
Choose ONE habit to focus on this week. Apply all 4 laws. Track it. Repeat.`,
|
|
quizData: JSON.stringify([
|
|
{
|
|
question: "What is a commitment device?",
|
|
options: [
|
|
"A promise to yourself",
|
|
"A present choice that locks in better future behavior",
|
|
"A device that tracks habits",
|
|
"An accountability partner",
|
|
],
|
|
correctIndex: 1,
|
|
},
|
|
{
|
|
question: "Wanting to read more — where should you keep the book?",
|
|
options: ["On your shelf", "On your pillow", "On your desk", "In your bag"],
|
|
correctIndex: 1,
|
|
},
|
|
]),
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
async function main() {
|
|
console.log("🌱 Seeding micro learning courses...\n");
|
|
|
|
for (const courseData of COURSES) {
|
|
const { modules, ...courseFields } = courseData;
|
|
|
|
// Upsert the course
|
|
const course = await prisma.learnCourse.upsert({
|
|
where: { slug: courseFields.slug },
|
|
create: courseFields,
|
|
update: courseFields,
|
|
});
|
|
|
|
console.log(` 📖 Course: ${course.title} (${course.slug})`);
|
|
|
|
// Upsert each module
|
|
for (const mod of modules) {
|
|
await prisma.learnModule.upsert({
|
|
where: {
|
|
courseId_slug: { courseId: course.id, slug: mod.slug },
|
|
},
|
|
create: { ...mod, courseId: course.id },
|
|
update: { ...mod, courseId: course.id },
|
|
});
|
|
console.log(` 📝 Module ${mod.order}: ${mod.title}`);
|
|
}
|
|
}
|
|
|
|
console.log(`\n✅ Seeded ${COURSES.length} course(s) successfully.`);
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error("❌ Seed failed:", e);
|
|
process.exit(1);
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|