Skip to content

Commit 2eeddbb

Browse files
authored
Merge pull request #311 from guillermoscript/chore/project-setup
chore(docs): project setup — env vars, README, test accounts, npm scripts
2 parents 9bb17ab + b03e6fa commit 2eeddbb

7 files changed

Lines changed: 237 additions & 141 deletions

File tree

.env.example

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,80 @@
1-
# ============================================================
2-
# LMS Platform — Environment Variables
3-
# Copy this file to .env.local and fill in your values.
4-
# NEVER commit .env.local to version control.
5-
# ============================================================
1+
# ─── MINIMUM VIABLE LOCAL SETUP ──────────────────────────────────────────────
2+
# Copy this file to .env.local and fill in the values below.
3+
# Do NOT commit .env.local — it is listed in .gitignore.
4+
# At minimum, you need these 4 vars to run the app locally:
5+
# NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY,
6+
# SUPABASE_SERVICE_ROLE_KEY, NEXT_PUBLIC_PLATFORM_DOMAIN
67

7-
# ─── Supabase ────────────────────────────────────────────────
8-
# Found at: https://supabase.com/dashboard → Project Settings → API
9-
NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co
10-
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY=eyJ... # anon / publishable key
11-
SUPABASE_SERVICE_ROLE_KEY=eyJ... # service_role key — keep secret!
8+
# ─── SUPABASE ─────────────────────────────────────────────────────────────────
9+
# Get these from: Supabase Dashboard → your project → Settings → API
10+
NEXT_PUBLIC_SUPABASE_URL= # Required — Supabase project URL
11+
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY= # Required — anon/publishable key
12+
SUPABASE_SERVICE_ROLE_KEY= # Required — service role key (bypasses RLS, server-only)
1213

13-
# ─── Platform Domain ─────────────────────────────────────────
14-
# The root domain for subdomain routing. Each school gets school.yourdomain.com
15-
# For local dev: lvh.me:3000 (all subdomains resolve to localhost)
16-
NEXT_PUBLIC_PLATFORM_DOMAIN=yourdomain.com
17-
NEXT_PUBLIC_APP_URL=https://yourdomain.com
14+
# ─── STRIPE — STUDENT PAYMENTS (Connect) ──────────────────────────────────────
15+
# Students pay schools via Stripe Connect (PaymentIntents)
16+
# Get keys from: https://dashboard.stripe.com/apikeys
17+
STRIPE_SECRET_KEY= # Required for payment features
18+
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= # Required for payment features
19+
STRIPE_WEBHOOK_SECRET= # Required — student payment webhook (/api/stripe/webhook)
1820

19-
# ─── Stripe — Student Payments (Connect) ─────────────────────
20-
# Schools receive payments via Stripe Connect.
21-
# Found at: https://dashboard.stripe.com/apikeys
22-
STRIPE_SECRET_KEY=sk_live_...
23-
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
24-
# Webhook secret for /api/stripe/webhook (student payments)
25-
# Created at: https://dashboard.stripe.com/webhooks → add endpoint
26-
STRIPE_WEBHOOK_SECRET=whsec_...
21+
# ─── STRIPE — SCHOOL BILLING (Platform) ───────────────────────────────────────
22+
# Schools pay the platform via Stripe Billing (Checkout + Subscriptions)
23+
STRIPE_PLATFORM_WEBHOOK_SECRET= # Required for school billing webhook (/api/stripe/platform-webhook)
2724

28-
# ─── Stripe — Platform Billing (School Subscriptions) ────────
29-
# Platform charges schools for their plan (Starter, Pro, Business).
30-
# Webhook secret for /api/stripe/platform-webhook
31-
STRIPE_PLATFORM_WEBHOOK_SECRET=whsec_...
25+
# ─── PLATFORM ─────────────────────────────────────────────────────────────────
26+
NEXT_PUBLIC_PLATFORM_DOMAIN=lvh.me # Has-Default — subdomain base (lvh.me for local, yourdomain.com in prod)
27+
NEXT_PUBLIC_APP_URL=http://localhost:3000 # Has-Default — base URL of the app
28+
NEXT_PUBLIC_APP_NAME=LMS Platform # Has-Default — displayed in UI and emails
3229

33-
# ─── AI — OpenAI (Exam Grading, Exercises, AI Tutor) ─────────
34-
# Found at: https://platform.openai.com/api-keys
35-
OPENAI_API_KEY=sk-...
30+
# ─── AI ───────────────────────────────────────────────────────────────────────
31+
OPENAI_API_KEY= # Optional — server-side AI features (Aristotle tutor, grading)
32+
# ⚠ SECURITY: This key is exposed to the browser bundle. Do not use a production key here.
33+
# It is consumed by the speech-input component. Server-side proxying is the intended fix (tracked separately).
34+
NEXT_PUBLIC_OPENAI_API_KEY= # Optional — client-side speech input feature
35+
ASSEMBLYAI_API_KEY= # Optional — audio transcription for speech exercises
3636

