# Project structure

# Introduction

This project is a mono-repository with the following directories:

  • admin: The admin dashboard of the platform
  • backend: The server of the platform
  • frontend: The client of the platform
  • common: The common files
  • docs: The documentation of the platform

# Technologies

To build this platform, we are using:

# 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.