Plutomi is a multi-tenant applicant tracking system that streamlines your entire application process with automated workflows at any scale.
Having worked at a company that needed to recruit thousands of contractors every month, improving our acquisition flow at that scale became a challenge. Many processes had to be done manually because there just wasn't an API available for it. We often hit limits and had to work around them with a myriad of webhooks, queues, and batch jobs to keep things running smoothly. It would have benefited us to have an open platform to contribute to and build upon and this project is my attempt to do just that.
You can create applications
which people can apply to. An application can be anything from a job, a location for a delivery company, or a program like a summer camp.
In these applications, you can create stages
which are individual steps that need to be completed by your applicants
. You can add questions
and setup automatic move rules
that determine where applicants go next depending on their responses
or after a certain time period.
An application for a delivery company might look like this:
New York City
Stages:
- Questionnaire - Collect basic information of an applicant. If an applicant does not complete this stage in 30 days, move them to the Waiting List.
- Waiting List - An idle pool of applicants
- Document Upload - Collect an applicant's license
- Final Review - Manually review an applicant's license for compliance
- Ready to Drive - Applicants that have completed your application
- Node 20
- Rust
- Docker
- AWS CDK CLI and SSO
Plutomi is deployed to AWS using CDK. A couple of resources are created like a Fargate service which runs the web app (NextJS) and api (Rust with Axum) in a private subnet as well as a NAT instance using fck-nat for outbound traffic. We use SES for sending emails and have an event processing pipeline to handle things like opens, clicks, bounces, and custom app events like totp.requested
or invite.sent
. We use Lambda to process events and they are written in Rust with Cargo Lambda. We use Cloudflare for DNS, CDN, WAF and other goodies - make sure to add a Cache Rule to ignore /api
routes.
For the database, we are using MongoDB on Atlas where we store everything in one collection. We write small documents and index a relatedTo
attribute that is shared across all items. For most queries, we can get an item and all of the items it is related to without using $lookup
. You can check this video for a demonstration of this technique.
Logging is handled by Axiom but this isn't required. Do note that we disabled CloudWatch logging in production due to cost reasons.
The following will start the API and the web app in development mode:
$ scripts/run.sh
You can also run either individually:
$ scripts/run.sh --stack <web|api>
The script also has hot reloading for both so you can make changes and see them reflected immediately once you change and save a file. Update the .env
in packages/<api|web>
for any environment variables needed.
To deploy to AWS, make sure you have configured SSO correctly. Update the AWS_PROFILE
variable in deploy.sh to match the profile names you want to use. Update the subdomain you want to use for sending emails in configureEmails.ts.
Change directories into packages/aws
, install dependencies, and set up the environment-specific .env
files and modify the values as needed.
$ cd packages/aws
$ npm install
$ cp .env.sample .env.development
$ cp .env.sample .env.staging
$ cp .env.sample .env.production
Once that's done, you can go back to the root and deploy using scripts/deploy.sh <development|staging|production>
.
After running the deploy script, most of your environment will be setup but you'll need to add a few records to your DNS provider. For a custom domain on the load balancer, make sure to validate your ACM certificate. For SES, your dashboard should look something like this with the records you need to add:
Also, make sure to setup DMARC. This is a TXT record with the name _dmarc.yourMAILFROMdomain.com
and value v=DMARC1; p=none; rua=mailto:you@adomainwhereyoucanreceiveemails.com
See this link for more information.
In MongoDB, make sure to whitelist the IP address of the NAT instance which you can find in the EC2 console. We will eventually migrate over to use PrivateLink.
This project is licensed under the Apache 2.0 license. Here is a TLDR.
To make a contribution, submit a pull request into the main
branch. You will be asked to sign a Contributor License Agreement for your PR. You'll only have to do this once.
Thanks goes to these wonderful people who contributed!
Jose Valerio 💻 🚇 🚧 |
praguru14 💻 🚧 |
Jose Valerio 💻 🚧 🐛 |
Jeremy Trenchard 💻 |
CodingRubix 💻 |
jlittlewood-scottlogic 💻 🎨 |
This project follows the all-contributors specification. Contributions of any kind welcome!
Open an issue! Or DM me on Twitter or email jose@plutomi.com