# Learner Management System (LMS) Backend This is the backend service for the Learner Management System, built with Rust using the Actix Web framework. It provides a RESTful API for the frontend application, handles business logic, interacts with a MariaDB database using SQLx, and implements secure PAKE SRP authentication. The application is designed to be run using Docker and Docker Compose. ## Features * **RESTful API:** Provides endpoints for authentication, user profiles, admin functions, and potentially course/classroom management in the future. * **Secure Authentication:** Implements Password-Authenticated Key Exchange (PAKE) using the Secure Remote Password (SRP-6a) protocol via the `srp` crate. * **High Performance:** Built with Rust and Actix Web for excellent performance, memory safety, and concurrency. * **Database Interaction:** Uses SQLx for asynchronous, compile-time checked SQL queries against MariaDB. * **Database Schema Management:** Automatically creates database tables on initial startup if they don't exist. * **Sample Data Population:** Populates essential data (e.g., courses, sample users without passwords) on first run. * **Dockerized:** Fully containerized using Docker and Docker Compose for easy setup, consistent environments, and deployment. * **Configuration:** Configurable via environment variables (`.env` file support). * **Modular Structure:** Code organized into logical modules (handlers, db, models, errors, config). * **Basic Logging:** Uses `env_logger` for request and application logging. ## Technologies Used * **Rust** (Stable toolchain) * **Actix Web** (v4): High-performance web framework. * **SQLx:** Asynchronous SQL toolkit with compile-time query checking. * **`srp` crate:** For SRP-6a protocol implementation. * **MariaDB:** Relational database (run via Docker). * **Docker & Docker Compose:** For containerization and orchestration. * **`serde`:** For data serialization/deserialization (JSON). * **`dotenv`:** For loading environment variables from `.env` files. * **`env_logger`:** For flexible logging configuration. * **`chrono`:** For date/time handling. * **`hex`:** For encoding/decoding SRP values. * **`uuid`:** For generating session tokens (current implementation). ## Prerequisites * **Docker** * **Docker Compose** (v1 or v2 syntax compatible with the `docker-compose.yml`) * **Rust Toolchain** (Stable - only needed if building/running outside the provided Docker setup) ## Getting Started 1. **Clone the Repository:** Clone the repository containing *both* the `lms-backend` folder and the main `docker-compose.yml`. ```bash git clone cd # Should contain lms-backend/ and docker-compose.yml ``` 2. **Create Environment File:** In the **root directory** (the one containing `docker-compose.yml`), create a `.env` file to specify database credentials. You can copy the example below or rely on the defaults defined in `docker-compose.yml`. ```dotenv # .env (in the root directory) # MariaDB Credentials (used by docker-compose to init the DB) MARIADB_ROOT_PASSWORD=supersecretroot MARIADB_DATABASE=lms_db MARIADB_USER=lms_user MARIADB_PASSWORD=lms_password # Backend Configuration (can override defaults) # SERVER_ADDR=0.0.0.0:8080 # Already set in compose file RUST_LOG=info,lms_backend=debug # Example: Set backend log level to debug # SECRET_KEY=your_secret_for_jwt_if_used # Needed if switching to JWT sessions ``` 3. **Build and Run using Docker Compose:** From the **root directory**, run: ```bash docker-compose up --build -d ``` * `--build`: Forces rebuilding the backend image if code has changed. * `-d`: Runs the containers in detached mode (in the background). * The first run might take some time to download images and build the Rust application. 4. **Accessing the API:** * The API should now be running and accessible at `http://localhost:8080`. * Test the health check endpoint: `http://localhost:8080/api/health`. You should receive a JSON response indicating success. 5. **Stopping the Services:** ```bash docker-compose down ``` ## Project Structure (`lms-backend/src/`) ``` src/ ├── main.rs # Entry point, server setup, middleware, routing ├── config.rs # Configuration loading (.env) ├── db.rs # Database logic (SQLx queries, migrations/setup, data population) ├── handlers.rs # Actix route handlers, business logic, API endpoint definitions ├── models.rs # Data structures (DB models, API request/response structs) └── errors.rs # Custom error types and `ResponseError` implementation ``` ## Configuration Configuration is primarily handled via environment variables, loaded using the `dotenv` crate during startup within the container. Key variables: * `DATABASE_URL`: The connection string for MariaDB (automatically constructed in `docker-compose.yml`). * `SERVER_ADDR`: The address and port the Actix server binds to (e.g., `0.0.0.0:8080`). * `RUST_LOG`: Controls logging verbosity (e.g., `info`, `debug`, `actix_web=warn,lms_backend=debug`). * `SECRET_KEY`: **Required** if implementing JWT-based sessions in the future. These variables are typically passed from the host's `.env` file (if present) or directly set in the `environment` section of the `backend` service in `docker-compose.yml`. ## API Endpoints The following main API endpoints are implemented in `src/handlers.rs`: * `GET /api/health`: Health check. * `POST /api/auth/srp/start`: Initiates SRP login (provides salt, server ephemeral). * `POST /api/auth/srp/verify`: Verifies client SRP proof, generates session token on success. * `POST /api/auth/logout`: (Basic) Invalidates session token. * `GET /api/profile/{user_id}`: Retrieves user profile information. * `PUT /api/profile/settings`: Updates user settings (e.g., profile picture). * `GET /api/admin/dashboard`: Gets admin dashboard counts. * `GET /api/admin/students`: Lists students (basic). * `GET /api/admin/students/{student_id}/financials`: Gets (mocked) financial data for a student. Refer to `src/handlers.rs` and `src/models.rs` for detailed request/response structures. ## Database * **Type:** MariaDB (run via `mariadb:10.11` Docker image). * **Interaction:** Asynchronous queries via `sqlx`. * **Schema:** Defined and created in `src/db.rs::init_db`. Tables include `students`, `teachers`, `courses`, `enrollments`. SRP salt and verifier fields replace traditional password hashes. * **Persistence:** Database data is persisted using a Docker named volume (`mariadb_data`) defined in `docker-compose.yml`. * **Initial Data:** `src/db.rs::populate_initial_data` adds sample courses and users (students/teachers) **without any password/SRP data set**. Users cannot log in until a password-setting mechanism is implemented. ## Authentication (SRP) * Uses the PAKE SRP-6a protocol. * **Flow:** 1. Client sends `userId` to `/api/auth/srp/start`. 2. Server looks up user (student or teacher), finds SRP `salt` and `verifier` (if set), generates server ephemeral `B`, and stores temporary challenge state (**in memory**). Responds with `salt`, `B`, and `userType`. 3. Client calculates its ephemeral `A` and proof `M1`, sends `userId`, `userType`, `A`, `M1` to `/api/auth/srp/verify`. 4. Server retrieves challenge state, verifies `M1`. If valid, calculates server proof `M2`, generates a session token (UUID), stores session (**in memory**), and responds with `M2` and login data (including token). 5. Client verifies `M2`. ## Important Notes & TODOs * 🚨 **Production State Management:** The current use of `AppState` (in-memory `Mutex`) for storing active SRP challenges and user sessions is **NOT suitable for production**. It will lose state on restart and doesn't scale. **Replace this** with a persistent solution like Redis or a dedicated database table for sessions and potentially challenges (with TTL). * 🔐 **Authentication Middleware:** Protected routes (`/profile/*`, `/admin/*`, etc.) currently **lack proper token validation middleware**. Implement Actix middleware to verify the `Authorization: Bearer ` header against the active session store before allowing access. * 🔑 **Password Setting/Registration:** There is currently **no mechanism** for users to set their initial password or change it. An endpoint needs to be created that takes a username/password, generates the SRP salt and verifier using `srp::server::generate_verifier`, and stores them in the database for the corresponding user. * 🧪 **Testing:** Implement comprehensive unit and integration tests for handlers, database logic, and authentication flow. * 📈 **Scalability:** Consider connection pool tuning (`max_connections` in `main.rs`) and potential optimizations for high-load scenarios. * 📚 **API Documentation:** Consider generating API documentation (e.g., using OpenAPI specs). ## Contributing ## License