37-
# ─── Email — Mailgun ─────────────────────────────────────────
38-
# Used for enrollment confirmations, certificate delivery, welcome emails.
39-
# Found at: https://app.mailgun.com/mg/dashboard
40-
MAILGUN_API_KEY=key-...
41-
MAILGUN_DOMAIN=mg.yourdomain.com
42-
MAILGUN_API_URL=https://api.mailgun.net # use https://api.eu.mailgun.net for EU
43-
EMAIL_FROM=noreply@yourdomain.com
37+
# ─── OBSERVABILITY / LANGFUSE ─────────────────────────────────────────────────
38+
LANGFUSE_PUBLIC_KEY= # Optional — LLM observability (Langfuse)
39+
LANGFUSE_SECRET_KEY= # Optional
40+
LANGFUSE_BASEURL= # Optional — defaults to Langfuse cloud if omitted
4441

45-
# ─── Certificates ────────────────────────────────────────────
46-
# Used to sign and verify issued certificates.
47-
CERTIFICATE_ENCRYPTION_KEY=a-random-32-char-secret-string
48-
CERTIFICATE_ISSUER_NAME=Your Platform Name
42+
# ─── EMAIL / MAILGUN ──────────────────────────────────────────────────────────
43+
MAILGUN_API_KEY= # Optional — transactional email
44+
MAILGUN_API_URL= # Optional — e.g. https://api.eu.mailgun.net (EU region)
45+
MAILGUN_DOMAIN= # Optional — your Mailgun sending domain
46+
EMAIL_FROM= # Optional — e.g. noreply@yourdomain.com
4947

50-
# ─── Company Info (used in invoices / emails) ────────────────
51-
COMPANY_NAME=Your Company Name
52-
COMPANY_EMAIL=hello@yourdomain.com
53-
COMPANY_ADDRESS=123 Main St, City, Country
54-
COMPANY_PHONE=+1 555 000 0000
48+
# ─── CERTIFICATES ─────────────────────────────────────────────────────────────
49+
CERTIFICATE_ENCRYPTION_KEY= # Optional — course completion certificate signing
50+
CERTIFICATE_ISSUER_NAME= # Optional — displayed on certificates
5551

56-
# ─── Cron Jobs ───────────────────────────────────────────────
57-
# Secret to authenticate /api/cron/* endpoints (called by Vercel Cron).
58-
# Generate with: openssl rand -hex 32
59-
CRON_SECRET=your-random-cron-secret
52+
# ─── INFRASTRUCTURE (deployment only) ─────────────────────────────────────────
53+
CLOUDFLARE_ZONE_ID= # Optional — Cloudflare DNS zone for custom domains
54+
CF_DNS_API_TOKEN= # Optional — Cloudflare API token
55+
SERVER_IP= # Optional — deployment target IP
6056

61-
# ─── PayPal (Optional — alternative payment provider) ────────
62-
# Only required if PAYMENT_PROVIDER=paypal
63-
PAYPAL_CLIENT_ID=
64-
PAYPAL_CLIENT_SECRET=
65-
PAYMENT_PROVIDER=stripe # stripe | paypal | manual
57+
# ─── PAYMENTS — PAYPAL ────────────────────────────────────────────────────────
58+
PAYPAL_CLIENT_ID= # Optional — PayPal payment provider
59+
PAYPAL_CLIENT_SECRET= # Optional
60+
PAYMENT_PROVIDER=stripe # Has-Default — stripe | manual | paypal
6661

67-
# ─── MCP Server (Optional — AI development tooling) ──────────
68-
MCP_SERVER_URL=
69-
MCP_PROXY_SECRET=
62+
# ─── MCP SERVER ───────────────────────────────────────────────────────────────
63+
# The mcp-server/ sub-project exposes LMS data to AI agents via MCP protocol.
64+
# See mcp-server/.env.example for the MCP server own env vars.
65+
MCP_PROXY_SECRET= # Optional — shared secret for MCP proxy auth
66+
MCP_SERVER_URL=http://localhost:3001 # Has-Default — URL of the MCP server
7067

71-
# ─── CORS (Optional — restrict API origins) ──────────────────
72-
ALLOWED_ORIGIN=https://yourdomain.com
68+
# ─── CRON ─────────────────────────────────────────────────────────────────────
69+
CRON_SECRET= # Optional — protects cron endpoints (/api/cron/*)
7370

