Skip to main content

Better Naming / Database Design

There were many bad naming/design decisions with the way data is stored in the Serial database. Here is a small wish list of things that would be nice to change eventually. We need to keep this in mind when making decisions about naming things in the API spec.

The name unique_identifier is too vague

The name unique_identifier is used all over the app to refer to instances of components. It is used in the database, and in the frontend but the API interface (user facing) is uses the name component_instance. component_instance is a much better name because it is more descriptive and easier to understand. The main thing that needs to change is the following tables:
  • unique_identifiescomponent_instances
  • unique_identifier_linkscomponent_instance_links

The naming of the data primitives

The data primitives are a bit confusing and could be improved. I recommend that the following changes be made. The data_ prefix ensures that the tables are grouped nicely together in the Supabase UI and it also makes it very clear which tables store the data.
  • parametric_quantitativedata_numerical
  • parametric_qualitativedata_text
  • checkboxesdata_booleans
  • datetime_datadata_datetime
  • imagesdata_files
  • filesdata_files
  • create new enum table for storing pass/fail values instead of storing them in the parametric_qualitative (data_text) table.
Along with changing the table names, the enum values corresponding to the data type of a data primitive should be changed.
  • LINKLINK (no change)
  • PARAMETRIC_QUANTITATIVENUMERICAL
  • PARAMETRIC_QUALITATIVETEXT
  • IMAGEIMAGE (no change)
  • FILEFILE (no change)
  • CHECKBOXBOOLEAN
  • PASSFAILENUM

Redux

Initially, our application relied heavily on Redux for managing global state. Redux provided a centralized store for data that needed to be accessed by multiple components across the app. However, as our application grew, we found that Redux introduced unnecessary complexity for many of our state management needs. We’ve since transitioned to using React Context for most of our global state management. Context provides a more lightweight and flexible solution that’s built into React, making it easier to manage state within specific feature areas without the overhead of Redux. Despite this transition, a few core features of our application still utilize Redux:
  1. Authentication: The auth slice in Redux manages user authentication state, including the Supabase UID, access token, user role, and company ID.
  2. Database State: A lightweight copy of the tenant’s database is still managed in Redux. This includes data such as components, processes, users, and other entities that are frequently accessed across the application.
  3. Real-time Updates: The Redux store is still used in conjunction with Supabase real-time subscriptions to keep the client-side data in sync with the backend.
While these features continue to use Redux, we’re gradually working towards migrating them to more modern state management solutions. This will help reduce our dependency on Redux and simplify our overall state management approach. As we continue to develop new features and refactor existing ones, we’re prioritizing the use of React Context and local state management where appropriate, reserving Redux for only the most complex global state requirements.

Frontend Primitives

A significant portion of Serial’s frontend was initially implemented without standardized UI primitives, leading to inconsistencies and maintenance challenges. However, newer features are now being built using a set of well-defined frontend primitives located in frontend/src/shared/components/primitives. This shift towards using reusable UI components has greatly improved the consistency and efficiency of frontend development. Frontend primitives are crucial for several reasons:
  1. Consistency: They ensure a uniform look and feel across the application.
  2. Efficiency: Developers can rapidly build new features using pre-built components.
  3. Maintainability: Changes to primitives propagate throughout the app, making updates easier.
  4. Accessibility: Primitives can be designed with accessibility in mind, improving overall app usability.
To showcase the power of these primitives, here are a few examples:
  1. Button primitive:
<Button size="md" variant="primary">
  Click me
</Button>
  1. Modal primitive:
<Modal.Root>
  <Modal.Trigger asChild>
    <Button>Open Modal</Button>
  </Modal.Trigger>
  <Modal.Content>
    <Modal.Main>Modal content goes here</Modal.Main>
  </Modal.Content>
</Modal.Root>
  1. Dropdown primitive:
<DropdownMenu.Root>
  <DropdownMenu.Trigger asChild>
    <Button>Open Menu</Button>
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Item>Option 1</DropdownMenu.Item>
    <DropdownMenu.Item>Option 2</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>
These primitives, along with many others, can be viewed and interacted with at the /frontend-primitives route in the app. This dedicated page serves as a living style guide, allowing developers to explore and understand the available UI components. As we continue to develop new features and refactor existing ones, leveraging these frontend primitives will be key to maintaining a cohesive and efficient frontend codebase.

Database Constraints