Introduction Why Docs About

Architecture

Here is technical overview of the Delibay platform as a whole. If you want to contribute to non-trivial features, you really need to read and understand these concepts. They are mostly a resume of deeper concepts described in dedicated documents.

Main structure

The platform is separated in 2 parts:

  • The backend: a server as a central source of truth, to host course content, manage users and organizations, provide syncing features.
  • The frontend: the client with the user interface and some training/parsing/validation logic. This is hosted on another subdomain.

The role of the API is almost to store data that need to be shared and saved. Its role is especially to check authentication, permissions and data validation, syncing content in both directions.

Most of the training experience logic is implemented on the frontend instead of the backend. The parsing of transcripts are done in the frontend too. Why ? For several reasons:

  1. To enable full offline usage
  2. To remove the network latency time and provide instant feedback
  3. In terms of software freedom, the frontend code can be changed and adapted to other specific needs. This frontend can be built and used against the existing API on courses provided by the school. Changing the backend code is technically possible too, but as the school content is hosted on an existing server managed by the school, individual students or teachers can't really change it.

Network schema

If you don't know how to the SPA+API model works, let's look at some schemas !

TODO: network schema of client and servers, prod + dev.

Authentication

We use Laravel Fortify to manage a lot of the boring features in the Laravel API. Currently, the following features are enabled:

  1. Login
  2. Logout
  3. Register
  4. Email validation

2FA and passwords reset are not enabled for the moment.

The contributed routes can be found in the php artisan route:list:

POST      api/login ......................................................... Laravel\Fortify › AuthenticatedSessionController@store
POST      api/logout ............................................. logout › Laravel\Fortify › AuthenticatedSessionController@destroy
POST      api/register ............................................................ Laravel\Fortify › RegisteredUserController@store
GET|HEAD  api/email/verify/{id}/{hash} ...................... verification.verify › Laravel\Fortify › VerifyEmailController@__invoke
POST      api/email/verification-notification .. verification.send › Laravel\Fortify › EmailVerificationNotificationController@store
GET|HEAD  api/user/confirmed-password-status ...... password.confirmation › Laravel\Fortify › ConfirmedPasswordStatusController@show
POST      api/user/confirm-password ....................... password.confirm › Laravel\Fortify › ConfirmablePasswordController@store

In addition, we use Laravel Sanctum that provide a cookie based (so technically stateful) and a token based authentication mechanism. As cookie as safer to store in browsers (as they are httpOnly, XSS code couldn't read it as they are not accessible to JavaScript, this is only the browser that sends them on each request). Cookie auth means that the SPA must be hosted under the same domain umbrella as the API (this SPA URL even need to be hard coded in .env as SPA_URL), so it could be a problem in the future with other SPA versions, a possible desktop app or anything else that doesn't support cookies or cannot be on this domain. So we might enable token based auth in the future, but this would require some work to enable tokens generations, token revocations, trying to store them securely...

GET|HEAD  sanctum/csrf-cookie ............ sanctum.csrf-cookie › Laravel\Sanctum › CsrfCookieController@show

Local first strategy

To support a big majority of features to be done locally without any internet connection (once we logged in), we use different tools and strategies to be able to maintain a coherent state locally (in the browser), that persist page reloads and page changes.

First, no component should directly make network request (except the login, register, sync and import ones). (This is not the case currently with course creation for example.) When we have a form to create a course, create an exo, edit a skill, answer an exo, ... we create the item locally with a UUID (to identify it before we can get a server database attributed ID) in IndexedDB. The syncing process will later pick up those items (they are the only ones that have a UUID field) and send them to the server. The detailed syncing processed in defined in sync.md.

Relationships in local only elements

TODO: think about that

Local coherence strategy

TODO: think about that