EduCloud Lite is a free-course React + FastAPI learning management system backed by Supabase PostgreSQL and Amazon Cognito. It supports verified-email signup, role-based learning, course authoring, multipart S3 video uploads, ratings and reviews, assessments, certificates, and AWS operations dashboards.
The current production build provides the following working flows:
- Replaced frontend-only/demo authentication behavior with Cognito email verification, resend-code, login token exchange, and two-step forgot-password/reset UI.
- Added Student/Instructor selection at signup. Instructor applicants remain Students until an Admin approves their application; rejected applications include a review note and can be resubmitted.
- Added Student profiles and certificate identity fields stored in Supabase.
- Added live Student learning data, resume-from-first-incomplete-lesson behavior, and Instructor enrollment/completion counts.
- Added Instructor-authored final assessments with configurable multiple-choice questions, correct answers, pass score, attempt limit, publication state, and backend-enforced time limit.
- Changed course completion so finishing lessons unlocks the final assessment; a certificate is issued only after a passing attempt.
- Added a branded certificate page with Student name, course, issue date, EduCloud logo, and Print/Save-as-PDF support without exposing the internal certificate identifier.
- Replaced fixed Admin/Student dashboard values with Supabase-backed aggregations, added Instructor application review, course visibility oversight, and a separate Admin Health page.
- Protected lesson content from public APIs, added role/ownership checks, uniqueness constraints, security headers, and demo rate limiting for sensitive authentication requests.
- Expanded automated backend coverage to 12 passing tests and verified the frontend production build.
Private S3/CloudFront media delivery, multipart video upload, course reviews, Cost Explorer metrics, and CloudWatch log viewing are deployed. All courses are intentionally free; payment processing and server-generated certificate PDFs remain outside the project scope.
- Amazon Cognito signup, six-digit email confirmation, resend code, login, and forgot/reset password.
- Reset-code requests pass through FastAPI and call Cognito only when the email is linked in Supabase via
cognito_sub, while returning a generic anti-enumeration response. - FastAPI validates Cognito ID tokens and exchanges them for 12-hour EduCloud JWTs containing the current Supabase role.
- Development student, instructor, and admin accounts stored in Supabase.
- Role guards for student, instructor, and admin pages.
- Published course catalog and course search loaded from Supabase.
- Instructor course CRUD, course settings, curriculum CRUD, thumbnails, videos, and materials.
- Free-only course publishing with no price or payment workflow.
- Verified Student ratings/reviews and aggregate course scores.
- Presigned multipart video upload to private S3 with CloudFront delivery.
- Removing or replacing a lesson attachment clears its database URL and deletes the previous course object from S3; deleting a lesson also removes dependent progress rows safely.
- Student enrollment, Learning Page playlist, lesson completion, and course progress persisted in Supabase.
- Instructor-managed timed final assessments with configurable questions, answers, pass mark, attempt limit, and time limit.
- Student profile setup and automatic, idempotent certificate issuance only after all lessons are complete and the final assessment is passed.
- Printable EduCloud certificate page with student name, course, issue date, logo, and browser Save-as-PDF support.
- Student dashboard calculated from
enrollments,progress,courses, andlessons. - Instructor course list with live enrolled-student and completed-student counts.
- Signup choice for Student or Instructor; Instructor applicants are safely created as students and routed into the admin-approved application flow.
- Admin overview calculated from live users, roles, courses, lessons, and enrollments, with instructor approval and course visibility controls.
- Admin Health Monitoring for traffic, database, live S3 inventory and Cost Explorer values, plus a separate CloudWatch Logs viewer.
- Public course APIs expose outlines only; lesson notes, videos, and materials require enrollment or course ownership.
- Basic auth rate limiting, API security headers, student-only enrollment/progress checks, and database uniqueness constraints.
- Swagger, Postman workspace, and isolated backend tests.
Cognito, S3, CloudFront, Elastic Beanstalk, Amplify, Cost Explorer, and CloudWatch Logs are integrated in production. Local storage remains available for development, and certificates can be printed or saved as PDF in the browser.
This section is the current handoff summary for teammates and reviewers.
React + Vite frontend (localhost:5173)
|
| Cognito signup/login + JSON / Bearer JWT
v
Amazon Cognito User Pool (verified email and password recovery)
|
| verified Cognito ID token
v
FastAPI backend (localhost:8001)
|
| SQLAlchemy + psycopg2, SSL
v
Supabase hosted PostgreSQL
Supabase remains the application database and role authority; it is not used for authentication. Cognito owns passwords, confirmation codes, and password recovery. FastAPI verifies the Cognito token, maps its sub to users.cognito_sub, and issues an EduCloud JWT using the role stored in Supabase. Local bcrypt login remains development-only while seeded accounts are migrated.
| Table | Purpose |
|---|---|
users |
Profile, email, application role, Cognito subject, and optional legacy password hash |
courses |
Course settings, publishing status, instructor ownership, and thumbnail URL |
lessons |
Ordered curriculum, notes, video URL, and material URL |
enrollments |
Student-to-course membership and enrollment status |
progress |
Per-student lesson completion state |
student_profiles |
Certificate name, birth date, organization, country, and student bio |
certificates |
One immutable certificate record per student/course completion |
instructor_requests |
Instructor applications, review status, admin notes, and reviewer audit data |
course_assessments |
Per-course final test settings, pass mark, timer, attempt limit, and publication state |
assessment_questions |
Multiple-choice questions, options, correct answers, and ordering |
assessment_attempts |
Timed student attempts, submitted answers, score, and pass/fail state |
Development compatibility migrations add missing course detail and user auth columns on startup. This is suitable for the current prototype; production should replace it with versioned Alembic migrations.
| Role | Working behavior |
|---|---|
| Student | Register/login, complete a profile, learn, take timed final assessments, print certificates, and submit/resubmit an instructor application |
| Instructor | Manage owned courses/lessons/final assessments, publish/hide content, upload resources, delete unused drafts, and view enrollment/certificate counts |
| Admin | Inspect metrics/recent users, approve/reject instructor applications, moderate course visibility, and monitor system health |
- Public registration always creates
student; a client cannot register itself as admin. - Course/lesson/upload mutations require instructor or admin authorization and ownership checks.
- Lesson attachment updates use explicit
nullvalues to remove existing video/material URLs. The backend performs best-effort cleanup of the previous object under the owningcourses/{course_id}/S3 prefix. - Only published courses appear in the public catalog; draft/hidden course detail is not public.
- Public detail contains lesson titles only. Full notes, video URLs, and material URLs require enrollment, ownership, or Admin access.
- Enrollment and lesson progress are Student-only, enrollment accepts published courses only, and unique database indexes prevent duplicate enrollment/progress rows.
- A course must contain at least one lesson and a published final assessment before it can be published.
- Assessment deadlines and attempt limits are enforced by the backend, not only by the browser timer.
- Certificate issuance is idempotent and requires every lesson plus a passing assessment attempt; an issued completion cannot be undone.
- Existing eligible completions are backfilled after a passing attempt when the student opens My Learning or course progress.
- Student and admin dashboards calculate values from database rows; they contain no fixed demo metrics.
- The frontend automatically attaches the signed-in JWT to API requests.
- The certificate has a printable HTML template; automatic server-side PDF rendering/upload to S3 is reserved for the AWS stage (
certificates.file_url). - Admin can review instructor applications and course visibility, but general role editing and account suspension/deletion are not implemented.
- Traffic metrics are process-local and reset after backend restart. Production aggregation should use CloudWatch or another shared metrics store.
- Schema evolution still uses a development compatibility helper instead of Alembic.
- The checked-in Postman collection began with the legacy development-token flow; replace its token variable with a login JWT when testing protected endpoints.
Prerequisites: Python 3.11+, Node.js 18+, your own Supabase project, and your own Amazon Cognito User Pool.
Each installation must use its own Supabase project. Do not reuse another developer's database password or committed connection string.
- Create a project in Supabase and save the database password in a password manager.
- Open Connect, choose Session Pooler, and copy the URI using port
5432. - Change the URI scheme from
postgresql://topostgresql+psycopg2://. - URL-encode the database password and ensure the URI ends with
sslmode=require. - Create the ignored local environment file:
Copy-Item backend/.env.example backend/.envTo URL-encode a password containing characters such as @, #, %, or /:
$password = Read-Host "Supabase database password"
[uri]::EscapeDataString($password)
Remove-Variable passwordPlace the encoded result only in backend/.env:
DATABASE_URL=postgresql+psycopg2://postgres.PROJECT_REF:URL_ENCODED_PASSWORD@POOLER_HOST:5432/postgres?sslmode=require
APP_ENV=development
ENABLE_DEV_AUTH=true
JWT_SECRET_KEY=replace-with-a-long-random-value
COGNITO_REGION=YOUR_AWS_REGION
COGNITO_USER_POOL_ID=YOUR_COGNITO_USER_POOL_ID
COGNITO_CLIENT_ID=YOUR_COGNITO_APP_CLIENT_ID
ALLOW_LEGACY_AUTH=trueGenerate a separate JWT secret for each installation:
$bytes = New-Object byte[] 64
[System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes)
[Convert]::ToBase64String($bytes)
Remove-Variable bytesbackend/.env is ignored by Git. Never put DATABASE_URL, the database password, or JWT_SECRET_KEY in the README, Dockerfile, frontend variables, screenshots, or commits.
Install dependencies, verify the connection, create the EduCloud tables, and optionally seed local development accounts:
cd backend
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements-dev.txt
python -m scripts.check_database
python -c "import main"
python -m scripts.seed_dev_accounts
python -m uvicorn main:app --reload --port 8001The first backend import/start creates the required tables in that developer's Supabase database. scripts.check_database prints the connected database and user without printing the password.
Create frontend/.env, then replace all YOUR_* values with the same Cognito configuration used by the backend:
cd frontend
Copy-Item .env.example .env
npm install
npm run devOpen http://localhost:5173. API health and Swagger are available at http://127.0.0.1:8001 and http://127.0.0.1:8001/docs.
Run python -m scripts.seed_dev_accounts before using these accounts. The shared development password is Demo123!.
| Role | |
|---|---|
| Student | student@educloud.local |
| Instructor | instructor@educloud.local |
| Admin | admin@educloud.local |
| Admin (backup) | admin2@educloud.local |
These are development-only accounts. The seed command updates their password hashes each time it runs.
- Sign in as the instructor and open Instructor.
- Create a course as
Draft. - Open Edit, add at least two lessons and optionally upload a video/material.
- In Final assessment, add questions, choose correct options, set pass mark/time/attempt limit, publish the assessment, and save it.
- Change the course status to
Publishedand confirm it appears in the public catalog.
- Register a new student; after registration, confirm the app opens Profile.
- Save the certificate name and optional date of birth, organization, country, and bio; verify
student_profilesin Supabase. - Open Courses, select a published course, and click Start Course; verify
enrollments. - Mark every lesson complete and confirm Take final test appears.
- Start the timed assessment, submit a passing answer set, and confirm the certificate-issued result.
- Open Profile, open the certificate template, and test Print / Save as PDF.
- Verify one matching row exists in
certificatesand one passed row exists inassessment_attempts. - Click Start/Continue Course again and confirm unfinished courses resume at the first incomplete lesson.
Return to the instructor's All courses page and verify the Students and Completed columns match enrollments and certificates in Supabase.
- Sign out, then sign in as admin.
- After a student submits Become an instructor from Profile, confirm it appears in Application review queue.
- Rejecting requires a review note; confirm the student can read that note and resubmit.
- Approve the request and verify
users.rolechanges toinstructorand the request becomesapprovedin Supabase. - The approved user must sign out and sign in again before Instructor navigation appears.
- Verify a student account cannot open
/adminor call/api/admin/dashboard. - Use Course oversight to hide/publish a valid course.
- Open Health, confirm database/traffic/storage/service metrics load and refresh.
- Set
ALLOW_LEGACY_AUTH=falseandENABLE_DEV_AUTH=falseoutside local development. - Replace
JWT_SECRET_KEYwith a long random secret and never commitbackend/.env, AWS keys, database passwords, or Cognito secrets. - Restrict
CORS_ORIGINSto the deployed Amplify domain; keep HTTPS enabled everywhere. - Use a least-privilege Supabase database account, retain SSL, enable backups, and avoid exposing its connection string to the frontend.
- Keep Cognito email verification and strong password policy enabled; optional MFA can be added for Admin accounts.
- Current bearer tokens live in
sessionStorage; a production hardening step is short-lived access tokens plus Secure, HttpOnly, SameSite cookies and refresh-token rotation. - Keep the S3 bucket private, use CloudFront OAC for reads, and upload with short-lived presigned multipart requests.
- Add AWS Budgets alerts, CloudWatch alarms for 5xx/latency, and WAF managed rules/rate limits when deploying publicly.
- The included in-memory auth limiter and response security headers are appropriate for a demo. Multi-instance production should move rate limiting to WAF, API Gateway, or Redis.
cd backend
.\.venv\Scripts\python.exe -m pytest -q
cd ..\frontend
npm run buildSee backend/README.md, frontend/README.md, and api/README.md for component-specific details.