duolingo-clone/
|- actions/
|-- challenge-progress.ts
|-- user-progress.ts
|-- user-subscription.ts
|- app/
|-- (auth)
|-- sign-in
|-- [[...sign-in]]
|-- page.tsx
|-- sign-up
|-- [[...sign-up]]
|-- page.tsx
|-- layout.tsx
|-- (main)
|-- courses
|-- page.tsx
|-- leaderboard
|-- page.tsx
|-- learn
|-- page.tsx
|-- quests
|-- page.tsx
|-- shop
|-- page.tsx
|-- layout.tsx
|-- (marketing)
|-- layout.tsx
|-- page.tsx
|-- admin
|-- app.tsx
|-- page.tsx
|-- api
|-- challengeOptions
|-- [challengeOptionId]
|-- route.ts
|-- route.ts
|-- challenges
|-- [challengeId]
|-- route.ts
|-- route.ts
|-- courses
|-- [courseId]
|-- route.ts
|-- route.ts
|-- lessons
|-- [lessonId]
|-- route.ts
|-- route.ts
|-- units
|-- [unitId]
|-- route.ts
|-- route.ts
|-- webhooks
|-- stripe
|-- route.ts
|-- buttons
|-- page.tsx
|-- layout.tsx
|-- lesson
|-- [lessonId]
|-- page.tsx
|-- layout.tsx
|-- page.tsx
|-- loading.tsx
|- components/
|-- Admin
|-- Challenge
|-- ChallengeCreate.tsx
|-- ChallengeEdit.tsx
|-- ChallengeList.tsx
|-- index.ts
|-- ChallengeOption
|-- ChallengeOptionCreate.tsx
|-- ChallengeOptionEdit.tsx
|-- ChallengeOptionList.tsx
|-- index.ts
|-- Course
|-- CourseCreate.tsx
|-- CourseEdit.tsx
|-- CourseList.tsx
|-- index.ts
|-- Lesson
|-- index.ts
|-- LessonCreate.tsx
|-- LessonEdit.tsx
|-- LessonList.tsx
|-- Unit
|-- index.ts
|-- UnitCreate.tsx
|-- UnitEdit.tsx
|-- UnitList.tsx
|-- Courses
|-- Card
|-- Card.tsx
|-- index.ts
|-- LessonButton
|-- index.ts
|-- LessonButton.tsx
|-- List
|-- index.ts
|-- List.tsx
|-- Unit
|-- index.ts
|-- Unit.tsx
|-- UnitBanner.tsx
|-- Header
|-- Header.tsx
|-- index.ts
|-- Leaderboard
|-- LeaderboardList
|-- index.ts
|-- LeaderboardList.tsx
|-- Learn
|-- Units
|-- index.ts
|-- Units.tsx
|-- Lesson
|-- Card
|-- Card.tsx
|-- index.ts
|-- Challenge
|-- Challenge.tsx
|-- index.ts
|-- Footer
|-- Footer.tsx
|-- index.ts
|-- Header
|-- Header.tsx
|-- index.ts
|-- QuestionBubble
|-- index.ts
|-- QuestionBubble.tsx
|-- Quiz
|-- index.ts
|-- Quiz.tsx
|-- ResultCard
|-- index.ts
|-- ResultCard.tsx
|-- Loader
|-- index.ts
|-- Loader.tsx
|-- Logo
|-- index.ts
|-- Logo.tsx
|-- Marketing
|-- Footer
|-- constants.ts
|-- Footer.tsx
|-- index.ts
|-- Header
|-- Header.tsx
|-- index.ts
|-- MobileHeader
|-- index.ts
|-- MobileHeader.tsx
|-- MobileSidebar
|-- index.ts
|-- MobileSidebar.tsx
|-- Modals
|-- ExitModal.tsx
|-- HeartsModal.tsx
|-- PracticeModal.tsx
|-- Promo
|-- index.ts
|-- Promo.tsx
|-- Quests
|-- QuestList
|-- index.ts
|-- QuestList.tsx
|-- Shop
|-- Items
|-- index.ts
|-- Items.tsx
|-- Sidebar
|-- constants.ts
|-- index.ts
|-- Sidebar.tsx
|-- SidebarItem.tsx
|-- Skeletons
|-- index.ts
|-- Skeletons.tsx
|-- ui
|-- Avatar.tsx
|-- Badge.tsx
|-- Button.tsx
|-- Dialog.tsx
|-- Progress.tsx
|-- Separator.tsx
|-- Sheet.tsx
|-- Skeleton.tsx
|-- Sonner.tsx
|-- UserProgress
|-- index.ts
|-- UserProgress.tsx
|-- Wrappers
|-- FeedWrapper.tsx
|-- StickyWrapper.tsx
|- constants.ts
|- db/
|-- drizzle.ts
|-- queries.ts
|-- schema.ts
|- lib/
|-- admin.ts
|-- stripe.ts
|-- utils.ts
|- public/
|-- boy.svg
|-- es.svg
|-- finish.svg
|-- fr.svg
|-- girl.svg
|-- heart.svg
|-- hero.svg
|-- hr.svg
|-- it.svg
|-- jp.svg
|-- leaderboard.svg
|-- learn.svg
|-- man.svg
|-- mascot_bad.svg
|-- mascot_sad.svg
|-- mascot.svg
|-- points.svg
|-- quests.svg
|-- robot.svg
|-- shop.svg
|-- unlimited.svg
|-- woman.svg
|-- zombie.svg
|- scripts/
|-- production.ts
|-- reset.ts
|-- seed.ts
|- store/
|-- use-exit-modal.ts
|-- use-hearts-modal.ts
|-- use-practice-modal.ts
|- styles/
|-- globals.css
|- .eslintrc.json
|- .gitignore
|- .husky/
|-- commit-msg
|-- pre-commit
|- .lintstagedrc
|- .prettierignore
|- .prettierrc
|- commitlint.config.ts
|- components.json
|- drizzle.config.ts
|- middleware.ts
|- next.config.mjs
|- package.json
|- postcss.config.mjs
|- tailwind.config.ts
|- tsconfig.json
- Make sure Git and NodeJS is installed.
- Clone this repository to your local computer.
- Create
.env
file in root directory. - Contents of
.env
:
# .env
# disabled next.js telemetry
NEXT_TELEMETRY_DISABLED=1
# clerk auth keys
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
CLERK_SECRET_KEY=sk_test_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# neon db uri
DATABASE_URL="postgresql://<user>:<password>@<host>:<post>/lingo?sslmode=require"
# stripe api key and webhook
STRIPE_API_SECRET_KEY=sk_test_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
STRIPE_WEBHOOK_SECRET=whsec_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# public app url
NEXT_PUBLIC_APP_URL=http://localhost:3000
# clerk admin user id(s) separated by comma and space (, )
CLERK_ADMIN_IDS="user_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# or CLERK_ADMIN_IDS="user_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx, user_xxxxxxxxxxxxxxxxxxxxxx" for multiple admins.
-
Obtain Clerk Authentication Keys
- Source: Clerk Dashboard or Settings Page
- Procedure:
- Log in to your Clerk account.
- Navigate to the dashboard or settings page.
- Look for the section related to authentication keys.
- Copy the
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
andCLERK_SECRET_KEY
provided in that section.
-
Retrieve Neon Database URL
- Source: Database Provider (e.g., Neon, PostgreSQL)
- Procedure:
- Access your database provider's platform or configuration.
- Locate the database connection details.
- Replace
<user>
,<password>
,<host>
, and<port>
placeholders in the URI with your actual database credentials. - Ensure to include
?sslmode=require
at the end of the URL for SSL mode requirement.
-
Fetch Stripe API Key and Webhook Secret
- Source: Stripe Dashboard
- Procedure:
- Log in to your Stripe account.
- Navigate to the dashboard or API settings.
- Find the section related to API keys and webhook secrets.
- Copy the
STRIPE_API_SECRET_KEY
andSTRIPE_WEBHOOK_SECRET
.
-
Specify Public App URL
- Procedure:
- Replace
http://localhost:3000
with the URL of your deployed application.
- Replace
- Procedure:
-
Identify Clerk Admin User IDs
-
Source: Clerk Dashboard or Settings Page
-
Procedure:
- Log in to your Clerk account.
- Navigate to the dashboard or settings page.
- Find the section related to admin user IDs.
- Copy the user IDs provided, ensuring they are separated by commas and spaces.
-
-
Save and Secure:
- Save the changes to the
.env
file.
- Save the changes to the
-
Install Project Dependencies using
npm install --legacy-peer-deps
oryarn install --legacy-peer-deps
. -
Run the Seed Script:
In the same terminal, run the following command to execute the seed script:
npm run db:push && npm run db:prod
This command uses
npm
to execute the Typescript file (scripts/prod.ts
) and writes challenges data in database. -
Verify Data in Database:
Once the script completes, check your database to ensure that the challenges data has been successfully seeded.
-
Now app is fully configured 👍 and you can start using this app using either one of
npm run dev
oryarn dev
.
[!IMPORTANT] Please make sure to keep your API keys and configuration values secure and do not expose them publicly.