74-
# ─── Local Development Only ──────────────────────────────────
75-
# NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
76-
# NEXT_PUBLIC_PLATFORM_DOMAIN=lvh.me:3000
77-
# NEXT_PUBLIC_APP_URL=http://lvh.me:3000
71+
# ─── INVOICING ────────────────────────────────────────────────────────────────
72+
COMPANY_NAME= # Optional — appears on generated invoices
73+
COMPANY_ADDRESS= # Optional
74+
COMPANY_EMAIL= # Optional
75+
COMPANY_PHONE= # Optional
76+
77+
# ─── TESTING ──────────────────────────────────────────────────────────────────
78+
BASE_URL=http://localhost:3000 # Has-Default — base URL for Playwright tests
79+
E2E_BASE_URL=http://localhost:3000 # Has-Default — explicit E2E base URL
80+
E2E_TENANT_BASE_URL=http://testschool.lvh.me:3000 # Has-Default — tenant subdomain for E2E multi-tenant tests

CLAUDE.md

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,17 +191,48 @@ Feature gating uses `get_plan_features(_tenant_id)` RPC as single source of trut
191191

192192
## Environment Variables
193193

194+
See `.env.example` for the full list with Required/Optional tags (33 vars across 14 categories). The minimum required vars to run locally:
195+
194196
```
195197
NEXT_PUBLIC_SUPABASE_URL=
196198
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY=
197199
SUPABASE_SERVICE_ROLE_KEY= # Bypasses RLS — admin ops only
198-
STRIPE_SECRET_KEY=
199-
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
200-
STRIPE_WEBHOOK_SECRET= # For Connect webhook (student payments)
201-
STRIPE_PLATFORM_WEBHOOK_SECRET= # For Billing webhook (school plan payments)
202-
NEXT_PUBLIC_PLATFORM_DOMAIN= # e.g. lmsplatform.com (for subdomain routing)
200+
NEXT_PUBLIC_PLATFORM_DOMAIN= # e.g. lvh.me for local dev, lmsplatform.com in prod
201+
```
202+
203+
Categories at a glance:
204+
- **Supabase** (3 vars): URL, anon key, service role key
205+
- **Stripe — Student Payments** (3 vars): secret key, publishable key, webhook secret
206+
- **Stripe — School Billing** (1 var): platform webhook secret
207+
- **Platform** (3 vars): domain, app URL, app name
208+
- **AI** (3 vars): OPENAI_API_KEY, NEXT_PUBLIC_OPENAI_API_KEY _(client-side — see Security Notes)_, ASSEMBLYAI_API_KEY
209+
- **Observability / Langfuse** (3 vars): public key, secret key, base URL
210+
- **Email / Mailgun** (4 vars): API key, API URL, domain, from address
211+
- **Certificates** (2 vars): encryption key, issuer name
212+
- **Infrastructure** (3 vars): Cloudflare zone ID, DNS API token, server IP
213+
- **Payments — PayPal** (3 vars): client ID, client secret, PAYMENT_PROVIDER
214+
- **MCP Server** (2 vars): MCP_PROXY_SECRET, MCP_SERVER_URL
215+
- **Cron** (1 var): CRON_SECRET
216+
- **Invoicing** (4 vars): company name, address, email, phone
217+
- **Testing** (3 vars): BASE_URL, E2E_BASE_URL, E2E_TENANT_BASE_URL
218+
219+
## MCP Server
220+
221+
An MCP (Model Context Protocol) sub-server lives in `mcp-server/`. It exposes LMS data to AI agents via the MCP protocol.
222+
223+
**Setup:**
224+
```bash
225+
cd mcp-server
226+
cp .env.example .env # fill in SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, MCP_PROXY_SECRET
227+
npm install
228+
npm run build
229+
npm start
203230
```
204231

