Rust backend service for the Merhaba Online Booking System (OBS) - Turkish Language Learning Platform.
- User Management: Complete CRUD for students with auto-generated student numbers (MMYY format)
- Audio Materials: Upload and manage MP3 listening materials
- Video Materials: Manage YouTube video links for lessons
- Handbook Management: Manage PDF/external book materials with cover images
- JWT Authentication: Secure token-based authentication
- Public API: Student endpoints for accessing learning materials
- Pagination: Built-in pagination for all list endpoints
- Swagger/OpenAPI: Interactive API documentation at
/swagger-ui/ - File Upload: Multipart file upload support for audio and images
- Language: Rust (Edition 2021)
- Web Framework: Actix-Web 4.4
- Database: MongoDB (official driver, TLS)
- Authentication: JWT (jsonwebtoken) + bcrypt
- API Documentation: Utoipa + Swagger UI
- Validation: Validator crate
- Rust 1.70+ (install from rustup.rs)
- MongoDB cluster (Atlas atau self-hosted)
- (Optional) OpenSSL dev libraries for build
cd /Users/baundx/Projects/Merhaba/obs-rustcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/envcargo buildSalin .env dari contoh di bawah. Jangan menaruh URI atau password asli di README / commit Git.
MONGO_URI=mongodb+srv://USER:PASSWORD@cluster.example.mongodb.net/?retryWrites=true&w=majority
MONGO_DB=merhaba
JWT_SECRET=ganti-dengan-string-acak-panjang
HOST=0.0.0.0
PORT=8080
RUST_LOG=infoVariabel sensitif hanya di file .env lokal (sudah di .gitignore).
cargo runThe server will start at http://localhost:8080
Open your browser and navigate to:
http://localhost:8080/swagger-ui/
GET /health
POST /api/auth/login
Request body:
{
"fullname": "user@example.com",
"password": "password"
}POST /api/admin/users - Create user
GET /api/admin/users - List users (with pagination)
GET /api/admin/users/{id} - Get user details
PUT /api/admin/users/{id} - Update user
DELETE /api/admin/users/{id} - Delete user
POST /api/admin/audio - Create audio (with file upload)
GET /api/admin/audio - List audio files
GET /api/admin/audio/{id} - Get audio details
PUT /api/admin/audio/{id} - Update audio
DELETE /api/admin/audio/{id} - Delete audio
POST /api/admin/videos - Create video
GET /api/admin/videos - List videos
GET /api/admin/videos/{id} - Get video details
PUT /api/admin/videos/{id} - Update video
DELETE /api/admin/videos/{id} - Delete video
POST /api/admin/handbooks - Create handbook
GET /api/admin/handbooks - List handbooks
GET /api/admin/handbooks/{id} - Get handbook details
PUT /api/admin/handbooks/{id} - Update handbook
DELETE /api/admin/handbooks/{id} - Delete handbook
GET /api/audio - List public audio
GET /api/audio/{id} - Get public audio
GET /api/videos - List public videos
GET /api/videos/{id} - Get public video
GET /api/handbooks - List public handbooks
GET /api/handbooks/{id} - Get public handbook
curl http://localhost:8080/healthcurl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"fullname": "admin@example.com",
"password": "yourpassword"
}'curl -X POST http://localhost:8080/api/admin/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"fullname": "Ahmet Yılmaz",
"email": "ahmet@example.com",
"password1": "password123",
"password2": "password123",
"city": "İstanbul",
"phone_num": "+905551234567",
"start_date": "2024-03-15",
"role_id": 2,
"status": "Active",
"gender": "erkek",
"status_pembayaran": "Paid Off"
}'curl "http://localhost:8080/api/admin/users?page=1&size=10&role_id=2" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"curl -X POST http://localhost:8080/api/admin/audio \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-F "judul=Listening Exercise 1" \
-F "sub_judul=Basic Greetings" \
-F "dialog=Merhaba! Nasılsınız?" \
-F "kelimeler=Merhaba, Nasılsınız, İyiyim" \
-F "user_sub_lesson_id=1" \
-F "audio=@/path/to/audio.mp3"curl -X POST http://localhost:8080/api/admin/videos \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"lesson_id": 1,
"topik": "Ders",
"title": "Turkish Alphabet - Video 1",
"description": "Learn the Turkish alphabet from A to Z",
"link": "https://www.youtube.com/watch?v=example"
}'curl -X POST http://localhost:8080/api/admin/handbooks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"lesson_id": 1,
"title": "Turkish Grammar Book - Level A1",
"description": "Comprehensive grammar guide for beginners",
"link": "https://drive.google.com/file/d/example"
}'obs-rust/
├── Cargo.toml # Project dependencies
├── .env # Environment configuration
├── .gitignore
├── README.md
├── uploads/ # File upload directory
│ ├── audio/ # MP3 files
│ └── images/ # Cover images
├── sql/
│ └── schema.sql # Database schema reference
└── src/
├── main.rs # Application entry point
├── lib.rs # Module exports
├── config.rs # Configuration management
├── db.rs # Database connection
├── models/ # Data models
│ ├── mod.rs
│ ├── user.rs
│ ├── role.rs
│ ├── lesson.rs
│ ├── audio.rs
│ ├── video.rs
│ ├── handbook.rs
│ └── dto.rs # Request/Response DTOs
├── handlers/ # HTTP handlers
│ ├── mod.rs
│ ├── auth.rs # Login/logout
│ ├── users.rs # User CRUD
│ ├── audio.rs # Audio CRUD
│ ├── video.rs # Video CRUD
│ ├── handbook.rs # Handbook CRUD
│ ├── health.rs # Health check
│ └── public.rs # Public endpoints
├── services/ # Business logic
│ ├── mod.rs
│ ├── auth_service.rs
│ ├── user_service.rs
│ ├── audio_service.rs
│ ├── video_service.rs
│ └── handbook_service.rs
├── repositories/ # Database operations
│ ├── mod.rs
│ ├── user_repository.rs
│ ├── audio_repository.rs
│ ├── video_repository.rs
│ └── handbook_repository.rs
└── middleware/ # Middleware
├── mod.rs
└── auth.rs # JWT authentication
The application uses the following tables:
user- Student/user accountsuser_role- User roles (Admin, A-1, A-2, B-1, B-2, DENEME)user_lesson- Lesson levels (A-1, A-2, B-1, B-2, Mini sınıf)user_sub_lesson- Sub-lessons within lessonslistening- Audio materials for listening exercisesvideo- Video materials (YouTube links)user_sub_handbook- Handbook/PDF materials
cargo build --releaseThe binary will be located at:
target/release/obs_api
./target/release/obs_apiCreate a Dockerfile:
FROM rust:1.70 as builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates
COPY --from=builder /app/target/release/obs_api /usr/local/bin/
COPY --from=builder /app/uploads /app/uploads
WORKDIR /app
EXPOSE 8080
CMD ["obs_api"]Build and run:
docker build -t merhaba-obs-api .
docker run -p 8080:8080 --env-file .env merhaba-obs-api- Change JWT Secret: Update
JWT_SECRETin production - Use HTTPS: Always use HTTPS in production
- Database Credentials: Use environment variables, never commit credentials
- Rate Limiting: Consider adding rate limiting for production
- Input Validation: All inputs are validated using the
validatorcrate
If you see connection errors:
- Verify
MONGO_URI/MONGO_DBand DB user password - Check network connectivity and Atlas IP allowlist / VPC
- TLS: pastikan cluster memakai connection string yang didukung driver
If OpenSSL is missing:
- macOS:
brew install openssl - Ubuntu:
sudo apt-get install libssl-dev pkg-config
Change the port in .env:
PORT=8081Proprietary - Merhaba Turkish Language Learning Platform
For issues and questions, contact the Merhaba development team.