A robust Node.js backend application built with Express, TypeScript, and PostgreSQL. Features include authentication, file uploads, real-time communication, and cloud storage integration.
- Authentication & Authorization - JWT-based auth with access/refresh tokens
- Database - PostgreSQL with Drizzle ORM
- File Upload & Storage - AWS S3-compatible storage (DigitalOcean Spaces)
- Image Processing - Sharp for image optimization
- Real-time Communication - Socket.IO integration
- Email Service - Resend API integration
- Type Safety - Full TypeScript support
- Data Validation - Zod schema validation
- Testing - Vitest testing framework
- Development Tools - ESLint, Prettier, hot reload
- Node.js (v18 or higher)
- pnpm (v10.6.5+)
- Docker & Docker Compose
- PostgreSQL
-
Clone the repository
git clone <repository-url> cd fyp-backend
-
Install dependencies
pnpm install
-
Environment Setup
Create
.env
file in the root directory:PORT=4000 DB_URL=postgresql://username:password@localhost:5432/database_name ACCESS_TOKEN_SECRET=your_access_token_secret REFRESH_TOKEN_SECRET=your_refresh_token_secret POSTGRES_USER=your_postgres_user POSTGRES_PASSWORD=your_postgres_password POSTGRES_DB=your_database_name NODE_ENV=development APP_ORIGIN=http://localhost:3000 RESEND_API_KEY=your_resend_api_key SPACES_ENDPOINT=your_spaces_endpoint SPACES_KEY=your_spaces_key SPACES_SECRET=your_spaces_secret SPACES_REGION=your_spaces_region BUCKET_NAME=your_bucket_name EMAIL_SENDER=your_email@domain.com
For testing, create
.env.test.local
:# Same as above but with test database configurations DB_URL=postgresql://username:password@localhost:5433/test_database POSTGRES_DB=test_database # ... other test-specific variables
-
Start the development database
pnpm run db:dev:up
-
Run database migrations
pnpm run drizzle:dev:migrate
-
Seed the database (optional)
pnpm run db:dev:seed
-
Start the development server
pnpm run dev
The server will start on http://localhost:4000
with hot reload enabled.
-
Build the application
pnpm run build
-
Start the production server
pnpm start
- Start database:
pnpm run db:dev:up
- Remove database:
pnpm run db:dev:rm
- Restart database:
pnpm run db:dev:restart
- Open Drizzle Studio:
pnpm run db:studio
- Generate migration:
pnpm run drizzle:dev:generate
- Create migration:
pnpm run drizzle:dev:generate -custom
- Generate custom migration:
pnpm run drizzle:dev:generate --custom
- After generating, add this trigger function to the migration file:
-- Custom SQL migration file, put your code below! -- CREATE OR REPLACE FUNCTION update_has_store_trigger() RETURNS TRIGGER AS $$ BEGIN -- If role is 'seller', set has_store to true, else false IF NEW.role = 'seller' THEN NEW.has_store := TRUE; ELSE NEW.has_store := FALSE; END IF; -- Update timestamp on insert or update NEW.updated_at := NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS profile_has_store_trigger ON profiles; CREATE TRIGGER profile_has_store_trigger BEFORE INSERT OR UPDATE ON profiles FOR EACH ROW EXECUTE FUNCTION update_has_store_trigger();
- This trigger automatically sets has_store field based on role and updates timestamps
- After generating, add this trigger function to the migration file:
- Apply migrations:
pnpm run drizzle:dev:migrate
- Push schema changes:
pnpm run drizzle:dev:deploy
- Start test database:
pnpm run db:test:up
- Remove test database:
pnpm run db:test:rm
- Restart test database:
pnpm run db:test:restart
# Lint code
pnpm run lint
# Fix linting issues
pnpm run lint:fix
# Format code
pnpm run format
Variable | Description | Required |
---|---|---|
PORT |
Server port | Yes |
DB_URL |
PostgreSQL connection string | Yes |
ACCESS_TOKEN_SECRET |
JWT access token secret | Yes |
REFRESH_TOKEN_SECRET |
JWT refresh token secret | Yes |
POSTGRES_USER |
PostgreSQL username | Yes |
POSTGRES_PASSWORD |
PostgreSQL password | Yes |
POSTGRES_DB |
PostgreSQL database name | Yes |
NODE_ENV |
Environment (development/production) | Yes |
APP_ORIGIN |
Frontend application URL | Yes |
RESEND_API_KEY |
Resend email service API key | Yes |
SPACES_ENDPOINT |
DigitalOcean Spaces endpoint | Yes |
SPACES_KEY |
DigitalOcean Spaces access key | Yes |
SPACES_SECRET |
DigitalOcean Spaces secret key | Yes |
SPACES_REGION |
DigitalOcean Spaces region | Yes |
BUCKET_NAME |
Storage bucket name | Yes |
EMAIL_SENDER |
Email sender address | Yes |
The application provides RESTful APIs for:
- Authentication - Login, register, token refresh
- User Management - Profile management, user operations
- File Upload - Image upload and processing
- Real-time Features - WebSocket connections via Socket.IO
- Email Services - Transactional emails via Resend
- Node.js - Runtime environment
- Express - Web framework
- TypeScript - Type-safe JavaScript
- PostgreSQL - Primary database
- Drizzle ORM - Type-safe database toolkit
- Docker - Database containerization
- JWT - JSON Web Tokens
- Argon2 - Password hashing
- CORS - Cross-origin resource sharing
- Multer - File upload middleware
- Sharp - Image processing
- AWS SDK - S3-compatible storage
- Socket.IO - Real-time communication
- Resend - Email service
- Vitest - Testing framework
- Pactum - API testing
- ESLint - Code linting
- Prettier - Code formatting
- tsx - TypeScript execution
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Script | Description |
---|---|
dev |
Start development server with hot reload |
build |
Build for production |
start |
Start production server |
test |
Run test suite |
lint |
Run ESLint |
lint:fix |
Fix ESLint issues |
format |
Format code with Prettier |
db:dev:up |
Start development database |
db:dev:restart |
Restart development database |
db:studio |
Open Drizzle Studio |
drizzle:dev:migrate |
Run database migrations |
drizzle:dev:generate |
Generate new migration |
db:dev:seed |
Seed database with initial data |
This project is licensed under the MIT License.
Yusf Nuru Yesuf
For more information or support, please refer to the project documentation or create an issue in the repository.