Architecture Overview
Training data shares a codebase with our parent app, DB Manager. Please look there for full documentation on back-end architecture. Within this environment, Training data uses:
/src
├── controllers
├── models
├── routes
├── services
├── middleware
├── utils
├── config
├── tests
└── app.js
Backend
Routes
API endpoints and their associated controller methods.
// routes/userRoutes.js
const express = require("express");
const userController = require("../controllers/userController");
const router = express.Router();
router.get("/users", userController.getUser);
module.exports = router;
Services
Complex business logic that isn’t directly tied to a specific endpoint.
// services/authService.js
const generateToken = (user) => {
// Logic to generate a JWT token
};
module.exports = {
generateToken,
};
Middleware
Authentication, validation and error handling.
Utils
Utility functions that can be reused across the application (p.e. formatDate).
Config
Environment variables, database configurations…
Tests
Unit and integration tests.
API
API
Description | Endpoint | Method | Params | Body | Return |
---|---|---|---|---|---|
Add list of different non moodle courses | /add | POST | - | - | array of course objects: [{ "id": int, "shortname": varchar, "start_date": datetime, "language": varchar, "format": varchar, "main_topic": varchar, "level": int, "edition": int, "duration": int }, ...] |
GET list of all non moodle courses | /getAllNMCourses | GET | - | - | array of course objects: [{ "id": int, "shortname": varchar, "start_date": datetime, "language": varchar, "format": varchar, "main_topic": varchar, "level": int, "edition": int, "duration": int }, ...] |
GET column shortname from non_moodle_courses | /getNMCourses | GET | - | - | array of strings: ["Course1", ...] |
Add list of different non moodle enrolments | /addEnrolment | POST | - | - | array of enrolment objects: [{ "id": int, "course_shortname": varchar, "user_fullname": varchar, "email": varchar, "country": varchar, "completion_date": datetime, "progress": int, "status": int }, ...] |
Frontend
Views
Components that hold an entire page view (containing multiple sub-components). Our only 3 views are:
├── TrainingData
├── TrainingNMCourses
├── TrainingNMEnrolments
TrainingData
is the landing page, including 2 main buttons that will redirect to either courses or enrolments.TrainingNMCourses
contains a table with all actual courses, and a button that will get a form to add more non moodle courses.TrainingNMEnrolments
include button that will get a form to add more non moodle enrolments, and also a bulk user option were you can download an empty CSV and then upload all the enrolments.
User flow
The user:
- Landing on the Training Data Main Page Interface: Displays two buttons:
[Courses]
[Enrolments]
- Navigating to Courses Action: Clicks on the [Courses] button.
Result: Redirected to the Courses page.
- Adding a Non-Moodle Course Action: Clicks [Add non-Moodle course].
Form: User fills in the required course information.
Action: Submits the form.
Result: The newly added course appears in a table with other courses listed below.
-
Returning to Main Page Action: Clicks a navigation element (e.g., Back to Training Data) to return to the main page.
-
Navigating to Enrolments Action: Clicks on the [Enrolments] button.
Result: Redirected to the Enrolments page.
- Adding a Non-Moodle Enrolment Action: Clicks [Add enrolment].
Form: User fills in the enrolment information.
Action: Submits the form.
Result: Enrolment is added to the enrolment list.
- Bulk Upload via CSV Option: User sees a section for Bulk Upload.
Step i: Clicks [Download Empty CSV] — gets a file with required columns.
Step ii: Fills out the CSV with enrolment data.
Step iii: Clicks [Upload CSV] — submits the populated file.
Style guide
Follow EUFMD's Engineering Guidelines. In addition to those, we do the following:
Vue API
- Use Vue Options API
- There is also the new Composition API, but the original dev team was more familiar with Options format.
- If looking up documentation, make sure the “Options” format is selected:
Naming conventions
- custom events (
$emits
) inkebab-case
- data/variable names in
camelCase
- component names should be:
- in
PascalCase
- always multi-word: i.e.
- ❌
Connections.vue
- ✅
ConnectionsTable.vue
- ❌
- when components are used by only one parent: prepend with their parent name, i.e. if a Form has components Question and Answers:
- ❌
,Question.vue
Answers.vue
- ✅
FormQuestion.vue
,FormAnswers.vue
- This ensures that related components are visually grouped together in the file structure.
- ❌
- when components are reused throughout the app: prepend with
RMT
. For example, if we reuse the sameButton
:- ❌
Button.vue
- ✅
RMTButton.vue
- This ensures that reusable components are visually grouped together in the file structure
- ❌
- in
Pinia for state management
Read and follow tutorial here, and examples in client > src > stores
.