Hammock
Hammock moves your favorite newsletters outside of your understandably cluttered
inbox, letting you focus on and learn from the content you love in a
distraction-free reading space.
## Terminology and Data Model
### `User`
A user is a person; someone who uses the app.
### `Subscription`
A subscription is a recurring newsletter from a specific email address.
### `Message`
A message is an email from a recurring newsletter (extends `Subscription`).
## Implementation
Included below are some high-level descriptions of how Hammock is implemented.
The purpose of this writing is not so much to act as documentation but rather to
encourage better README-driven development.
#### Gmail Sync
Our Gmail sync is composed of various methods to ensure that our
Supabase-managed PostgreSQL database is always up-to-date with our users' Gmail
inboxes:
1. When the user first signs up, they call our `/api/sync` endpoint which starts
[a full sync](https://developers.google.com/gmail/api/guides/sync#full_synchronization)
using Gmail's `messages.list` API endpoint. This endpoint syncs 10 messages
and then redirects (using the `nextPageToken`) to `/api/sync` recursively to
sync the next 10 messages and so on and so forth. We save the current sync
cursor (the `nextPageToken` returned by the last `messages.list` call) in our
database so subsequent calls to `/api/sync` start right where we left off.
2. When the user signs up, we also setup [a Google Pub/Sub subscription](https://cloud.google.com/pubsub/docs/push)
using Gmail's [`users.watch`](https://googleapis.dev/nodejs/googleapis/latest/gmail/classes/Resource$Users.html#watch)
API endpoint. This [push subscription](https://cloud.google.com/pubsub/docs/subscriber#push-subscription)
then calls our `/api/push` endpoint which uses Gmail's [`history.list`](https://googleapis.dev/nodejs/googleapis/latest/gmail/classes/Resource$Users$History.html#list)
API to sync newly received messages as they come in.
## Development
Hammock aims to use the most cutting-edge, performant, and production-ready
solutions available. Included below is our current selection and the reasoning
behind it, but we're always open to improvements!
#### Languages
- [Typescript](https://www.typescriptlang.org) - As our language of choice
(mostly for static typing, stronger linting capabilities, etc). Typescript is
also [well supported by Next.js](https://nextjs.org/docs/basic-features/typescript)
and [React](https://reactjs.org/docs/static-type-checking.html#typescript).
- [CSS-in-JS](https://github.com/vercel/styled-jsx) - Instead of packaging
styles separately from our React components, all styles are included alongside
them _in the same files_. This allows for better code-splitting, etc.
#### Frameworks
- [React](https://reactjs.org) - As our front-end framework.
- [Next.js](https://nextjs.org) - To easily support
[SSR](https://nextjs.org/docs/basic-features/pages#server-side-rendering) and
other performance [PWA](https://web.dev/progressive-web-apps/) features.
- [SWR](https://swr.vercel.app) - Used to manage global state. SWR fetches data
from our back-end, stores it in a global cache, and allows local mutations of
that cache (with or without automatic revalidation).
- [`next-auth`](https://next-auth.js.org) - Manages authentication with JWT
session cookies.
#### Tooling
- [Yarn](https://yarnpkg.com) - To manage dependencies much faster than NPM (and
for better community support, advanced features, etc). This project uses Yarn
Berry (v2) and takes advantage of its new plug-n-play functionality.
- [ESLint](https://github.com/eslint/eslint) - For code linting to avoid
common mistakes and to enforce styling. Follow [these
instructions](https://eslint.org/docs/user-guide/integrations) to install it
in the text editor of your choice (so you won't have to wait until our
pre-commit hooks fail to update your code).
- [Cypress](https://docs.cypress.io) for integration, UI, and some unit tests.
Cypress is like Selenium; but built from the ground-up with the developer in
mind. Cypress runs alongside your code in the browser, enabling DOM snapshots,
time travel, and overall faster test runs.
#### Database
- [Supabase](https://supabase.com) - For their managed [PostgreSQL
relational database](https://supabase.com/database).
## Commit Message Format
I have very precise rules over how Git commit messages in this repository must
be formatted. This format leads to **easier to read commit history**.
Please refer to the following documentation for more info:
- [Conventional Commit Messages](https://www.conventionalcommits.org/en/v1.0.0/)
- [Angular's Commit Message Format](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format)
- [Udacity's Commit Message Style Guide](http://udacity.github.io/git-styleguide/)
### Commit Message Header
Commit messages that do not adhere to the following commit style will not be
merged into `develop`:
```
():
│ │ │
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─⫸ Commit Scope: The page, API route, or component modified.
│
└─⫸ Commit Type: ci|docs|feat|fix|perf|refactor|test|deps|chore
```
The `` and `` fields are mandatory, the `()` field is
optional.
#### Type
Must be one of the following:
- **ci**: Changes to our CI configuration files and scripts.
- **docs**: Documentation only changes.
- **feat**: A new feature.
- **fix**: A bug fix.
- **perf**: A code change that improves performance.
- **refactor**: A code change that neither fixes a bug nor adds a feature.
- **test**: Adding missing tests or correcting existing tests.
- **deps**: A change in dependencies.
- **chore**: A code change in utility scripts, build configurations, etc.
## Git Flow
This repository follows [the standard git-flow
workflow](https://nvie.com/posts/a-successful-git-branching-model/) with a
couple of important exceptions:
- `develop` should always be stable and ready for release.
- `develop` just has not yet been released (e.g. for marketing purposes, we
release changes in large batches).
- `master` represents the current production state of the app.
