A modern, type-safe REST API for laboratory management built with Hono.js, TypeScript, and Cloudflare Workers. This system manages laboratory schedules, equipment tracking, user roles, and seating arrangements for educational institutions.
The Lab System Backend is a comprehensive laboratory management solution designed for educational institutions. It provides a robust API for managing various aspects of computer laboratory operations, including:
- User Management: Role-based access control for administrators, teachers, and technical staff
- Laboratory Management: Track and manage multiple laboratory rooms with real-time status
- Equipment Tracking: Monitor computer equipment conditions (monitors, keyboards, mice, cables)
- Seating Plans: Assign and track student seating with equipment status
- Activity Logging: Maintain historical records of lab usage and equipment conditions
- Scheduling: Manage lab class schedules and availability
The system is built using modern technologies ensuring type safety, performance, and scalability while providing an intuitive API for frontend applications.
- Runtime: Cloudflare Workers with Node.js compatibility
- Framework: Hono.js with OpenAPI integration
- Database: PostgreSQL with Drizzle ORM
- Validation: Zod schemas for type safety
- Authentication: bcryptjs for secure password hashing
- Logging: Pino structured logging
- Package Manager: Bun
- Testing: Vitest for unit and integration testing
- Documentation: Scalar API reference with OpenAPI specification
Before setting up the project, ensure you have the following installed on your system:
- Bun (v1.0.0 or later) - Fast JavaScript runtime
- PostgreSQL database (local or cloud-hosted like Neon)
- Git for version control
- Node.js (v18.0.0 or later) - Required for some dependencies
git clone <repository-url>
cd lab-system-backendThis project uses Bun as the package manager instead of npm:
bun installCopy the example environment files:
cp .env.example .env
cp .dev.vars.example .dev.varsEdit both .env and .dev.vars files with your database connection details:
# Database
DATABASE_URL=postgresql://username:password@localhost:5432/lab_system_db
# Logger
# Options: info | fatal | error | warn | debug | trace | silent
LOG_LEVEL=debug
# Node Environment
# Options: development | production
NODE_ENV=development- Install PostgreSQL on your system
- Create a new database:
CREATE DATABASE lab_system_db;
- Update your
DATABASE_URLin both.envand.dev.vars
- Sign up at Neon
- Create a new project and database
- Copy the connection string to your environment files
Generate and apply database schema:
# Generate migration files (if you adjusted anythig in the schema otherwise just run bun run drizzle-kit push)
bunx drizzle-kit generate
# Push schema to database
bunx drizzle-kit pushThe system uses SendGrid for sending password reset emails. Follow these steps to configure email functionality:
- Sign up at SendGrid
- Complete account verification
- Navigate to Settings > API Keys
- Click "Create API Key"
- Choose "Restricted Access"
- Grant the following permissions:
- Mail Send: Full Access
- Sender Authentication: Read Access (optional, for verification)
- Copy the generated API key
Important: SendGrid requires sender verification to prevent spam.
- Go to Settings > Sender Authentication
- Click "Verify a Single Sender"
- Fill in your details:
- From Name: Your organization name (e.g., "Lab System")
- From Email: Your verified email address
- Reply To: Same as From Email (recommended)
- Company Address: Your organization's address
- Click "Create" and check your email for verification
- Click the verification link in the email
The system supports both inline HTML emails and SendGrid dynamic templates. Using templates provides better email design and easier management.
- Navigate to Email API > Dynamic Templates in SendGrid
- Create a new template or use the existing template ID:
d-07f4668c32d94aac9d7d93dcf19b7ab4 - Template Variables: The system passes these variables to your template:
{{username}}- The user's username{{reset_link}}- The password reset URL
Template HTML Structure (if creating your own):
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lab System - Reset Password</title>
</head>
<body style="margin: 0; padding: 0; background-color: #f5f5f5; font-family: Arial, sans-serif">
<!-- Your template content here -->
<p>Hello <strong>{{username}}</strong>,</p>
<p>Click the button below to reset your password:</p>
<a
href="{{reset_link}}"
style="background-color: #007bff; color: #ffffff; padding: 12px 24px; text-decoration: none; border-radius: 5px"
>
Reset Password
</a>
<!-- Rest of your template -->
</body>
</html>Add the following to both .env and .dev.vars files:
# Email Configuration - SendGrid
SENDGRID_API_KEY=your_sendgrid_api_key_here
SENDGRID_TEMPLATE_ID=d-07f4668c32d94aac9d7d93dcf19b7ab4
[email protected]
# Password Reset Configuration
BCRYPT_COST=10
APP_URL=http://localhost:5173
RESET_TOKEN_EXPIRY_HOURS=1
# Frontend URL (for CORS and redirects)
FRONTEND_URL=http://localhost:5173Important Notes:
- Use the same verified email in both
SMTP_FROMvariables - The
SMTP_FROMemail must match exactly what you verified in SendGrid - For development, ensure
.dev.varshas the correctSMTP_FROMvalue
-
Start the development server:
bun run dev
-
Create a test user (or use existing user)
-
Test password reset:
curl -X POST http://localhost:8787/auth/forgot-password \ -H "Content-Type: application/json" \ -d '{"email":"[email protected]"}'
-
Check the server logs for success message:
Password reset token generated and email sent
Issue: 403 - The from address does not match a verified Sender Identity
- Solution: Ensure
SMTP_FROMmatches exactly the email you verified in SendGrid - Check: Both
.envand.dev.varshave the same verified email
Issue: 400 - text/plain must be first, followed by text/html
- Solution: This is already fixed in the codebase (content order corrected)
Issue: No email received but logs show success
- Solution: Check spam folder, verify recipient email exists in database
Issue: 401 - Unauthorized
- Solution: Verify your SendGrid API key is correct and has Mail Send permissions
To customize the email template:
- Log into SendGrid and navigate to Email API > Dynamic Templates
- Find your template (ID:
d-07f4668c32d94aac9d7d93dcf19b7ab4) or create a new one - Edit the template using SendGrid's drag-and-drop editor or HTML editor
- Use these variables in your template:
{{username}}- User's display name{{reset_link}}- Complete password reset URL
- Test the template using SendGrid's preview feature
- Update the template ID in your environment variables if you create a new template
The system uses SendGrid for email delivery:
# Resend Configuration (alternative to SendGrid)
RESEND_API_KEY=your_resend_api_key_herePriority Order:
- SendGrid with Template (if
SENDGRID_API_KEYandSENDGRID_TEMPLATE_IDare set) - SendGrid with Inline HTML (if only
SENDGRID_API_KEYis set) - Development logging (no actual email sent)
Template Benefits:
- Professional email design with consistent branding
- Easy template management through SendGrid interface
- Better deliverability and spam protection
- Responsive design for mobile devices
Start the development server:
bun run devThe API will be available at http://localhost:8787
| Script | Command | Description |
|---|---|---|
| Development | bun run dev |
Start development server with hot reload |
| Build & Deploy | bun run deploy |
Deploy to Cloudflare Workers |
| Type Generation | bun run cf-typegen |
Generate TypeScript types for Cloudflare bindings |
| Linting | bun run lint |
Run ESLint code quality checks |
| Lint Fix | bun run lint:fix |
Automatically fix linting issues |
| Tests | bun run test |
Run unit and integration tests |
| Generate Migration | bunx drizzle-kit generate |
Generate new migration files |
| Push Schema | bunx drizzle-kit push |
Push schema changes to database |
| Database Studio | bunx drizzle-kit studio |
Open Drizzle Studio (database GUI) |
GET /- API welcome messageGET /health- Health check endpoint
POST /auth/login- User login with email and passwordPOST /auth/refresh- Refresh authentication tokenPOST /auth/logout- User logoutGET /auth/me- Get current user informationPOST /auth/forgot-password- Request password reset emailPOST /auth/reset-password- Reset password with tokenGET /auth/validate-reset-token- Validate reset token
POST /users- Create new user accountGET /users- List users with paginationGET /users/:id- Get specific user detailsPUT /users/:id- Update user informationDELETE /users/:id- Soft delete userPATCH /users/:id/restore- Restore soft deleted userDELETE /users/:id/hard- Permanently delete user
GET /teachers- List teachers with paginationGET /teachers/:id- Get specific teacher detailsGET /teachers/:id/laboratories- Get laboratories assigned to teacherGET /teachers/:id/dashboard- Get teacher dashboard data
GET /laboratories- List laboratories with paginationPOST /laboratories- Create new laboratoryGET /laboratories/:id- Get specific laboratory detailsPUT /laboratories/:id- Update laboratory informationDELETE /laboratories/:id- Delete laboratory
GET /subjects- List subjects with paginationPOST /subjects- Create new subjectGET /subjects/:id- Get specific subject detailsPUT /subjects/:id- Update subject informationDELETE /subjects/:id- Delete subject
- Interactive Documentation:
http://localhost:8787/reference - OpenAPI Specification:
http://localhost:8787/docs
The API documentation provides comprehensive information about all endpoints, request/response schemas, and example usage.
curl -X POST http://localhost:8787/users \
-H "Content-Type: application/json" \
-d '{
"username": "johndoe",
"email": "[email protected]",
"password": "SecurePassword123",
"confirmPassword": "SecurePassword123",
"user_type": "teacher"
}'curl "http://localhost:8787/teachers?page=1&limit=10"- Request Password Reset:
curl -X POST http://localhost:8787/auth/forgot-password \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}'- Reset Password with Token (from email):
curl -X POST http://localhost:8787/auth/reset-password \
-H "Content-Type: application/json" \
-d '{
"token":"selector.verifier_from_email",
"newPassword":"NewSecurePassword123"
}'src/
├── index.ts # Main application entry point
├── db/ # Database layer
│ ├── index.ts # Database connection factory
│ └── schema.ts # Drizzle schemas & Zod validation
├── lib/ # Core application utilities
│ ├── create-app.ts # App factory with middleware
│ ├── openapi-configuration.ts # API docs setup
│ └── types/ # TypeScript definitions
├── middleware/ # Request processing middleware
│ ├── env.ts # Environment validation
│ ├── pino-logger.ts # Logging middleware
│ └── utils/ # Utility middleware
├── routes/ # API route definitions
│ ├── index.ts # Root routes
│ ├── auth/ # Authentication routes
│ ├── users/ # User management routes
│ ├── teachers/ # Teacher management routes
│ ├── laboratories/ # Laboratory management routes
│ └── subjects/ # Subject management routes
├── handlers/ # Business logic implementations
│ ├── auth/ # Authentication handlers
│ ├── users/ # User-related handlers
│ ├── teachers/ # Teacher-related handlers
│ ├── laboratories/ # Laboratory-related handlers
│ └── subjects/ # Subject-related handlers
├── services/ # Business service layer
│ ├── UserService.ts # User business logic
│ ├── TeacherService.ts # Teacher business logic
│ ├── LaboratoryService.ts # Laboratory business logic
│ ├── SubjectService.ts # Subject business logic
│ ├── EmailService.ts # Email sending functionality
│ └── PasswordResetService.ts # Password reset logic
└── openapi/ # OpenAPI utilities
The API provides comprehensive documentation through:
- Interactive API Reference: Available at
http://localhost:8787/referencewhen running the development server - OpenAPI Specification: Available at
http://localhost:8787/docs - Built-in Validation: All endpoints include Zod schema validation with detailed error messages
The documentation includes:
- Detailed endpoint descriptions
- Request/response schemas
- Example requests and responses
- Authentication requirements
- Error codes and messages
We welcome contributions! Please read our CONTRIBUTION.md for detailed information on:
- Development Environment Setup
- Code Style Guidelines
- Testing with Vitest
- Architecture Patterns
- Deployment Process
- Troubleshooting Guide
- Read the CONTRIBUTION.md - Essential setup and guidelines
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Follow the development patterns outlined in CONTRIBUTION.md
- Test your changes thoroughly
- Submit a Pull Request
This project uses Vitest for unit and integration testing. See CONTRIBUTION.md for detailed testing guidelines.
# Run tests
bun run test
# Run tests with UI
bun run test:ui
# Run tests once
bun run test:run
# Run tests with coverage
bun run test:coveragebun run deployFor detailed deployment instructions and environment configuration, see CONTRIBUTION.md.
- Documentation: Check CONTRIBUTION.md for comprehensive guides
- Issues: Report bugs or request features via GitHub Issues
- Questions: Create a discussion or issue for help
This project is licensed under the terms specified in the LICENSE file.
Ready to contribute? Start by reading our CONTRIBUTION.md guide!