Skip to content

Technical Architecture

Aivant Goyal edited this page May 7, 2020 · 7 revisions

Overview

At a high level, the project consists of a web-client (peoplepower-web) that talks to a node server (peoplepower-node).

Interaction

The node server (peoplepower-node) can be thought of as having two separate parts. One part is airlock, this is the middle-man for all requests to airtable. The other part is the project's backend endpoints. These accomplish one-off tasks like bill generation, sending an invite, or approving a bill. These one-off tasks do not interface with airlock but rather edit airtable directly

The web client (peoplepower-web) interacts with Airlock for all interactions with Airtable. It uses request.js functions to do that. It also interacts with the backend endpoints directly, sometimes, via fetch (to trigger actions like inviting and bill generation).

The sections below will talk more about the technical architecture of both the web client and server.

peoplepower-web

This web app was bootstrapped using create-react-app and a lot of the start, build, and test scripts are taken from the provided libraries.

All interactions with airtable happen through function calls in the airtable.js file, which are airtable API function calls that make calls to Airlock under the hood (Airlock uses the same API as Airtable, and to see what I mean, notice that the Airtable constructor is called with the string 'airlock' as the key in airtable.js.

A layer on top of that is the request.js function calls, which are function calls to specific tables. These can be taught of as convenience wrapper functions around the airtable.js functions. Lastly, we have utility functions specific to different components and use cases composed of request.js functions in src/lib/utils.

In this way, peoplepower-web follows a 'narrow waist' architecture, where each layer of abstraction uses a smaller set of common functions beneath it, for code reuse and modularity.

request.js and airtable.js are generated methods using the airtable schema generator, which is a package written by @aivantg that generated these methods automatically based on the schema of the table. The schema generator also provides a few other files (e.g. schema.js) with the schema of the airtable tables.

What this means is that you should not edit the request.js and airtable.js files directly, because these changes would be overwritten when the schema generator is run. In fact, you should not be/need to modify these file at all, as these are auto-generated based on your table and should contain everything you need.

Current Impementation

In an ideal world, no function outside of request.js should call airtable.js functions, and no functions outside of util functions should call request.js functions. For the most part this is true, but we do violate these conventions here and there. I wanted to explicitly note this down in the documentation, but by and large this is the architectural design we followed.

The rest of the web-app

The screens that are shown sits on top of this architecture, and the frontend logic basically displays the data returned by the utility functions. In other words, most of the business logic lives in utility functions, and components only deal with frontend logic + display.

Again, in an ideal world, this abstraction barrier would be 100% adhered to, but we do violate this rule sometimes. By and large (again), this is the architectural design we have tried to follow.

peoplepower-node

The backend server, as described above, is split into two parts. Airlock, which serves as the middleman for all requests between the frontend and Airtable, and the API Endpoints, which run one-off tasks directly interfacing with Airtable.

The backend server needs to be run using babel-node as it uses language features that are currently not in Node (such as the import syntax). Babel is a transpiler that converts the latest javascript syntax to a compatible version.

You can run the server using yarn start but if you want to run an individual file, you will need to use babel-node instead of node

API Endpoints

The API Endpoints handle any business logic that is not suited for the frontend, specifically sending an invite email, bill generation, getting latest solar production data, and verifying the uniqueness of an email. Some of these tasks are in the backend because they need to be run on a regular schedule (getting solar production data), some for security reasons (verifying email uniqueness), some to access email functionality (invite flow), and some to do actions that should not be cancelable by closing your browser window (bill generation).

All API endpoints are located in index.js. From there, they largely call other functions located in the utils/ folder. Those functions interact with airtable using a similar narrow waist architecture generated by the Airtable Schema Generator utility. There are a number of request.js functions that are called, with no direct interaction with airtable.js

For more information about the bill generation part of the node server, see Bill Generation

Airlock

Airlock lives in a separate package, our server simply integrates that package. The only Airlock-related code you will find on our backend is the main integration in index.js and the resolvers, which live in resolvers/index.js. You can read more on the dedicated page.