Hobby2025
DevCode Academy LMS
A role-based learning management system for programming schools.
- Roles
- Admin · Teacher · Student
- Tables
- 17
- Pages
- 30+
- Migrations
- Drizzle Kit
01Overview
DevCode Academy runs a programming school end to end: courses and lessons, live class sessions with attendance, assignments with grading, public certificate verification and a blog.
Each role gets its own dashboard and navigation, backed by a single typed schema shared by the client and the server.
02Architecture
A React single-page app talks to an Express REST API. The database schema is defined once in a shared module and reused for queries, migrations and request validation.
Client
Admin
Courses, teachers, students
Teacher
Lessons, grading, attendance
Student
Courses, assignments, grades
Public
Landing, blog, certificate check
Client runtime
Wouter
Routing
TanStack Query
Server-state cache
React Hook Form + Zod
Validated forms
API
REST routes
Express · TypeScript ESM
Auth
Sessions + role guards
Storage layer
Repository over Drizzle
Shared
shared/schema.ts
Drizzle tables + drizzle-zod schemas
Data
PostgreSQL
Neon serverless
Session store
connect-pg-simple
03Components
Course domain
Content and enrolment
- Courses → lessons → materials and lesson assignments, plus separate offline courses with their own enrolments.
- Lesson progress is tracked per student and aggregated on dashboards.
Live sessions & attendance
Classroom operations
- Teachers open a lesson session; a global active-session bar follows them across pages.
- Attendance is recorded per session and visible to students.
Assignments & grading
Learning loop
- Students submit work, teachers grade with feedback, grades roll up into the student's record.
Certificates
Trust outside the platform
- Certificates are issued on completion and can be verified publicly by anyone with the certificate code.
04How it works
- 1
Admin
Creates courses and assigns teachers.
- 2
Teacher
Builds lessons, runs live sessions, takes attendance.
- 3
Student
Enrols, follows lessons, submits assignments.
- 4
Teacher
Grades submissions; progress updates on both dashboards.
- 5
Platform
Issues a verifiable certificate on completion.
05Technical deep dives
One schema, three uses
Tables are declared once with Drizzle. The same definitions produce SQL migrations, typed queries on the server, and Zod insert schemas that validate request bodies and client forms - so the API contract cannot drift from the database.
export const courses = pgTable("courses", {
id: serial("id").primaryKey(),
title: varchar("title", { length: 255 }).notNull(),
level: varchar("level", { enum: ["beginner", "intermediate", "advanced"] }).notNull(),
instructorId: varchar("instructor_id").notNull(),
isActive: boolean("is_active").default(true),
enrollmentCount: integer("enrollment_count").default(0),
createdAt: timestamp("created_at").defaultNow(),
updatedAt: timestamp("updated_at").defaultNow(),
});
// Reused by the API (request validation) and the client (forms)
export const insertCourseSchema = createInsertSchema(courses).omit({
id: true,
createdAt: true,
updatedAt: true,
});
export type InsertCourse = z.infer<typeof insertCourseSchema>;06Design decisions
Storage interface between routes and database
Routes depend on a storage abstraction, not on Drizzle directly, which keeps handlers thin and the data layer testable.
Server state in TanStack Query
No global client store: server data is cached and invalidated by query keys, UI state stays local.
Sessions in PostgreSQL
Sessions live in the same database, so the app scales horizontally without a separate session service.
07Tech stack
- Frontend
- React 18TypeScriptViteTailwind CSSshadcn/uiTanStack QueryWouter
- Backend
- Node.jsExpressPassportexpress-session
- Data
- PostgreSQL (Neon)Drizzle ORMdrizzle-zod
08What's next
- Automated grading for code assignments.
- Real-time notifications for live sessions.
Next case study
Crypto Trading Bot
A multi-indicator trading engine with live dashboard, backtesting and Telegram control.