Lexiverse
Lexiverse - AI contextual reading engine for English learners. Your next article is your next review.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Quizora is a placement-prep and mock-test platform for students. They practise topic by topic with instant worked solutions, sit timed mock tests and live contests, and follow their progress on streaks, heatmaps, leaderboards and analytics. Staff run the question bank, syllabus, tests, contests, users and reports from an admin console. Premium tests and contests are sold through Dodo Payments.
Stack: Next.js 16 (App Router, Tailwind 4), Drizzle ORM on PostgreSQL (embedded PGlite locally), Better Auth (email and password), Vitest, Playwright.
Requires Node.js 24 or later.
npm install
cp .env.example .env.local # then set BETTER_AUTH_SECRET (openssl rand -base64 32)
npm run db:reset # fresh local database with the full demo data
npm run dev # open http://localhost:3300
npm run db:reset deletes the local PGlite folder (.pglite), applies the migrations and runs the demo seed. It refuses to run in production, with DATABASE_URL set, or while a server is listening on port 3300 (PGlite allows one process per database, so stop npm run dev first). npm run db:seed on its own adds whatever demo data is missing and can be run again safely.
In the Claude desktop app the project also has a preview configuration named quizora (.claude/launch.json) that runs npm run dev on port 3300.
| Role | Password | Notes | |
|---|---|---|---|
| Super admin | [email protected] | admin-pass-123 | Everything in the admin console |
| Content manager | [email protected] | content-pass-123 | Question bank, syllabus, tests, moderation; no orders or settings |
| Student (live demo) | [email protected] | demo-pass-123 | A week of light practice, 3-day streak, no purchases: use it to buy a premium test |
| Student | [email protected] | demo-pass-123 | Leaderboard #1, 15-day streak, bought the GATE CS mock |
| Student | [email protected] | demo-pass-123 | Steady, 6-day streak |
| Student | [email protected] | demo-pass-123 | Most accurate, slower pace |
| Student | [email protected] | demo-pass-123 | Fast but inaccurate; lowest accuracy |
| Student | [email protected] | demo-pass-123 | Joined this week; strong on the weekly board |
The seed also loads the full syllabus (6 sections, 39 modules, 248 topics), 546 original questions, 6 mock tests (3 premium: ₹49, ₹99, ₹149), 3 contests (one live this week, one upcoming in two days, one past with results), 7 discussion threads, four weeks of practice and test history for the students, and one completed purchase. Anyone can also register a new account at /register.
[email protected] / demo-pass-123 (or Register to create a brand-new student).[email protected] / admin-pass-123, press Admin in the sidebar:
Admins make a test or contest paid by giving it a price in rupees (Admin → Tests / Contests → edit → "Paid test (₹)"). Students see a Premium badge and a Buy for ₹X button; a purchase is a one-time payment with lifetime access. Free content stays free, and staff can open every premium item to preview it.
PAYMENT_PROVIDER picks the provider:
fake (default): the built-in Test checkout page with Pay and Simulate a failed payment buttons. No account or keys needed. It refuses to run when NODE_ENV=production.dodo: Dodo Payments hosted checkout.Both send the buyer back to /payments/return, which verifies the payment on the server before granting access. Admin → Orders lists every order with revenue and counts by state, an order's history and Recheck with provider. Students see their receipts in Profile & Settings → Plan & purchases. Admin → Settings and Admin → System Health show the active provider, which payment variables are set (never their values) and what is missing, in plain words.
About ten minutes. Do it in Test Mode first; nothing charges real money.
Account – sign up at dodopayments.com and open the dashboard.
Test Mode – switch the dashboard to Test Mode with the toggle at the top. Create everything below while it is on.
API key → DODO_PAYMENTS_API_KEY – Developer → API Keys → create a key and copy it.
Product → DODO_PAYMENTS_PRODUCT_ID – Products → create one product: type One-time, pricing Pay What You Want, currency INR, a minimum price at or below your cheapest premium item (e.g. ₹1), a name such as "Quizora premium access". Copy its id (pdt_…). Every premium test and contest is sold through this one product; Quizora sends the item's own price (in paise) with each checkout.
Alternative: a fixed-price one-time INR product per test, pasted into that test's Dodo product id field in the admin form (it wins over the shared product). Its price must equal the test's price, or the payment is refused as an amount mismatch.
.env.local – set:
PAYMENT_PROVIDER=dodo
DODO_PAYMENTS_API_KEY=... # the test-mode key from step 3
DODO_PAYMENTS_ENVIRONMENT=test_mode
DODO_PAYMENTS_PRODUCT_ID=pdt_... # from step 4
DODO_PAYMENTS_WEBHOOK_KEY= # leave empty on localhost (step 8)
APP_URL=http://localhost:3300 # where Dodo sends buyers back
Restart npm run dev (environment changes need a restart). Check Admin → Settings → Payments: it should say Ready; anything missing is named there.
Test a purchase – as a student, buy a premium test. You land on Dodo's checkout; pay with a test card from Dodo's docs (docs.dodopayments.com, the test-mode / testing page). Dodo sends you back to /payments/return, which asks Dodo for the payment and grants access only if it succeeded, belongs to that buyer's order and matches the price. Use a failing test card to see "Payment failed" and Try again.
Webhook (once deployed) – webhooks cannot reach localhost, and localhost does not need them. On a public URL (the deployed site, or a tunnel such as cloudflared tunnel --url http://localhost:3300): Developer → Webhooks → add endpoint https://<your domain>/api/payments/dodo/webhook with the events , , and ; copy the endpoint's signing secret () into , set to the public https address, restart. Webhooks cover buyers who close the tab before returning, failed and cancelled payments, and refunds (a full refund removes access). An order stuck on "Pending" can always be settled with on its admin page.
If a required setting is missing, Buy shows "Payments are not set up yet: …" naming the variable, and the admin pages show the same message.
DODO_PAYMENTS_API_KEY, and set DODO_PAYMENTS_ENVIRONMENT=live_mode.DODO_PAYMENTS_PRODUCT_ID (test-mode ids do not exist in live mode; re-enter any per-test product ids too).DODO_PAYMENTS_WEBHOOK_KEY.APP_URL to the public https origin, keep PAYMENT_PROVIDER=dodo, redeploy.Automatic setup on Vercel. On each deploy, the build applies database migrations and, when the database has no content yet, loads the syllabus, questions, tests and contests (set
SEED_CONTENT_ON_DEPLOY=falseto skip). For the first admin, setBOOTSTRAP_ADMIN_EMAILto your email and sign up on the live site with it: that account becomes super admin, and the setting stops having any effect once a super admin exists. The manualdb:seed:contentandcreate-adminsteps below are only needed if you prefer them.
The app runs on Vercel as serverless functions against a hosted Postgres database (PGlite is local only: on Vercel the app refuses to start without DATABASE_URL). Every deploy runs npm run vercel-build, which applies the database migrations and then runs next build; a deploy without DATABASE_URL fails with a message saying what to add. .env.production.example lists every variable.
Create the database. Vercel dashboard → Storage → Create Database → Neon (Postgres) → pick a region close to your users → Connect it to the Quizora project for Production and Preview. The integration adds DATABASE_URL (pooled; the app uses it) and DATABASE_URL_UNPOOLED (direct; migrations use it) to the project. Copy the pooled DATABASE_URL (host contains -pooler, ends with ?sslmode=require) from the database's .env.local tab for steps 5 and 6. If you create the database in Neon directly instead, paste its pooled connection string as DATABASE_URL yourself. Previews share this database unless you give Preview its own (Neon branch or second database); migrations run on every deploy, previews included.
Deploy. Either push this folder to a new GitHub repository and in Vercel choose Add New → Project → Import that repository (framework Next.js, everything else default), or run npx vercel in this folder and follow the prompts (then npx vercel --prod for production). Vercel uses npm run vercel-build on its own.
Set the environment variables (Project → Settings → Environment Variables), then redeploy (Deployments → ⋯ → Redeploy) so they apply:
| Variable | Production | Preview | Where the value comes from |
|---|---|---|---|
DATABASE_URL | pooled URL | pooled URL (or a preview database) | Added by the Neon integration (step 1), or the Neon dashboard → Connection string, Pooled |
BETTER_AUTH_SECRET | required | required | Generate once: openssl rand -base64 32. Changing it signs everyone out |
BETTER_AUTH_URL | https://<your domain> | leave unset | Your custom domain. Unset, it falls back to the project's https://<project>.vercel.app (production) or the preview's own URL |
APP_URL | https://<your domain> | leave unset | Same as BETTER_AUTH_URL; Dodo returns buyers to APP_URL/payments/return. Same fallback |
Notes: sessions, posting limits and settings live in Postgres; the only in-process state is per-instance caching (the chosen payment provider, the commit id), so nothing depends on one long-running server. Sign-in runs in Server Actions, so Better Auth's in-memory rate limiter (which guards only its HTTP routes, not mounted here) is not relied on. System Health's uptime is one serverless instance's (instances start and stop on their own). To try the Postgres path locally without Docker: npm run db:pg-server (a Postgres wire-protocol server on port 54329 backed by .pglite-pg), then in another terminal DATABASE_URL=postgres://postgres:[email protected]:54329/postgres npm run db:migrate, … npm run db:seed:content -- --yes and … npx next dev --port 3320. npm run test:pg runs the whole Vitest suite through node-postgres against such a server.
The seed questions are originals written for this rebuild. Load the real bank through Admin → Import (/admin/questions/import):
P-001; codes are listed under Admin → Topics), a difficulty (easy, medium or hard), the question text, 2 to 6 options, the correct option and an optional explanation.
topic_code,difficulty,stem,option_a,option_b,option_c,option_d,correct,explanation (add option_e, option_f for more options; leave trailing options empty for fewer). correct is the letter A–F (or 1–6). Quote cells that contain commas or line breaks.{ "questions": [...] }) of { "topicCode": "P-001", "difficulty": "easy", "stem": "...", "options": ["...", "..."], "correctIndex": 0, "explanation": "..." } with correctIndex counted from 0, the same format as src/db/seed/questions/*.json.Expected volume: the syllabus is sized for about 57,650 questions; files of several thousand rows import in one go (split very large banks into files of 5,000–10,000 rows). New questions are active at once and appear in practice, topic pages and the test builder.
| Command | What it does |
|---|---|
npm run dev | Development server on http://localhost:3300 |
npm run build / npm start | Production build and server (port 3300) |
npm run db:reset | Delete the local PGlite database, migrate and seed the demo (local only, server stopped) |
npm run db:migrate | Apply migrations |
npm run db:seed | Add any missing demo data (idempotent; refuses with NODE_ENV=production) |
npm run db:seed:content -- --yes | Production content only: syllabus, questions, tests, contests (idempotent; --yes needed with DATABASE_URL or in production) |
npm run db:pg-server | Local Postgres wire-protocol server on port 54329 (PGlite in .pglite-pg), for trying DATABASE_URL without Docker |
npm run vercel-build | What Vercel runs: migrations against DATABASE_URL, then next build |
npm run db:generate | Generate a migration after changing src/db/schema/ |
npm run create-admin -- <email> "<name>" <password> [role] | Create or promote a staff account (admin by default); runs from this machine, against production with DATABASE_URL=… |
npm run typecheck | Route type generation and TypeScript |
npm run lint | ESLint |
npm test | Vitest (data layer, in-memory PGlite per file) |
npm run test:pg | The same Vitest suite through node-postgres over the Postgres wire protocol |
npm run test:e2e | Playwright on port 3310 with its own .pglite-e2e database, reset every run |
Leave DATABASE_URL empty to use PGlite in PGLITE_DATA_DIR (default .pglite); set it to use a PostgreSQL server instead (then run db:migrate and db:seed or db:seed:content against it; db:reset only touches PGlite). ?sslmode=require in the URL turns on TLS.
src/app/ – routes: / landing, /login, /register, /legal; the student app in (app)/ (dashboard, practice, tests, contests, subjects, topics, bookmarks, history, leaderboard, discussions, progress, settings); the full-screen runner in session/; the printable report in (report)/; checkout pages in payments/; the admin console in admin/; the Dodo webhook in api/payments/dodo/webhook/. Navigation lives in src/app/nav.ts.src/server/ – all data access; every function takes an actor and authorizes itself.src/db/schema/ – Drizzle schema; migrations in drizzle/; demo data and the 546 seed questions in src/db/seed/.src/providers/payments/ – payment providers (fake, dodo) and the Dodo webhook verifier.src/components/ – UI (ui/ holds the shared Button, Card, Badge, StatCard, PageHeader, Tabs and form fields); design tokens in src/app/globals.css.src/lib/ – pure rules and helpers (scoring, stats, import parsing, formatting).scripts/ – demo seed, production content seed, reset, create-admin, the Vercel build and the e2e fixture.tests/ (Vitest) and e2e/ (Playwright).docs/recon/), not from its code or data. Layout, wording and features follow those notes; anything they did not show was designed for this project (decisions are listed in PROGRESS.md).payment.succeededpayment.failedpayment.cancelledrefund.succeededwhsec_…DODO_PAYMENTS_WEBHOOK_KEYAPP_URLPAYMENT_PROVIDER | dodo | dodo | Fixed. The built-in test checkout is refused in production builds, and Vercel previews are production builds |
DODO_PAYMENTS_API_KEY | required | required | Dodo dashboard → Developer → API Keys (Test Mode key while testing) |
DODO_PAYMENTS_ENVIRONMENT | test_mode (later live_mode) | test_mode | Must match the key |
DODO_PAYMENTS_PRODUCT_ID | pdt_… | pdt_… | Dodo dashboard → Products → your one-time Pay What You Want INR product |
DODO_PAYMENTS_WEBHOOK_KEY | whsec_… | optional | Step 5 |
DATABASE_POOL_MAX | optional | optional | Connections per serverless instance; default 3 |
Load the content and create the first admin, from this machine, after the first successful deploy (the migrations have run by then). Use the pooled DATABASE_URL from step 1; the commands print what they did and can be run again safely:
cd /Users/jai/quizora-clone
DATABASE_URL='postgresql://…-pooler…/neondb?sslmode=require' npm run db:seed:content -- --yes
DATABASE_URL='postgresql://…-pooler…/neondb?sslmode=require' npm run create-admin -- [email protected] "Your Name" '<a strong password>' super_admin
db:seed:content loads only the syllabus (6 sections, 39 modules, 248 topics), the 546 questions, the 6 tests and the 3 contests (live and upcoming windows set from today); run it again later to move the contest windows forward. It adds no demo students, activity, orders, discussions or passwords, and asks for --yes whenever DATABASE_URL is set. Never run npm run db:seed (the demo seed with known passwords) against production.
Add the Dodo webhook. Dodo dashboard → Developer → Webhooks → Add endpoint https://<your domain>/api/payments/dodo/webhook with the events payment.succeeded, payment.failed, payment.cancelled and refund.succeeded. Copy the endpoint's signing secret (whsec_…) into DODO_PAYMENTS_WEBHOOK_KEY for Production and redeploy.
Verify. Sign in with the admin from step 4. Admin → System Health should show Database Connected (PostgreSQL), Migrations 8 / 8 with none pending, Platform Vercel · production, and the row counts (546 questions, 6 tests, 3 contests). Admin → Settings → Payments should say Ready with provider dodo and every Dodo variable Set. Then register a student account, buy a premium test with a Dodo test card (docs.dodopayments.com, testing page), check you return to "Payment successful" and can start the test, and that the order shows as Paid under Admin → Orders (and "Last webhook received" on System Health shows payment.succeeded).
Custom domain. Project → Settings → Domains → add your domain and create the DNS records Vercel shows. Then set BETTER_AUTH_URL and APP_URL to https://<your domain>, change the Dodo webhook URL to the new domain, and redeploy. Going live with real payments: README "Going live" above.