232+
The MCP server runs separately from the Next.js app on port 3001 by default (`MCP_SERVER_PORT`). The `mcp:build` npm script builds it from the project root: `npm run mcp:build`.
233+
234+
**Env vars** (see `mcp-server/.env.example`): `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `MCP_PROXY_SECRET`, `MCP_SERVER_PORT`, `MCP_SERVER_HOST`.
235+
205236
## Testing
206237

207238
E2E tests in `tests/playwright/`. Four files by priority:
@@ -210,7 +241,11 @@ E2E tests in `tests/playwright/`. Four files by priority:
210241
- `payment-security.spec.ts` — P0, 7 tests
211242
- `comprehensive-security-audit.spec.ts` — P1/P2, 26 tests
212243

213-
Test accounts: `student@test.com` / `teacher@test.com` / `admin@test.com` — all `password123`
244+
Test accounts (from `supabase/seed.sql` — seeded by `supabase db reset`):
245+
- `student@e2etest.com` / `password123` — student (Default School)
246+
- `owner@e2etest.com` / `password123` — admin (Default School)
247+
- `creator@codeacademy.com` / `password123` — teacher (Code Academy, subdomain: `code-academy.lvh.me:3000`)
248+
- `alice@student.com` / `password123` — student (Code Academy)
214249

215250
Pre-commit checklist: `npm run build` · tenant filter on every query · tested with all relevant roles · loading + error states handled
216251

@@ -235,6 +270,12 @@ Pre-commit checklist: `npm run build` · tenant filter on every query · tested
235270
- **`enroll_user()` RPC** loops through ALL courses per product (FOR loop) — a product can have multiple courses via `product_courses`.
236271
- **Transactions unique constraint** is a partial index on `(user_id, product_id, plan_id) WHERE status IN ('pending', 'successful')` — allows retries after failed payments.
237272

273+
## Security Notes
274+
275+
- **`NEXT_PUBLIC_OPENAI_API_KEY`** is exposed to the browser bundle (used for speech input). Do not use a production key. Server-side proxying is the intended fix (tracked separately).
276+
- **Sentry DSN** is currently hardcoded in `sentry.server.config.ts`. This is intentional (public DSN) but consider moving to an env var for consistency.
277+
- **Test account passwords** (`password123`) are for local development only — seeded by `supabase db reset`. Never use these credentials in a deployed environment.
278+
238279
## Key Documentation
239280

240281
- `docs/DATABASE_SCHEMA.md` — complete schema with relationships

README.md

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,61 @@
1-
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2-
3-
## Getting Started
4-
5-
First, run the development server:
6-
7-
```bash
8-
npm run dev
9-
# or
10-
yarn dev
11-
# or
12-
pnpm dev
13-
# or
14-
bun dev
15-
```
16-
17-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18-
19-
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20-
21-
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22-
23-
## Learn More
24-
25-
To learn more about Next.js, take a look at the following resources:
26-
27-
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28-
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29-
30-
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31-
32-
## Deploy on Vercel
33-
34-
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35-
36-
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
1+
# LMS Platform
2+
3+
A multi-tenant SaaS Learning Management System. Schools run on subdomains (`school.platform.com`). Educators create and sell courses; students enroll and learn.
4+
5+
**Stack:** Next.js 16 · React 19 · TypeScript · Supabase · Shadcn UI · Tailwind CSS v4 · Stripe Connect · next-intl (en/es)
6+
7+
## Prerequisites
8+
9+
- Node.js 20+
10+
- Docker (required for local Supabase)
11+
- [Supabase CLI](https://supabase.com/docs/guides/cli)
12+
- Stripe CLI _(optional — only for testing webhooks locally)_
13+
14+
## Quick Start
15+
16+
1. **Clone and install**
17+
```bash
18+
git clone <repo-url>
19+
cd lms-front
20+
npm install
21+
```
22+
23+
2. **Configure environment**
24+
```bash
25+
cp .env.example .env.local
26+
# Fill in at minimum: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY
27+
```
28+
29+
3. **Start local Supabase** _(requires Docker)_
30+
```bash
31+
supabase start
32+
supabase db reset # applies all migrations + seeds test data
33+
```
34+
35+
4. **Run the dev server**
36+
```bash
37+
npm run dev
38+
```
39+
40+
5. **Open the app**
41+
Visit `http://localhost:3000` — or use a tenant subdomain like `http://testschool.lvh.me:3000`
42+
43+
## npm Scripts
44+
45+
| Script | Command |
46+
|--------|---------|
47+
| `npm run dev` | Start dev server |
48+
| `npm run build` | Production build (TypeScript + lint) |
49+
| `npm run lint` | Run ESLint |
50+
| `npm test` | Run Playwright E2E tests |
51+
| `npm run db:reset` | Reset local DB (migrations + seed) |
52+
| `npm run db:push` | Push migrations to cloud Supabase |
53+
| `npm run mcp:build` | Build the MCP server sub-project |
54+
55+
## Documentation
56+
57+
- [`docs/GETTING_STARTED.md`](docs/GETTING_STARTED.md) — full local setup guide
58+
- [`CLAUDE.md`](CLAUDE.md) — architecture reference for AI agents and developers
59+
- [`docs/DATABASE_SCHEMA.md`](docs/DATABASE_SCHEMA.md) — complete DB schema
60+
- [`docs/AUTH.md`](docs/AUTH.md) — authentication flows
61+
- [`docs/MONETIZATION.md`](docs/MONETIZATION.md) — billing and payments

0 commit comments

Comments
 (0)