# Architecture

Collecticity Dons — plateforme de dons. Cette doc (Collecticidoc) est maintenue par Urbanis Finance.

Clone : [email protected]:collecticity/don.git
Branche de travail : don-stage.

# Mono-repo

Dossier Rôle Port local Node
backend/ API Express + GraphQL + crons 3001 16 (^16.13.1)
frontend/ Site public (Nuxt SSR) 3000 16
admin/ Dashboard admin (Nuxt) 3002 16
common/ Thème, logos (PLATFORM_NAME)
docs/ Ce site VuePress 8080 en npm run dev 14.15 au build CC

Les 3 apps se parlent via APP_URL / API_URL / ADMIN_URL.

Install local : Getting started.

# Staging

Hébergement Clever Cloud. URLs :

App URL Alias CC
Frontend https://app-don-stage.collecticity.fr don-frontend-staging
Backend / API https://api-don-stage.collecticity.fr don-backend-staging
Admin https://admin-don-stage.collecticity.fr don-admin-staging

Variables d’environnement typiques (staging) :

  • PLATFORM_NAME=Collecticity
  • PAYMENT_SERVICE_PROVIDER=MANGOPAY
  • ENV / NODE_ENV selon l’app CC
  • APP_URL, API_URL = les URLs HTTPS ci-dessus

Déployer une app (depuis la machine, scripts locaux deploy-don.sh) :

cd frontend && sh deploy-don.sh staging   # clever deploy -a don-frontend-staging -f
cd backend  && sh deploy-don.sh staging
cd admin    && sh deploy-don.sh staging

Jenkins (Jenkinsfile) tourne sur les commits ; le déploiement docs n’est pas activé (DEPLOY_DOC=no). La doc se déploie à part (docs/deploy-doc.sh, app don-docs).

# Backend

  • Stack : Node 16, Express, Apollo GraphQL, MongoDB, sessions (express-session + MongoStore).
  • Entrée : backend/bin/start.js — migrations puis serveur, puis crons.
  • Install : voir Getting started. Commandes : cd backend && npm install && npm run dev (après .env).
  • API : un seul endpoint GraphQL POST /graphql (et playground en NODE_ENV=development : http://localhost:3001/graphql).
  • Schéma : backend/graphql/typeDefs/types/Query.graphql et Mutation.graphql.
  • Proxy front : le Nuxt frontend proxy /graphql vers API_URL (frontend/nuxt.config.js).

Le navigateur tape donc https://app-don-stage.collecticity.fr/graphql ; le SSR doit utiliser API_URL (backend).

Webhooks Mangopay : fichiers dans backend/routes/hooks/ (payIn, payOut, transfer, KYC, UBO, …). JSDoc type GET /webhooks/mangopay/payin.

Crons : backend/crons/ — liste dans API reference.

# Frontend (site public)

  • Stack : Nuxt 2 (SSR), Vue 2, Vuex, Apollo, Element UI, nuxt-i18n, Stylus.
  • Install : cd frontend && npm install && npm run dev (port 3000).
  • Config : frontend/.envAPP_URL, API_URL, PLATFORM_NAME, PAYMENT_SERVICE_PROVIDER, S3_URL (Cellar), recaptcha / GMaps / Intercom, etc. (modèle : frontend/.env.example).
  • Thème : common/Collecticity/theme (selon PLATFORM_NAME) + CSS Element généré (npm run element:themes si le thème change).

Parcours donateur : pages contribution / paiement (CB, virement, chèque). Le workflow de création jusqu’à clôture d’une campagne est dans le guide projets.

# Admin

  • Stack : Nuxt 2, Apollo, Element UI.
  • Install : cd admin && npm install && npm run dev (port 3002).
  • Config : admin/.envAPI_URL, APP_URL, PLATFORM_NAME, ADMIN_EMAIL / ADMIN_PASSWORD, PSP.
  • Login admin : mot de passe ADMIN_PASSWORD du .env backend (création user admin via migration / seed).

# Variables d’environnement (commun)

À coller dans chaque .env concerné :

Variable Rôle
PLATFORM_NAME Collecticity
PAYMENT_SERVICE_PROVIDER MANGOPAY
APP_URL Frontend (http://localhost:3000 en local)
API_URL Backend (http://localhost:3001)
ADMIN_URL Admin (backend surtout)
MONGODB_URL / MONGODB_DATABASE Mongo (backend)
SESSION_SECRET Sessions backend
MANGOPAY_* API sandbox / prod Mangopay
MAILGUN_* / EMAIL_FROM E-mails
CELLAR_ADDON_HOST / CELLAR_ADDON_KEY_ID / CELLAR_ADDON_KEY_SECRET Cellar (stockage fichiers, backend)
S3_BUCKET Nom du bucket Cellar (parfois encore un bucket Amazon)
S3_URL URL publique des fichiers (frontend, proxy /s3)

Ne pas committer les .env (secrets). Copier depuis les .env.example.

# Terminologie

Terme Sens
Donateur / Contributor Personne ou organisation qui donne
Porteur de projet / Project owner Organisation qui porte une campagne
Contribution / Don Don (carte, virement ou chèque)
Campagne / Collecte Projet de collecte publique

# Technologies & services

  • Runtime apps : Node.js 16, npm 8
  • Front / admin : Nuxt, Vue, Vuex, Apollo, Element UI
  • Backend : Express, GraphQL, MongoDB, AJV, ESLint
  • Paiement : Mangopay (opens new window)
  • E-mail : Mailgun (opens new window)
  • Fichiers : Cellar (opens new window) (Clever Cloud, API compatible S3) — c’est le stockage habituel. Amazon S3 reste possible ponctuellement (anciennes URLs / migration). Le client est dans backend/utils/s3.js (CELLAR_ADDON_* + S3_BUCKET, URLs *.cellar-c2.services.clever-cloud.com).
  • Hébergement : Clever Cloud (opens new window)
  • CI : Jenkins (Jenkinsfile)
  • Autres souvent configurés : reCAPTCHA, Google Maps, Intercom, Mailchimp

# Fichiers statiques plateforme

Logos etc. : common/$PLATFORM_NAME/static → servis en $HOST/logo.svg (ex. common/collecticity/static/logo.svg). Cache long (1 an) ; changer le hash du nom de fichier pour invalider (logo.[hash].svg). Config : middleware dans frontend/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')