-
Notifications
You must be signed in to change notification settings - Fork 30
General Architecture
FEM is the frontend to the Zooniverse website. It is a rebuild of Panoptes-Front-End with additional features.
ADR #2 briefly explains how FEM was initialized. At the Zooniverse Team Meeting April 2018, it was decided that Panoptes-Front-End (PFE) would be broken up into modular libraries and apps inside a monorepo. NextJS was chosen as the SSR framework, and an emphasis on modular code instead of monoliths was mentioned in CONTRIBUTING.md.
Beyond the mentioned guidelines, there’s not much “big picture” documentation from the initial discussions about FEM’s broader architecture plan. What follows in this wiki is an overview of the evolution of apps and libraries in FEM, its current architecture, and guiding principles for development of its architecture during the continued migration of Zooniverse routes from PFE to FEM.
The two FEM NextJS apps are described in detail below. app-project is a legacy Pages Router and app-root is a modern App Router. They handle different routes on the Zooniverse website.
Due to the lack of big picture documentation from the initialization of FEM, it’s now up to the current dev team to decide whether to continue with multiple NextJS apps or to consolidate to one.
Scenario 1: Consolidate to app-root
- app-root’s App Router would handle all routes on the Zooniverse website.
- app-root would control all “context providers” such as signed-in user, UI theme, and other user-specific preferences that could eventually be applied to the entire site (like language preference).
- This scenario would require us to first convert app-project's Pages Router to an App Router, and then extract its contents to an FEM library (lib-project), and finally consume lib-project in app-root.
- The advantage to this scenario is that all webpages would eventually use the same context provider strategy and only one app would be deployed by devOps.
Scenario 2: Keep two separate NextJS apps
- The advantage here is less dev time toward refactoring. For instance, the reason we didn’t consolidate to one app during the initialization of app-root is simply because of the amount of work required to modernize app-project’s code to the latest NextJS features and split the UI components into their own FEM library.
- Even if we keep two NextJS apps in FEM, ideally app-project will be converted from a Pages Router to an App Router to modernize its code.
Some discussion on this topic is documented in Discussion #5089 from the User Stats & Group effort in ‘23/’24. The outcome was ..
(To edit once officially decided) Read more about the planned NextJS architecture in ADR ?
- This is the OG NextJS app in FEM. It handles all Zooniverse projects at the route
/projects/[owner]/[projectName],/projects/[owner]/[projectName]/classify, and/projects/[owner]/[projectName]/about- Zooniverse projects now point to the FEM frontend by default (only their homepage, classify, and about pages), with a select list of projects pointing to the legacy PFE frontend. You can find the list of projects “held back” on PFE in its slugList.js.
- The
/talk,/stats,/collectand/recentsproject pages point to the PFE frontend for all Zooniverse projects. Their rebuild in FEM is planned for 2026 and onwards. - app-project has a
basePathconfig as/projectsbecause during the first couple of years of FEM development, there were two NextJS apps, app-project and app-content-pages. When the apps were launched, a single domain could only host one NextJS app. Each app was given its own subdomain:fe-content-pages.zooniverse.organdfe-project.zooniverse.organd then proxied URLs fromwww.zooniverse.orgto those domains (ADR #36).- app-content-pages has since been absorbed into app-root.
- We still have two NextJS apps in FEM.
- This app is deployed at https://fe-project.zooniverse.org.
- This is the newest Next.js app in FEM. It was added during the User Stats & Groups effort in ‘23/’24. It handles all FEM routes other than Zooniverse projects (
/projects/[owner]/[projectName]). - Relevant routes in the App Router:
-
/(homepage) /users/groups/about/get-involved-
/projects(Only the exact path, which is the Zooniverse Projects page)
-
- This app’s dependencies are intentionally minimal. It does not contain libraries for test suites or Storybook. Those development tools are in the FEM Zooniverse libraries described below.
- Why weren’t the above routes simply added to app-project?
- app-project’s router is and always was a Pages Router. In 2023, Next’s App Router was released as a stable feature, and at the Zooniverse Team Meeting July 2023 it was decided the “new” FEM routes would be handled by a new FEM app with the latest SSR features. Also, app-project is configured with a
basePathof/projects, and we were rebuild page routes not on the/projectspath.
- app-project’s router is and always was a Pages Router. In 2023, Next’s App Router was released as a stable feature, and at the Zooniverse Team Meeting July 2023 it was decided the “new” FEM routes would be handled by a new FEM app with the latest SSR features. Also, app-project is configured with a
- app-root is deployed at https://fe-root.zooniverse.org/
- The primary export is a frozen object of async states to use in data stores.
- Used in lib-classifier to define ready states in the mobx-state-tree. For example, the task area in the classification interface should be disabled until the subject area is successfully loaded.
- Used in app-project to define app loading state. For example, certain UI components depend on “user project preferences” successfully loaded.
- Used in lib-subject-viewers to define loading state of the VolumetricViewer.
- Used in lib-user to define success or error state when exporting stats data.
- A library of the classifier UI components and mobx-state-tree store.
- Used in app-project as an isolated React component on the
/classifypage.- The only exception to the above is ongoing development of the Subject Level Talk Page (SLTP) where subject viewer UI components are exported from lib-classifier and imported by SubjectTalkViewer in app-project.
- A library of components used in content pages such as About Zooniverse, Get Involved, Policies, and signed-out Homepage.
- The components in this library are imported into app-root. For example, the About page.
- The primary export of this library is the Zooniverse theme object for the Grommet 2.0 React component library.
- It’s widely used in all FEM apps and libraries. Examples:
- In a test suite.
- In a Storybook file.
- Passed to a Provider in app-root.
- A javascript client for Panoptes. This client is designed to be stateless. It is up to the consumers of the library to decide how to store the responses from Panoptes as state.
- The Zooniverse website originally used the panoptes-javascript-client (PJC) library for requests to the Panoptes API. PJC is still used in some FEM apps and libraries because key features like user authentication functions haven’t yet moved to FEM’s lib-panoptes-js.
- Ideally, the plan for future dev work on this client is to replace
superagentwith modernfetchrequests, and eventually deprecate PJC.- Note: In many components, there’s no need for a client like lib-panoptes-js. See an example in lib-user where native
fetchis used..
- Note: In many components, there’s no need for a client like lib-panoptes-js. See an example in lib-user where native
- A library of Zooniverse-specific React components, built using Grommet.
- It’s widely used in all FEM apps and libraries. Examples:
- ZooHeader in app-root and app-project
- Markdownz in lib-classifier and
- A library of subject viewer UI components. For now, this library contains only the VolumetricViewer. That particular viewer was developed for the Zooniverse project Mind Mapper, and due to its Three.js dependency, it was placed in a library external to lib-classifier and “lazy loaded” only for Mind Mapper’s
/classifypage. - There are no concrete plans to move the rest of the subject viewers to this library yet. However, as various subject previews in Talk, Recents, and Collections are developed, it’s worth considering if lib-react-component’s Media should be moved to lib-subject-viewers because it’s only use case in FEM is to render subject preview cards (aka a subject viewer). This would solve a circular dependency between lib-classifier, lib-subject-viewers, and lib-react-components for the VolumetricViewer.
- A library for the Zooniverse user stats, user group stats, and user-related components of the home page.
- The components in this library are imported into app-root as part of
/usersand/groups. - For example, UserStatsContainer is the entire page contents in between ZooHeader and ZooFooter for
/users/[login]/stats- In an ideal NextJS App Router, the UI layout is a server component, and then if the child UI components need client side data, they get a visual loading state while the browser fetches. Note that Zooniverse user auth functions are client-side only, therefore the contents developed in lib-user was intentionally architected with a top-level loading state in app-root’s AuthenticatedUsersPageContainer, and only when an authenticated user is detected, the page contents appear. There is a world where lib-user could be refactored to setup individual UI components with a loading state and their page layouts in app-root rather than the “whole page” being dropped in from lib-user, but at the time of dev, app-root was brand new and it was easiest to build “whole page” components in lib-user to complete the user stats / groups deliverables.
- A linter, customized for the Zooniverse. However, most Zooniverse devs do not use this tool.
- We do use the formatting established during FEM’s init, such as 2 spaces for indentation, no semicolons, etc.
- In the future, this tool could be refactored to standardize
eslintor similar for anyone running FEM locally.