QC Service Pros aims to be a modern take on what Angie and Home Advisor could be if they were built solely for a metropolitan area.
Using Modern tooling, and a focus on user experience, QC Service Pros hopes to provide a better experience for consumers and service professionals alike.
This guide will be used to document the project and the decisions made along the way, along with some of the key features and concepts and architecture.
This application is made up of two main parts:
- A consumer-facing website
- A service professional-facing website
The consumer-facing website is used to allow consumers to find and book service professionals.
The service professional-facing website is used to allow service professionals to manage their business.
Key terms:
- Business: A business is a service professional that provides a service to a consumer.
- Customer: A customer is a person who is looking for a service professional.
- Job Request: A job request is a request for a service from a customer to a business. From a database perspective, a customer owns and can have many job requests.
- Lead: A lead is the same as a job request, but we decided to use the term "lead" to refer to a request for a service from a customer to a business due to negative connotations with the term "lead".
- Opportunity/Connection: If a customer submits a job request to a business, and the business accepts the job request, the opportunity is created. This is currently called a connection. From a database perspective, a business owns and can have many connections.
The project is currently divided into to applications:
qc-service-pros: An application that is used to power the consumer-facing website.qc-service-pros-landing-page: An application that is used to power the landing page of the website.
Note that if given more time, we would have liked to combine the landing page and the consumer-facing website into a single application once a refactored signin/signup flow was in place.
To keep costs at a minimum, this project is built using a serverless architecture.
- AWS Amplify is used to host the application
- AWS Cognito is used to store user authentication data.
- DynamoDB is used to store the data for the application.
- AWS AppSync is used as the API and AWS Lambda is used for any custom business logic.
- Amazon S3 is used to store the images for the application.
- Amazon SQS is used to process the job requests asynchronously.
- Resend is used to send emails. SES is not used due to the annoyance is getting production access once ready to move out of the Sandbox.
- Amazon EventBridge Bus is used to handle Stripe events
- Amazon EventBridge Scheduler is used to send future dated emails
- Amazon Bedrock is used for the AI services.
- Stripe is used to process payments. Specifically the following components are used
- Stripe Pricing table
- Stripe Customer Billing Dashboard for account management
Review the project architecture document for a high-level overview of the project.
On the consumer-facing website, a business can signin via email/password. Note that while this currently only supports email/password, adding support for social signin was an in-flight task. With the current architecture, a postconfirmation trigger is used to add the user to a specific group (the business group) in Cognito. This allows us to control what resources the user has access to based on the group they are in.
On the consumer-facing website, a customer can signin via facebook or google. Note that while this currently only supports facebook and google signin, adding support for email/password signin was an in-flight task. Because a postconfirmation trigger doesn't fire for social signins, the migration tasks involved would have been non-trivial, but would essentially been moving away from the postconfirmation trigger to a post authentication trigger and adding a custom cognito attribute.
Once a user is signed in, the job request flow becomes a simple crud operation on a JobRequest resource. Customers can choose to use AI to generate a description of the job request, or they can manually enter the details.
Once the job request is created, it is sent to all the businesses in the area. The businesses receive a notification via email and the connection is created.
- Customer creates a job request
- Job request is sent to all businesses in the area
- The businesses tier determines when they receive the job request:
- Elite: Businesses receive the job request immediately
- Standard: Businesses receive the job request in 1 hour
- Lite: Businesses receive the job request in 2 hours
- Businesses receive an email with the job request details, but not customer details
- Businesses click the link in the email and are redirected to the business-facing website
- Before viewing the connection, a check is made to make sure the business has access to the connection, the job request is still active, and if so, the business is then charged the connection fee.
When a customer creates a job request, the following components are used in the billing process
- Category
- Subcategory
- Job Request assumed complexity
- If the job request is urgent
By selecting a category, the subcategories will appear. Each subcategory has a price associated with it. This price can be found in the utils file, in which only the base price is used. That base price is what we call a job cost estimate.
A customer can select up to 5 ranges of complexity when creating a job request. The complexity multiplier is then applied to the job cost estimate. Note that a complexit of 1 or 2 yields the same multiplier of 1, and a complexity range of 3 or 4 yields the same multiplier of 1.5. A complexity range of 5 yields a multiplier of 2.
If the job request is marked as urgent, a multiplier of 0.5 is applied to the job cost estimate (see the formula below).
The formula for pricing a job request is as follows:
Job cost estimate X (complexity level multiplier 1 or 1.5 or 2 (based on 1-5 rating) + .5 (urgency if marked))
This represents the amount that we think the job will cost. This amount is then looked up in a table of pricing tiers to determine the price charge to the business.
A cron job (not yet created) will run once per month to gather all businesses, find their connections, sum them up, and charge the business for the connections. While getting started, this can be done manually by an admin.
As with most javascript projects, by installing the dependencies and running npm run dev, the application can run locally. However, because the serverless backend needs to be deployed, be sure to have followed the setup guide from their docs.
As noted in the sample.env file, the following environment variables need to be set:
- STRIPE_EVENTBUS_ID
- NEXT_PUBLIC_STRIPE_PRICING_TABLE_ID
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
- NEXT_PUBLIC_STRIPE_CUSTOMER_BILLING_PORTAL_ID
- STRIPE_SECRET_KEY
- RESEND_EMAIL_API_KEY
Once the environment variables are set, the application can be deployed by running npm run build and then amplify push.
- Add a cron job to charge businesses for their connections
- Allow social signin for businesses as discussed above
- Fix ownership issue of connections. Currently they are saved in the database and the email is sent to the business, but this is not reflected in the UI.
- Changing the verbiage of "connection" to "opportunity".
- Separate accounts for sandbox, test, and production environments.