Skip to content
Yangshun Tay edited this page Apr 20, 2024 · 26 revisions

Getting Started

Install Yarn

Install Yarn as the package manager. All npm commands should be using yarn and not npm. After installing Yarn, run yarn once at the root of the repository.

yarn

Set up the .env file

Make a copy of apps/portal/.env.example to apps/portal/.env. This is the environment config that is used by the TIH Portal Next.js app.

cp apps/portal/.env.example apps/portal/.env
  • DATABASE_URL: You will need to have a PostgreSQL database already running and add in the password. You can use Supabase to spin up a managed PostgreSQL database quickly if you don't want to bother with setting up local databases.
  • GITHUB_CLIENT_SECRET: Ping @yangshun) for the value.

Run the app locally

At the root of the repository:

  • yarn dev: Runs just app/portal. Most of the time you'll only need this. Open http://localhost:3000 to access the app.
  • yarn dev:ui: Runs just app/storybook. Runs the local Storybook environment.

Tech Stack

Area Choice What is it
Monorepo Turborepo High-performance build system that allows you to break a repo into multiple smaller packages
Language TypeScript Statically typed JavaScript
View React Most popular UI library
App Framework Next.js React meta framework that has multiple ways of rendering
Styling Tailwind CSS Rapidly build modern websites without ever leaving your HTML
Data Fetching React Query A pretty sophisticated data fetching library
Auth NextAuth.js Authentication for Next.js, supports many OAuth options
Type Safety tRPC End-to-end typesafe APIs made easy
ORM Prisma Next-generation Node.js and TypeScript ORM
Database PostgreSQL Popular open source relational database

Development

Source Control

  • main is release branch and should remain stable at all times.
  • Create feature branches for your in-progress features and using the format <username>/my-feature (doesn't have to be your GitHub username, just use something identifiable and be consistent about it).
  • Before merging/pushing to main, ensure that running yarn ci in the root directory doesn't show any errors.
  • We use a variation of Conventional Commits specification for commit messages:
  • Use [feat] my commit message instead of feat: my commit message.
  • Prefix the commit message with the project. E.g. [resumes][feat] foobar, [offers][fix] foobar, [questions][refactor] foobar.
  • Rebase and squash commits into a single commit before merging into main. We don't want main to contain any merge commits. A linear Git history is much easier to look at.
  • Delete your branch after merging into main.

Code Editor

Directory Structure

The repository is structured as a Turborepo monorepo:

.
β”œβ”€β”€ package.json # Global dependencies. You shouldn't need to modify this.
β”œβ”€β”€ apps
β”‚   β”œβ”€β”€ portal # TIH portal
β”‚   β”œβ”€β”€ storybook # Storybook to view and try UI components
β”‚   └── website # Existing website on Docusaurus. Ignore
└── packages
    β”œβ”€β”€ eslint-config-tih # ESLint configuration
    β”œβ”€β”€ tsconfig # TypeScript configuration
    └── ui # UI components

You should spend most of the time building within /apps/portal. New dependencies should be installed within /apps/portal/package.json.

Front End

Next.js

  • For most imports, use ~/ which is an alias for the apps/portal/src instead of relative paths.
  • We're using the new newNextLinkBehavior: true flag, so there's no need for <a> within <Link>.
  • SSR pages as much as possible (via getServerSideProps()), rather than fetching data on the client side for better SEO.
  • Work within your designated directories:
    • Resumes: src/components/resumes and src/pages/resumes
    • Offers: src/components/offers and src/pages/offers
    • Questions: src/components/questions and src/pages/questions

React

  • Props should be Readonly.
  • Props should be sorted alphabetically.
  • Props should be destructured in the component function declaration.

Styling

  • Use components as much as possible, rather than Tailwind classes.
  • Color guidelines:
    • Use semantic colors where available:
      • Use primary instead of purple/indigo (e.g. text-primary-500 over text-indigo-500. This is so that we can change all the colors anytime by changing the Tailwind config.
      • Other available colors:
        • danger (red)
        • success (green)
        • warning (yellow)
        • info (blue)
    • Use slate instead of gray as that's our preferred shade of gray.

Data Fetching

React Query is a client side state management library to help you manage remote state (data fetched from the server). With React Query (and tRPC), you can do data fetching in a declarative and typesafe manner.

Form Library

  • Form library TBD. Possibly react-hook-form.
  • Don't add state for forms unless necessary (e.g. front end validation).

Back End

Data Model: Prisma

We use Prisma, which is an ORM for JavaScript/TypeScript applications. Make sure you have the Prisma VS Code extension installed, which gives you autocompletion and formatting of the .prisma files.

  • Model
    • Namespace/Prefix your models per project (e.g. ResumesSomething, OffersSomething, QuestionsSomething).
    • enum values should be written using UPPER_SNAKE_CASE.
  • Fields
    • Use camelCase for fields in schema.prisma. If you see some snake_case fields in Account, that's because of the requirements of NextAuth.js, and they are exceptions.
    • Use cuid() for ids, don't use autoincrement(). We don't want to reveal how many rows there are in a table.
    • Look around and see the existing schema fields and try to be consistent about field naming, even across projects.

Prisma Studio

In case you want to have an admin view of your database, run yarn prisma studio which will run an admin web app on http://localhost:5555.

Server API calls: tRPC

We're using tRPC v9. Check that you're looking at the right version of the docs because v10 is quite different.

  • userIds for creator fields should always come from the session, not from a parameter.
  • Prisma doesn’t have ACL (access control list), so we need to manually implement permissions in tRPC routing code.
  • Handle errors properly. Refer to error docs.

Database

Set up your own local PostgreSQL database and update the DATABASE_URL field within the .env file.

Setting up

Running prisma migrate dev in apps/portal updates the database specified in .env with the latest changes. You will need to run the command if it's your first time setting up the database and every time schema.prisma changes.

Changing schema

  1. After you change schema.prisma, run prisma migrate dev in apps/portal. Prisma will generate migration files for you and make the changes to your local database.
  2. Ping @yangshun for now to productionize any changes.

Auth

We're using NextAuth.js which has integrations with many auth providers for Next.js and is super handy. Most of the time you won't need to mess with authentication since it's already done. But if you need to, here's NextAuth.js' official demo site and the source code on GitHub.

Google Analytics

Setting Up

  1. Configure your product's Google Analytics 4 (GA4) measurement ID in your product config.
  2. Note that GA logging is disabled during development by default. If you want to test the logging during development, comment out the process.env.NODE_ENV === 'development' checks in GoogleAnalytics.tsx.

Logging Events

import { useGoogleAnalytics } from '~/components/global/GoogleAnalytics';

function MyComponent() {
  const { event } = useGoogleAnalytics();

  return <div>
    <button onClick={() => {
      // Reference: https://developers.google.com/analytics/devguides/collection/gtagjs/events
      event({
        // Prefix with your action strings with your product name
        // because eventually we'll combine all the events into measurement ID.
        action: 'offers.button_click',
        category: 'engagement',
        label: 'Click Me',
      });
    }}>
      Click Me
    </button>
  </div>
}