# Project structure
# Introduction
This project is a mono-repository with the following directories:
admin
: The admin dashboard of the platformbackend
: The server of the platformfrontend
: The client of the platformcommon
: The common filesdocs
: The documentation of the platform
# Technologies
To build this platform, we are using:
- Nuxt.js (opens new window) - Framework used to create a Vue.js application using SSR.
- Vue.js (opens new window) - Progressive framework for building user interfaces.
- Vuex (opens new window) - State management for Vue.js.
- nuxt-i18n (opens new window) - A vue-i18n (opens new window) integration, automatic routes generation prefixed with locale code, routes translation, SEO, lazy-load, auto-detect language and other features.
- Stylus (opens new window) - Style language.
- Pug (opens new window) - Template language.
- Express (opens new window) - Fast, unopinionated, minimalist web framework for Node.js.
- GraphQL (opens new window) - A query language.
- Apollo GraphQL (opens new window) - A GraphQL implementation.
- AJV (opens new window) - A JSON schema validator.
- ESLint (opens new window) - Lint for JavaScript.
- dotenv-safe (opens new window) - Ensures that all necessary environment variables are defined.
- Element UI (opens new window) - A Desktop UI Library.
- Nightwatch.js (opens new window) - e2e testing.
- Puppeteer (opens new window) - Headless Chrome Node.js API for useful tasks (e.g.: PDF generation)
- Mailgun (opens new window) - An email service.
- Mangopay (opens new window) - Payment service provider.
- Lemonway (opens new window) - Payment service provider.
- Yousign (opens new window) - Electronic signature service.
- Jenkins (opens new window) - Automated deployment with custom pipeline.
- Clever Cloud (opens new window) - Hosting service.
- And others...
# Platform driven by the environment
C4$hM4chin3 is a white-label platform built for PepperState and Collecticity. Anything being platform-specific (theme, some features, etc.) is driven by the environment variable PLATFORM_NAME
Accepted values:
PepperState
Collecticity
WARNING
Some features are reserved to a specific platform. In that case, please note the tag PEPPERSTATE / COLLECTICITY next to the description of the feature in this documentation.
The same way, the environment variable PAYMENT_SERVICE_PROVIDER
defines which service is used.
Accepted values:
MANGOPAY
LEMONWAY
WARNING
It is to note that we started to develop the platform using Lemonway. Halfway of the development, we decided to move on with Mangopay. The platform has not been fully tested with Lemonway so it is highly possible to see some features not working properly if Lemonway is the selected PSP.
Some features are reserved to a specific provider. In that case, please note the tag MANGOPAY / LEMONWAY next to the description of the feature in this documentation.
# Static files
Files specific to a platform like logos can be served as static files. Put the files in the folder common/$PLATFORM_NAME/static
.
A file common/pepperstate/static/logo.svg
will then be served at $HOST/logo.svg
.
TIP
The cache is enabled and max-age is set to 1 year. But whenever a file's content changes, it's possible to counteract the cache using a different random hash: file.[hash].ext
$HOST/logo.d352fg.svg
$HOST/logo.foo.svg
Will both serve the file logo.svg
The config of this server middleware is set the nuxt.config.js
.
# Themes
For each platform, there is a theme located in the folder common/$PLATFORM_NAME/theme
.
This is were colors, fonts, breakpoints, etc. are defined. Import the file common/getTheme.js
to dynamically get an object with all the variables defined:
import getTheme from "common/getTheme";
const theme = getTheme(process.env.PLATFORM_NAME);
console.log(theme);
/*
output:
{
borderRadius: {},
breakpoints: {},
colors: {},
fonts: {},
transitions: {}
}
*/
TIP
This object is injected in the nuxt application: this.$theme
# Element UI theme for the frontend
In order to deeply stick to the platform's identity, a custom theme for Element UI is generated. This theme written in sass extends the default theme from Element UI (theme-chalk (opens new window)).
The entry point of the theme is located in frontend/assets/styles/element-ui/index.scss
.
Element UI has a set of overridable variables. The list of these variables is in this file (opens new window).
Our custom variables are located in frontend/assets/styles/element-ui/custom/variables.scss
. As the original theme, variables are prefixed by --
.
We use a generated css file per platform so whenever the theme changes, we need to regenerate them:
cd frontend
npm run element:themes
This command uses gulp to generate a css file for each platform in the folder element-ui
. The task in the gulpfile
uses a custom json loader to use json files as sass variables, allowing us to fetch the right theme for the right platform. As result of the task, each css file is named after its platform name. The css file corresponding to the current platform is then dynamically imported in the nuxt.config.js
.
TIP
The theme doesn't change very ofter so in order to save some time at the build time, we chose to generate the theme separately using Gulp.
# Objects
In addition to the original theme, css objects have been created. Objects are reusable and abstract set of styles defined using sass placeholders (opens new window).
All objects are prefixed by -o-
in order to be clearly identifiable.
Objects are located at frontend/assets/styles/element-ui/custom/objects/
.
WARNING
Sass placeholders are not rendered in css. We use placeholders because we don't want to render the object styles every time we import a placeholder file. That would be very inconvenient!
If you want to use an object outside of scss, in the html for example, you can create the class selector that extends the placeholder in the file ~/assets/styles/element-ui/custom/objects/index.scss
:
@import "./{PATH_TO_OBJECT}";
.-o-my-object {
@extends -o-my-object;
}
# Adding an object
Let's assume we want to add the layout object container
.
Add the placeholder in a file ~/assets/styles/element-ui/custom/objects/layout.scss
%-o-container {
padding-left: 2rem;
padding-right: 2rem;
}
# Using an object
@import "./{PATH_TO_OBJECT}";
.my-selector {
@extend %-o-title-2;
}
# Mixins
# Breakpoints
The res-spec
mixin have been created for media queries:
.my-selector {
// This style will be only applied to xs devices
@include res-spec(xs-only) {
padding-right: 50px;
}
}
TIP
You can see the list of keys here (opens new window)
⚠️ Breakpoints are defined in the theme of the platform.
# Components
Element UI components are written usig the BEM syntax (opens new window). They use mixins b
, e
, m
, respectively Bloc, Element and Modifier to write their style. We chose to follow the same rules.
# Overriding a component style
To override the component el-button
:
- Create a file named
button
in the folder~/assets/styles/element-ui/custom/components/
. - Add this comment a the top of the file:
// Custom style for Button // src: https://github.com/ElementUI/theme-chalk/blob/master/src/button.scss
- Import files you need, for instance variables and mixins
- Add the custom style by following the same structure of the original file:
@include b(button) { // will automatically prepend with the prefix `el-` // custom style }
TIP
Before overriding a component, make sure the customization can't be achieved by just editing variables!
# Using theme's variables in stylus
It's possible to import JSON files as variables in stylus. A variable $platform-theme
that represents the path to the current platform's theme is injected in the stylus loader so to import a JSON file, simply do:
json($platform-theme + '/colors.json')
# Deployment
A pipeline on Jenkins is triggered on every commit. The behavior is described in the file Jenkinsfile
at the root of the project.
# Stages
The pipeline is separated in different stages:
Notify
: Notifies the beginning of the job in Slack and log different information.Build
: Build each app for end-to-end tests.Run
: Run each app for end-to-end tests.Test
: Test each app (eslint, end-to-end in headless mode).Deploy
: Deploy each app.Deploy docs
: Deploy the documentation.
# Driven by the branch name
The behavior of the pipeline is driven by the branch name on which the pipeline is running, following these conditions:
Branch name | Platform name | Deployment |
---|---|---|
develop | PepperState | deploys the documentation |
feature/pep-X_feature-name | PepperState | None |
pep-staging | PepperState | deploys pepperstate-staging |
pep-production | PepperState | deploys pepperstate-production |
feature/col-X_feature-name | Collecticity | None |
col-staging | Collecticity | deploys collecticity-staging |
col-production | Collecticity | deploys collecticity-production |
# End-to-end tests
Both admin and frontend are subject to end-to-end tests. On test failure, a screenshot will be saved as an artifact in the job and the deployment be skipped.
WARNING
The end-to-end tests are using APPROVED
users with a valid wallet for the money-in and investment flows. Please make sure that those users are correctly setup for your app or the tests will fail and the platform won't be deployed.