- T4SG Spring 2024 Application Deliverable
Welcome to Biodiversity Hub, the webapp for T4SG's Spring 2024 applications!
The project uses Next.js, a React-based framework with significant optimizations. The frontend uses shadcn/ui
, an open-source library of UI components that are built with Radix primitives and styled with Tailwind CSS. The backend uses Supabase, an open-source Firebase alternative. The entire stack is written in Typescript to provide comprehensive typesafety across both frontend and backend.
To set up the starter code for Biodiversity Hub, follow these instructions in order.
You should first update your npm
and node
packages to the latest version by following this installation guide. (If you use a Node versioning manager like nvm
, you can just update through there.)
cd
into a desired destination folder, then clone the repo (preferably using SSH):
git clone [email protected]:hcs-t4sg/s24-eng-r2-deliverable.git
-
Open the project folder in VSCode. You can do so with the following terminal shortcut:
# Navigate into the project directory cd s24-eng-r2-deliverable # Open in VSCode code . # If the second command gives you an error, you probably don't have the VS Code 'code' keyword added to your PATH variable. Follow this tutorial: # https://www.freecodecamp.org/news/how-to-open-visual-studio-code-from-your-terminal/#:~:text=Once%20your%20terminal%20is%20open,Then%20hit%20enter%20.&text=Once%20you%20hit%20enter%20%2C%20VS%20Code%20will%20now%20open.
-
Open a terminal in the project folder by dragging up from the bottom of the code window or by going to
Terminal > New Terminal
in the menu bar. -
Run:
npm install
(npm i
for short)- If you get something like "command not found", you might not have
npm
installed. - Make sure you're running
npm install
inside the project directory. That is, your terminal should indicate you're inside thes24-eng-r2-deliverable
directory. If you're using MacOS (with azsh
terminal), this probably looks something like:username@some-address s24-eng-r2-deliverable % npm install
- If you get something like "command not found", you might not have
-
If successful you should see something like:
added 414 packages, and audited 415 packages in 13s 149 packages are looking for funding run `npm fund` for details found 0 vulnerabilities
-
You should see a popup in the bottom right prompting you to install recommended extensions. Please install these, they'll be helpful for code formatting and developing the webapp. You can also view the recommended extensions in the extensions sidebar (
cmd + shift + X
.) -
You will also get a prompt to use the workspace's Typescript version; accept it. You may have to navigate to any
.ts
or.tsx
file in the project and open it to receive the prompt. If you don't get one, or if you get an error that the path "does not point to a valid tsserver install", make sure you're using the workspace's Typescript version by pressingcmd
+shift
+P
and typing "typescript", selectingTypescript: Select Typescript Version
, and selectingUse Workspace Version
. Again, you'll need to be viewing a.tsx
or.ts
file to do this.
-
Visit the Supabase website, create an account (or login if you already have one), and create a new project. You will be prompted to set a Database Password; remember it. Wait for your database provisioning and setup to finish.
- Try to avoid using special characters like
?
,$
, etc. in your password.
- Try to avoid using special characters like
-
There is a
.env.example
file in your local project directory (e.g. in VSCode). Duplicate it (into the same directory) and rename to.env
. Inside.env
, set the following variables according to your Supabase project settings:NEXT_PUBLIC_SUPABASE_URL
: From Project Settings > API > Project URL.NEXT_PUBLIC_SUPABASE_ANON_KEY
: From Project Settings > API > Project API Keys >anon
public
.SECRET_SUPABASE_CONNECTION_STRING
: From Project Settings > Database > Connection String > Nodejs. Replace[YOUR-PASSWORD]
with your database password.- If you insist on using special characters in your password you will need to replace them with the percent-encoded version (see this reference)
The final result should look something like this:
# Some other comments above NEXT_PUBLIC_SUPABASE_URL="https://abcdefghijklmnopqrst.supabase.co" NEXT_PUBLIC_SUPABASE_ANON_KEY="longlonglongstring" SECRET_SUPABASE_CONNECTION_STRING="postgresql://postgres:[email protected]:5432/postgres"
You should not share these keys publicly, especially the
SECRET_SUPABASE_CONNECTION_STRING
.
- In your Supabase project dashboard, navigate to
SQL Editor
in the left sidebar, then click(+) New Query
>New blank query
. If you wish, you can rename the query from "Untitled Query" to something else by clicking the dropdown in the left sidebar. - In your starter code, there is a
setup.sql
file containing a SQL script that will set up the database for you. Copy the entire contents of the file and paste it into your new query. - Run the query with the button in the bottom right or by pressing
cmd
+return
. In the results panel, you should see the messageSuccess. No rows returned
. If you're having issues with this, contact Eileen and Matthew (the directors of engineering)!
-
The below command will run the webapp locally so that you can view and test your code when developing. Go ahead and run it:
# Start the webapp in development mode (usually what you do in development). Exit with Ctrl + C npm run dev # You'll get several "compiling" messages after running this command. That's expected!
By default, the webapp should be accessible at
http://localhost:3000/
. -
Now you need to log into the webapp with the
Log In
button in the top right. Enter an email to receive a magic link (at that email) that you can use to log in. (Make sure you open the link in the same browser from which you initiated the login). Accounts are associated with email, so if you ever need to log back in just enter the same email. -
Once you log in, go to your Supabase database (via the
Table Editor
in the left sidebar of the project dashboard) and confirm that theprofiles
table has a row corresponding to your email.
We gave you some example species data to seed your database! Follow similar steps as in the "Supabase Database Setup" section to set it up. Make sure you've confirmed that the profiles
table is non-empty (see previous step).
- In your Supabase project dashboard, navigate to
SQL Editor
in the left sidebar, then click(+) New Query
>New blank query
. If you wish, you can rename the query from "Untitled Query" to something else by clicking the dropdown in the left sidebar. - In your starter code, there is a
seed.sql
file containing a SQL script that will set up the database for you. Copy the entire contents of the file and paste it into your new query. - Run the query with the button in the bottom right or by pressing
cmd
+return
. In the results panel, you should see the messageSuccess. No rows returned
. If you're having issues with this, contact Eileen and Matthew (the directors of engineering)!
-
The Supabase CLI will be helpful for a number of functions, such as running Supabase locally and generating Typescript types from our database schema. For the CLI to work, you will have to install Docker. During the installation process, if Docker prompts you to run an
osascript
, make sure to run it. -
If you've done
npm install
, the CLI should already be installed. You can test it by runningnpx supabase
, which will give you a version (Supabase CLI 1.64.8
) and a list of commands. -
We preconfigured a command (in
package.json
) for you to easily generate type definitions inlib/schema.ts
from your remote Supabase database schema. These type definitions are used throughout the codebase to make sure you're interacting with the database correctly. You don't need to run this command now, because we've already set up the database schema for you. However, make sure to run it if you edit your database schema (adding columns, tables, etc).// Introspects your remote Supabase database and generates types in lib/schema.ts npm run types
Note: You need to have
SECRET_SUPABASE_CONNECTION_STRING
configured in.env
in order for the above command to work.
More instructions on troubleshooting potential errors are below.
This section provides a short description and important commands related to each component of the stack.
Typescript is a strongly-typed programming language based on Javascript. It integrates closely with your editor and provides type inference and static type checking to catch errors/bugs early-on and provide a great developer experience. Furthermore, it is a superset of Javascript and can be transpiled to any version of Javascript to run in browsers.
Typescript applies type inference to your files automatically, but you can also manually run it with the following terminal command:
# Type check all typescript files (--noEmit disables generation of a report file, which is not needed)
npx tsc --noEmit
A quick tip on coding with Typescript: When fixing type errors, you should avoid using type assertions (with as
) and the any
type as much as possible. These functionalities are escape hatches built into Typescript to allow you to avoid type-checking, but they don't actually solve the underlying problem of a type error! Simply ignoring the problem by avoiding type-checking will only make future bugs much more difficult to fix. Most of the time, a type error exposes an important error/oversight in your code.
Sometimes you may run into a Typescript error that seems incorrect or won't go away. The error might just be a result of lag in VSCode's Typescript server, so try reloading the server by hitting Cmd + Shift + P
, typing Reload
, and selecting Developer: Reload Window
.
Finally, note that type definitions for many npm
packages are maintained by the Typescript community and may be found with the @types/
prefix on npm
, if they're not already included in the package itself (generally they are). Several of the config files in the project (ex: .prettierrc.cjs
) manually import type definitions, but you generally will not need to worry about such syntax in your actual source code.
More references
The project uses UI components from shadcn/ui
, an open-source library of UI components prebuilt with Radix and Tailwind CSS.
Radix is what developers refer to as a "headless" (or "behavior") UI library. It controls how components work (i.e. dropdowns, buttons, checkboxes) and provides a set of unstyled, functional, accessible components (aka primitives) to which further styling can be applied. To change how our components look, we style them with Tailwind CSS, which is a CSS framework that allows us to rapidly apply CSS styling to our components by adding html classes.
shadcn/ui
provides a set of UI components prebuilt with Radix and TailwindCSS that can be copy-pasted into our project or added with its CLI (with the terminal command npx shadcn-ui add
). These components are not "imported" like they are in other component libraries like MUI; they are simply additional code added to our project, which gives us full control over the styling and functionality of each component if necessary. The result is a component library that looks nice with minimal effort but is also easily customizable! Individual shadcn/ui
components can be customized in components/ui
, and global theming can be customized in app/globals.css
.
More references
Next.js is a React-based framework that offers significant optimizations with relatively small learning curve. Notably, it provides a powerful page routing system, ability to create built-in API routes without a separate backend, and a variety of options for fetching data and rendering content on the server.
To run the webapp in development mode, use the following terminal command:
# Start the webapp in development mode (usually what you do in development). Exit with Ctrl + C
npm run dev
To create and run a production build of the webapp (great for testing before deployment), use the following terminal command:
# Create a production build
npm run build
# Start the production build
npm start
Note that React 18 introduced server components, which form a new paradigm for conceptualizing and constructing webapps. This project uses the Next.js app/
router, which was introduced in Next.js 13 and uses React server components. Server components are very new and can take a while to wrap one's head around (especially for people already accustomed to React's old "mental model"). However, React and Next.js development is shifting towards this new paradigm, just like how we shifted from using class components and lifecycle methods to using functional components and hooks in React a few years ago. So we at T4SG Eng want to move along with the rest of the developer community and ensure that we're learning/practicing the most relevant skills!
If you are new to React, check out the React documentation first before touching Next.js. The Next.js docs have a great React Essentials section. When browsing documentation or looking at tutorials for Next.js, try to first look for examples explicitly referencing Next 13 or the app
router, not the pages
router (which is the older way of building Next.js webapps).
More references
- Official Next.js documentation
- Official React documentation
- Learn Next.js - an interactive Next.js tutorial.
- Next.js GitHub repository - good place to ask for help!
- Example Next.js project built by
shadcn
!
The backend uses Supabase, an open-source Firebase alternative. (Both are BaaS platforms: backend as a service.) Supabase provides all of Firebase's most important functionality and more:
- Database: Built on Postgres, a relational database which is open-source (thus more easily maintainable by clients).
- Realtime: Allows you to listen to changes in the database (aka Postgres Changes). Supabase also offers Broadcast and Presence, which are other forms of realtime that provide ultra-fast synchronization for features like chatrooms or online games.
- User authentication: A simple auth system with all social providers and user permissions for database access.
- File storage: Cloud storage for any kind of digital content.
- Edge functions: Server-side Typescript functions that run on Supabase without needing to set up a backend server.
- Local development: Ability to easily create locally-hosted Supabase projects with tracked migration history (super useful when working in teams)
- Typesafety: The Supabase CLI (command line interface) can be used to generate Typescript types based on your database schema, allowing for typesafe database queries.
More references
- Official Supabase documentation
- Example project using Supabase auth with Next.js app router
- Another example project
Whenever you're running the CLI (such as running the type-generating command above) you might get an error:
Cannot connect to the Docker daemon at unix:///Users/matthewsu/.docker/run/docker.sock. Is the docker daemon running?
Make sure you have Docker running, and start a new terminal and retry the command. If that still doesn't work, you may need to manually point your terminal to Docker in the terminal configuration. Example instructions for using a zsh
terminal on MacOS:
-
Find your
.zshrc
file. Instructions for finding it are here; note that it is a hidden file, so you may have to presscmd
+shift
+.
in Finder in order to see your hidden files. -
Open
.zshrc
with notepad and add this line:export DOCKER_HOST=unix://"$HOME/.docker/run/docker.sock"
-
Save and close
.zshrc
, then start a new terminal (make sure you're using azsh
terminal and not abash
terminal) and retry the command.
Feel free to reach out for help!
This section provides information on various tools this project uses to streamline the development process.
This project uses a combination of code formatting and linting tools to catch errors and enforce consistent code styling across all collaborators working on the project. Documentation and a quick description of each tool is given below. The configuration files for each tool have also been commented with additional information/references.
The preset configurations should work great out of the box, but feel free to customize them to your liking.
A linting tool that statically analyzes our code to detect and fix issues with code quality (like unused variables, residual console statements, etc). eslint
is configured to run on save and before making a git commit
(see below), but you can also run it manually with the following terminal commands:
# Easiest way to lint all relevant files in the project. Notifies you of any linting issues.
npm run lint
# Lint all relevant files in the project, fix any auto-fixable issues, and notify you of the remaining issues.
npm run lint:fix
# Specification of these npm scripts are in package.json
# Lint a specific file (or all relevant files by using "."). Add the --fix tag to have eslint correct errors that are automatically fixable.
npx eslint [filepath or .] --fix
If you need to exclude certain folders/files from the ESLint rules, you can create a .eslintignore
file.
If you want to modify the eslint
rules, you can edit the rules
array in .eslintrc.cjs
. If adding a new rule, make sure that it doesn't conflict with prettier
by running the following command (more info here):
# Test eslint-config-prettier against some file in the codebase, for example index.tsx. You usually only need to run this for one file
npx eslint-config-prettier src/index.tsx
However, note that if you encounter an eslint
error when coding, you shouldn't just immediately ignore it or turn the rule off. These rules are put in place to catch errors you may not even know about, so you should do some extensive research on the rule (and how you might change your code to conform to it) and only ignore/disable the rule as a last resort. Listening to eslint
builds good code quality habits!
Config file is in .eslintrc.cjs
.
Formats outputted code to a consistent, opinionated style after it has been written. prettier
is configured to run on save and before making a git commit (see below), but you can also run it manually with the following terminal commands:
# Check files for formatting errors and give a human-friendly summary of all errors.
npm run prettier
# Fix formatting errors in-place for all files.
npm run prettier:fix
# Specification of these npm scripts are in package.json
Note that prettier
and eslint
have overlapping functionalities, so to prevent conflict between the two we also add eslint-config-prettier
, which disables all eslint
rules that would conflict with prettier
Finally, our prettier
configuration also includes a plugin for sorting import declarations.
If you need to exclude certain folders/files from the prettier
formatting, you can create a .prettierignore
file. The prettier
config file is in .prettierrc.cjs
.
Standardizes some settings (only in the project workspace) across different editors (Sublime, VSCode, etc) to apply formatting rules before writing code (e.g. hitting tab
leaves two spaces). Config file is in .editorconfig
. Both EditorConfig and prettier
work in tandem to enforce consistent styling/formatting across your entire team, which will help prevent some annoying formatting situations (ex: every line in a pull request being marked as a diff
because one team member uses tab indents and another uses space indents).
You can use the following terminal command, which will auto format all your code and notify you of any linting issues.
# Format all relevant files with Prettier and check all relevant files for eslint errors
npm run format
# Specification of npm scripts are in package.json
The project contains workspace-specific VSCode settings in .vscode/settings.json
. These settings (which only apply when inside the project workspace) set the editor to:
-
Format with
prettier
, then lint witheslint
on save (this is the quickest way)- (Note that we use an extension, Format Code Action, to achieve this specific order)
-
Use
prettier
as the default formatter -
Prompt the user to use the codebase's version of Typescript for Intellisense (preventing errors arising from differing Typescript versions)
These add in-editor support (syntax highlighting, error checking, etc.) for their respective tools. The recommended workspace extensions are configured in .vscode/extensions.json
.
Allows you to categorize your comments into color-coded Alerts, Queries, TODOs, and Highlights for more human-friendly annotations.
Enables you to collaboratively edit and debug with others in real time. Think Google Docs functionality but for your codebase.
Allows us to run eslint
after prettier
on save, which is the fastest order.
Improves error highlighting and displays diagnostic text inline.
Formats Typescript errors to be more human-readable.
Deployment guides for Vercel, Netlify and Docker. The easiest way to deploy is with Vercel, which was created by the creators of Next.js!