Skip to content

Frontend Architecture

Peter Wu edited this page Aug 28, 2020 · 4 revisions

Current Setup Diagram

The frontend workflow can be summarized with the following ASCII art:

     <------------ <------------ <---------------
     |                                          |
     |   (Supported by Firebase Auth)           |
     |      |                                   |
     \/     \/                                  |
[LoginBarrier] ------> (user not logged in) ----
    |
    | (when user logged in)
    |
    \/
(Initialize Firebase Listeners to create the following cycle)


Reactive Model

[Firestore Listeners] <------ (automatically notify) <----- [Firestore]
   |                                                           /\
   | (push changes to)                                         |
   |                          (add/update/delete documents in) |
   \/                                                          |
[Redux Store]                                      [Our Various Firestore Actions]
   |                                                           /\
   | (push changes to)                                 (calls) |
   |                                                           |
   -----------> [Our Various React Components] -------> ------->

Brief explanations:

  • The LoginBarrier component ensures that the user must log in to see the application component. Otherwise, only the login prompt screen will be shown.
  • Firestore Listeners is a single subscriber function that sets up the connection between Firestore and redux store. It ensures the eventual consistency of state between these two storage systems by emitting diff object to the Redux store.
  • Firestore Actions is a collection of functions that imperatively tells the Firestore how to efficiently perform some database operations to update the state based on user actions.
  • Our Redux store has a fairly simple reducer thanks to the reactive model. It mostly just transforms the data and apply the diff given by Firestore listners. You can see the types of diff objects here.
  • Firestore does have some small latency, but that is negligible in most situations. Therefore, most of the time, the Redux store/Firestore represents the single source of truth. However, in cases where the user interactivity is high (Task Editor typing) and the latency is intolerable, we introduce some local cache that will be eventually invalidated by incoming Firestore data.

Firestore & Redux Store

You can see the type definition of Firestore here and type definition of redux store here.

We have our Firestore and Redux Store to have almost the same shape. In this way, we can speed up our development process by making as less data conversion as possible. We only have some slight shape different when we absolutely need them.

Components Hierarchy

Inside the src/components folder inside the frontend folder, you will see that the components are organized in these folders:

  • TaskCreator: the task creator component below the header.
  • TaskView: the main task view that contains both the focus view and future view, displaying different views based on application state.
  • TitleBar: header of the application.
  • UI: some UI primitives that are specific to our design. It's a similar concept to Semantic UI.
  • Util: some complex utility components that are used across the entire app.