Skip to content

Running a project

At dcentralize, we’re running several SaaS platforms. Each SaaS platform consists of several projects. Usually a minimum setup contains:

  • A frontend project
  • A backend project
  • A support project

These projects are usually hosted on GitLab, where the frontend and backend are sharing a mono-repository and the support project leverages the GitLab service desk where incoming emails from support@ are converted into issues.

Best practices

  • All relevant information to understand and get started adding value to a project should be reachable from the projects’ README in the root. Some ideas for including here:
    • How to setup and run the project locally
    • Write user stories breaking down the implemented functionality (“As a user, I want to register, so that I can keep track of my subscriptions”. “As an admin, I [want to], [so that]”).
  • A reasonable amount of tests should be present in the project. The desired amount of code coverage depends on the level of maturity and mission-critical factor of the project. E.g. invoicing and payment related code better be tested fully. An experimental feature without solid business case, perhaps not.
  • When choosing a programming language or a new library for a project, look at what our other projects are already using. Unless there’s a very good argument to use something else, go with what is already used. That helps future maintainability.
  • GitLab CI is there to maximize consistency within en between projects:
    • Have a shared understanding of how to build, test and deploy project. All information should be transparent to the whole team.
    • Linting is applied to ensure a consistent coding style. Even spell checking can be a part of it.
    • Unit / end-to-end testing of the software verifies if our promises to our clients are still holding up. We can’t have unintended API changes.
    • Pushing new version out to production should be as simple as creating a new tag. The GitLab CI pipeline should take care of the rest.
  • The team handles support questions, we intentionally want software developers taking care of client support because by exposing them to direct client problems, they’re aware of how their users experience the product, and they can fix root causes directly.

Choosing a programming language

The following languages are the dominant ones within the company:

  • Python
  • JavaScript/TypeScript
  • sh (scripting)
  • bash (if you need more scripting)

Introducing any new language than the above ones should not be taken lightly, as the reasons not to do it probably outweigh the reasons to do it.

Why not to do it:

  • Not many other people can help or take over maintenance, we don’t want to introduce you as a single point of failure.
  • To maintain a low barrier to entry a project, we choose whether it’s Python or Node.js as backend language, not both nor extra languages.
  • Compared to the current language mentioned above, this new languages doesn’t bring anything (or enough) that these languages don’t provide:
    • Mature languages.
    • Active development on them.
    • Big community.
    • Easy to learn.
    • Optimize for human time, not CPU time.

That being said, we’re not going to stick with those languages forever, there just need to be really compelling reasons for it.

Sentry configuration

Sentry is a library to embed in your backend and frontend. It signals unhandled crashes to the Sentry platform. It can show relevant information about the crashes. It’s most useful if it’s setup to notify developers when such event occurs in production.

Create a project on Sentry

d-centralize self-hosted Sentry is set up and can be found here. In order to gain access to the self-hosted Sentry just navigate to the link provided above and follow the steps. The authentication works by logging into your GitLab account.

If the project that you work on doesn’t appear in the list of Projects there is a set of steps that should be followed to add it:

  1. Navigate to the projects list and Create project
  2. Choose your platform. While some of them such as NextJS is not showcased by default you can use the search bar and find the platform used in your project
  3. Select your alert frequency. Pick the first option Alert me on every new issue
  4. Provide a project name and assign it to the team. If the team does not exist, create one and invite your team members to it.

Then:

Consider that Sentry might have already been set up in your project. If so, then only the DSN value should be copied. Take into account that you can also find that value later on by navigating to Projects > [project] > Settings > Client Keys (DSN). This value is usually used in the GitLab CI/CD. Navigate to the GitLab CI/CD variables in the current project and replace the its old value with the new one in all environments where it is used.

It is suggested that you also create a variable with the specific environment name, e.g: ‘production’, ‘staging’, ‘review’, etc. This will report errors per environment.

The new connection can be tested out by adding an explicit error in the code. For example, throw an error intentionally and the error should be visible in the Sentry issues.

Inspiration on how to create the configuration for a NextJS project can be found in pro6pp-web.

Integrations

Mattermost

In Mattermost, create a Sentry channel in the team if it doesn’t already exist. Configure an incoming webhook that’s locked to the channel.

In Sentry integrations:

  1. Choose “Slack (Legacy)” -> Project configurations -> Add to project
  2. Choose a Sentry project
  3. Insert the Mattermost webhook URL at “Webhook URL”. (if you’re using Discord, add /slack to the webhook to obtain a Slack compatible one)
  4. Save, enable plugin
  5. Test plugin, should work.

Now select a Sentry project:

  1. set Alert rules.
  2. At “Then, perform these actions”, add action: “send a notification via an integration”.
  3. Select: “(Legacy) Slack”
  4. Sent Test Notification
  5. Should work

Note that regular webhooks or non-legacy Slack won’t work.

Gitlab

Allow easy Gitlab issue creations from Sentry is pretty handy. For this, a one time integration needs to be arranged.

In Sentry integrations:

  1. Choose Gitlab
  2. Choose Configurations
  3. Add installation
  4. Follow instructions on creating a Sentry App in Gitlab (as admin on https://gitlab.d-centralize.nl/admin/applications)
  5. Setup installation at instance level: https://gitlab.d-centralize.nl
  6. You’ll be asked to link repositories of individual projects. For example add itslanguage/kat
  7. You can also add code path mappings:
    • Project: kat-backend
    • Repo: itslanguage/kat
    • Stack trace root: <empty>
    • Source code root: /backend

Localisation

Running a project in more than one language takes extra work on several levels.

Backend

  • Backend needs to store user language preferences
  • If backend sends email, you need localised email templates. Connect to weblate.
  • Consider these API conventions regarding translations.

Frontend

Email

To allow the project to send email, use our company email server for that.

  • Create an inbox if needed (like noreply@project.com or support@project.com)

App passwords

Next, login with the account associated to the selected inbox and create an app password to allow the app access to the SMTP and IMAP server. Save the login credentials in Vaultwarden and share it with the appropriate team (<project> Infra).

For local development and CI e2e testing and staging environments, using mailpit is advised.

Payments

Administrative backoffice

If the project creates invoices, these have to be passed to the administrative backoffice, for the company (tax) administration. This is accomplished by calling the Yuki API (python package) and delivering the invoice data and PDF rendering for each paid invoice.

Obtain an API key through the Yuki portal with the following settings and save it in Bitwarden:

  • Type: Administratie.
  • Administratie: select the company.
  • Rechten: Geselecteerde webservices.
    • Financial
    • Verkoop
  • Opmerkingen: <project> connection to Yuki for delivering invoices.