Node 14+
Run the available setup script using yarn run setup
Alternatively, run the following individual commands:
- Generate an environment file defining
PORT=3033
andJWT_SECRET
. The secret can be any value. - Run
yarn
to install packages - Provision the database using
npx knex migrate:latest
- Build the app using
yarn run build
- Start the server using
yarn run start
The app has a few basic features:
Users can create accounts and login using the /authenticate
endpoint
The schema is:
{
email: EmailAddress, // must be valid email
password: String,
create: Boolean, // set to 'true' if signup
createdAt: DateTime
}
Authentication and refresh tokens are passed in the cookie header as _jwt
and _ref
respectively
Returns:
{
userId: EmailAddress,
token: JWT,
refreshToken: RefreshToken
}
Authenticated users can request a welcome message and image using the /welcome
endpoint
Returns:
{
msg: String,
img: URL
}
Settings defines an endpoint allowing different account settings to be updated. Currenty, only password
is defined.
The user's password can be updated like this:
{
password: {
currentPassword: String, // server verifies current password before allowing change
newPassword: String
}
}
The UI handles authentication and displaying welcome messages, along with changing passwords
The app loads the default page, after which it queries the /authenticate
endpoint to determine whether it has a valid token.
If not, the backend will try to refresh the token using the refresh token passed in the header. If it can refresh, a new auth token and refresh token are passed along and the request continues. If the token can't be refreshed, an error response is returned and the user must authenticate again with an email and password.
If the user is authenticated, the app state reflects this by displaying the Welcome
component, which sends an authenticated request to the /welcome
endpoint to retrieve the day's message and image.
The app is broadly split into a few parts:
Contains the database driver for Knex and migrations. Also houses the SQLite database file once provisioned. The SQLite database contains users and refresh tokens. It is not seeded.
Holds the React app:
- /components: Reusable components directory
- /hooks: Custom React hooks
- /pages: App views
- /providers: Context providers for global app states
Stylesheets, compiled scripts, etc.
API routes
Helper functions for signing tokens, middlewares, etc.
Automated unit tests
Hold the view controllers used by Express
Tests are built using Jest
Run tests by starting the server yarn run start
and using yarn run test
Some things to consider for implementation in a production system:
- Security: Passwords are stored in plaintext in a SQLite database file. This is neither secure nor stable enough for a production system. Passwords should be salted before being written and the database should exist as a standalone instance, either managed or unmanaged. It should be backed up and redundant to reduce downtime. In production, we'd also use SSL to secure transmissions.
- Scalability: This app only has a couple routes, but for larger apps it would make more sense to use a frontend framework like Next to handle routing.
- Styling: Production apps should have a style guide and component library.
- Tests: More robust tests for more edge cases. The small number of tests currently written is simply a result of the time constraints.
- Documentation: This README should be cleaned up and a dedicated documentation page set up.
- Load balancing: This app uses the built in Express server to listen on a port for requests. In production, we'd want to load balance and potentially turn the associated service into serverless functions
- Email verification: This app doesn't verify emails to keep the project self-contained for evaluation purposes. Ideally, this app would use an email server to send verification links, password reset links, new login notifications, etc.