Challenge Overview
If there is only one passing submission for this challenge, we will grant the second place prize money to the first place winner too. Else, the first place winner gets a $200 bonus.
EnerWise is your personal energy concierge. It is also a web application that guides a homeowner / home buyer through the process of analyzing their home’s current/expected energy usage and potential savings from adding solar and performing energy efficiency upgrades. We then connect the homeowner to the best source of capital and qualified installers to maximize their investment.
For this challenge, the goal is to implement a REST API backend and wire it up the provided AngularJS HTML prototype.
Challenge Requirements
You will address the following :
Technology Stack
You will use the follow stack in this challenge
-
- Express.JS 4.0
-
- Postgres (latest stable version)
-
- AngularJS
-
- Node.JS (latest stable version)
-
- Nginx (as reverse proxy)
-
- Async module is a must.
-
- Use Underscorejs if needed
-
- Nodemailer for sending emails
-
- S3 for uploading images
Model Definition
-
- user
-
- id (primary id)
-
- role : home_owner, financier, realtor, energy_installer, or admin
-
- email
-
- password (hashed and salted)
-
- first_name
-
- last_name
-
- company (optional)
-
- utility_name
-
- utility_referral_id : this is the utilityAPI referral token retrieved from authorization flow
-
- utility_account_id : this is the utilityAPI#account#uid
-
- utility_service_id : this is the UtilityAPI#service#uid
-
-
- user_social_account
-
- user_id
-
- type (facebook, twitter, g+)
-
- token
-
- identifier
-
-
- houses
-
- house_id
-
- address
-
- city (lookup)
-
- state (lookup)
-
- zip
-
-
- house_info
-
primary (house_id)
-
houses_of_interest (array of house_id’s)
-
number_of_adults (optional)
-
number_of_children (optional)
-
-
- user_house
-
- user_id
-
- house_info_id
-
-
- house_analysis
-
- house_id (reference id)
-
- sell-rate
-
- system-cost
-
- image
-
- solar_production (array of 12 items, each item represents a month of the year set in the record, the value is the production in kWh)
-
- solar_production#image.
-
- status : (pending/completed)
-
- Pending : It means the house_analysis of this house is not populated yet.
-
- Completed : It means the house_analysis of this house is populated by admin and ready for user to view it.
-
-
-
- financier_customer
-
- financier_user_id (reference to financier user)
-
- user_id
-
- house_info_id
-
- authorizedAccess (false/true)
-
- This becomes true only if user authorized access to financier to see the primary house information.
-
-
-
- utilities (lookup)
-
- Name
-
- service_type (electricity,gas,water,fuel_oil, other)
-
- URL - not set for ‘other’ service_type
-
- otherDetails - json object.
-
-
- state_tax (lookup)
-
- id
-
- state
-
- tax_percentage (between 0.00 - 1.00)
-
Note the following :
-
You can add more models as needed, and suggest changes to the models above.
-
Roles : in this portal only Homeowners, Financiers and Admins can login. Realtors and Installers will have their own UI soon. Your solution is preferred to be flexible to add more roles in future.
NodeJS API
-
- The backend will be REST API communicating with AngularJS in frontend.
-
- The code must be organized into controllers, each controller/endpoint should be a self-contained functionality (i.e. controller for user management (login, signup, .. etc), controller for homeowner dashboard .. etc).
-
- Add proper role authorization validation to access each endpoint.
-
- Logging, validation, and error handling must be properly implemented.
-
- Follow best practices in REST API.
Backend and Pages Requirements
-
- Landing Page
-
- page : #/landing
-
- The four widget’s ‘Create Account’ takes user to Signup page.
-
- Sign in in header takes user to login page.
-
-
- Signup
-
- page: #/signup
-
- If navigation to page came from Homepage then type should be selected based on selection from Homepage.
-
- User can select a type from the page.
-
- Implement validation in frontend and backend as done in the UI prototype.
-
- Backend will create new user record and redirect user to #/thankyou page
-
- Send user welcome email :
-
- nodemailer options should be configurable.
-
- email template should be configurable.
-
-
-
- Login
-
- Page : #/signin
-
- Implement validation as done in UI prototype in both frontend and backend.
-
- User should be able to login using social network accounts.
-
- User passport.js to implement login functionality
-
- For facebook/google :
-
- If user with identifier exists then login the user.
-
- else If user with email exists then create new user_social_account record
-
- else if user with email does not exist redirect user to sign up and pre-fill signup form from data pulled from the social network, on successful registration user and user_social_account should be created
-
- redirect user to proper dashboard based on user type.
-
-
- For twitter
-
- if user with identifier exists then login the user.
-
- else redirect user to sign up form, pre-fill form with data pulled from twitter, on successful registration user and user_social_account should be created
-
- redirect user to proper dashboard based on user type.
-
-
- For failed attempts, lockout after 10 login attempts and log that.
-
-
- Logout
-
- Hovering on top right corner will open a div with logout button.
-
- Implement logout functionality, it will redirect user to landing page.
-
-
- Forgot Password
-
- Page : #/reset
-
- Add proper validation for email as done in the UI prototype in both frontend and backend.
-
- Use nodemailer to send emails.
-
- The templates should be configurable.
-
- The nodemailer options should be configurable.
-
- If user with email exists it should send reset password email.
-
- There should be an expiration date >= 48 hrs for the reset password functionality.
-
- If user with email does not exists then return error and display popup same as done in the UI prototype.
-
- On successful forgot password flow redirect user to a page similar to #/thankyou page with message stating that “Email has been successfully sent, check your email.” and add link to Login page.
-
-
- Reset Password
-
- This page should look like Forgot Password page.
-
- It should contain two input fields to provide a new password and to re-type new password.
-
- Validation for the reset password link and it’s expiry date must be applied here.
-
- On successful execution redirect user to login page.
-
- If link is invalid or expired return user to page similar to #/thankyou with proper message displayed “Reset password is invalid” or “Reset password link has expired”.
-
-
Homeowner Dashboard
-
- Page : #/homeowner
-
- Home Info Tab
-
- Personal Info tab
-
- It will load content from User table
-
- User should be able to update information
-
- Validation for email and password should be applied here, same rules as in signup form.
-
- Create/Update to backend will be applied when clicking “Next”
-
-
- Utility Info tab
-
- Refer to HomeOwner Utility Information section below understand changes to this tab.
-
- The collected info should be created/updated in User on clicking “next”.
-
-
- Primary Home Address tab
-
- Information will be populated/stored from/in house_info#primary.
-
- If there is a primary house address for customer it should be populated.
-
-
- Display “View Analysis” only if existing house analysis status is Completed.
-
- User can change the primary house address
-
- When user change primary address we move the old house to house of interest and we create new house entry and add store it in house_info#primary
-
-
- State/City drop down lists should be loaded from lookup table, so add two GET endpoints to return list of cities and states, there are nodejs modules and api you can reuse here.
-
- Add validation for Zipcode in frontend/backend.
-
- Call to backend to create/update information will be done when clicking “Next”.
-
- The house information will be stored in house_info.primary field.
-
-
-
- House Of Interest Tab
-
- User can provide zero or more house addresses in this tab.
-
- This tab list all house addresses associated with the User from house_info#houses_of_interest field.
-
- “View Analysis” button only displayed for Completed house addresses entries.
-
-
- For new user this page will be empty with only “Add House” button, clicking on the button will add new House form.
-
- Users can add as many Houses as they want.
-
- Houses will be stored in backend when user click on “Update Information”.
-
- The houses will be stored in house_info#houses_of_interest array field.
-
-
-
-
- House Analysis Tab
-
- This tab display house analysis information for selected house address.
-
- Add Financing and Potential Payback of Loan sections in Financier House Analysis Tab to this Tab, we want to user to see financing information and potential payback loan information as well.
-
- On this tab, user will have the option to change the address of what analysis to view by selecting from the dropdown field. This drop down will only display completed house addresses associated with that user.
-
- If selected House analysis is Pending then display a bootstrap alert message with statement “Report is not yet finished, it can take up to 48 hours to complete. You’ll receive an email when it’s done.”
-
- user same message styling as in “House Info” tab.
-
-
- For “Completed” house, render the house_analysis data in the page.
-
- Retrieve house_analysis record of the home address.
-
- Retrieve house_analysis#solar_production array.
-
- Set image from retrieved house_analysis#image field.
-
- The column bar chart should be changed to side-by-side column instead of stacked columns.
-
- The bar chart will calculate utilityapi electricity usage only for primary house if the user of the house has referral_id associated with her account, house of interest we will only render the solar_production array data.
-
- The column bar chart data will be calculated as follow (calculation should be done in server side):
-
- Retrieve the current year house data (12 months) for both utility api and the electricity rate.
-
- Use utilityAPI #/intervals endpoint to get electricity usage, where <uid> is the user#utility_service_uid
-
- We only retrieve two days interval in the demo account provided by utility api, refer to Interval Data Workaround section below to implement a workaround.
-
- Aggregate data by month for the last 12 months
-
- Use utilityAPI bills endpoint to get user bills.
-
- Group bills information by date and get the last 12 months bills and calculate bill_total for each month.
-
-
- Retrieve the current year data (12 months) for both solar production and the seller rate.
-
- Multiply each month by the seller-rate.
-
-
- Return the data in two dimensional array.
-
- The blue column represents the solar data, while the green represents the utility data.
-
- Usage is aggregated monthly utilityapi interval data in green, and the blue is the calculated solar_production data.
-
-
-
- The “Annual Savings” div will be calculated as = total earnings in that year - total bills from utility api in that year.
-
-
- Clicking on “Find vendors and financing for me” will send email for support.
-
- It sends email to configurable email address
-
- Email body will be the following text “<user#firstname> <user#lastname> at <house#address> is interested in adding solar to their roof. Their email address is <user#email_address>. ”
-
- It sends email to homeowner with the following text “Dear <first_name>, We are looking for the best installers and financing sources for you right now and will be in touch shortly with more information and/or question. Best regards, The EnerWise Team”
-
- The sender (contact information) should be included in the email.
-
- Store the request in database, this requires new table.
-
-
- Financing section
-
- The system cost is pulled from database.
-
- Federal tax is configurable value in percentage, set it to 30% for testing.
-
- Lookup State tax from state_tax table where state equals to house address.
-
- Multiply system cost by federal tax and render the value.
-
- Multiple system cost by state tax and render the value.
-
- Estimated cost after incentives will be the system cost subtracted by the calculated federal/state tax values.
-
-
- Potential Payback of Loan section
-
- Above the “Potential Payback of Loan section” there are set of range input fields for two loan scenarios:
-
- System Cost in $ from 0 to 50,000 with initial value set to SYSTEM COST from database.
-
- Yearly interest rate in % from 0 to 10 (add % unit to label)
-
- Loan term in years from 0 to 30 (years unit to label)
-
- Percentage savings applied to loan payments in % from 0 to 100
-
-
- The D3 chart with 2 line graphs, one for loan scenario 1 and one for loan scenario 2
-
- Chart x and y axis :
-
- Y-axis is Remaining Value of the loan
-
- X-Axis is Time from beginning of loan
-
-
- To calculate the graph data :
-
- Variables :
-
- Estimated System cost = SYS
-
- Annual Percentage Rate = APR
-
- Monthly Percentage Rate (MPR) = APR/12
-
- Loan Term = LTR
-
- Monthly Savings from Solar = SAV
-
- % Savings applied to loan = SAL
-
- X = Month from start of Loan
-
- Y = Remaining balance of loan
-
-
- Formula : Y = SYS(1 - X*( MPR + (MPR/((1+MPR)^(LTR*12)-1)) - (SAV * SAL)*X
-
- You are provided with sample document that show you the calculations.
-
-
-
- The table below the D3 chart for the loan scenarios will summarize the loans scenario, it will display the time to payoff the loan and the total of 25 year value of installation.
-
-
- Export to PDF
-
- Should export the same page without header/footer to PDF with same look and feel on a white background.
-
- User open source node module to support this functionality.
-
-
-
-
- Financier Dashboard
-
- Page : #/financier
-
- Your Info Tab
-
- Form will be populated from User model for currently logged in user.
-
- User can update the form with information.
-
- Validation should be done in frontend/backend as in UI prototype.
-
- Validating existing email already exist should be done as well.
-
-
- Customers tab
-
- User will use this page to manage Customers.
-
- The functionality for adding houses is same as the one done in Homeowner dashboard.
-
- The page will manipulate users and will create association between financing user and the customer user by storing it in financier_customer model.
-
- For each customer, the backend will create a user with ‘home_owner’ type, create houses records, and create house_info record for the addresses to be associated with the user, then associate the user with currently logged in financier in financier_customer table.
-
- Show autocomplete list in the customer email, financier can select a user or insert new email. If financier select an existing user we will populate the primary address of that selected user in the primary address field in READONLY mode.
-
- Send email to the customer indicating that “<financier name> want to access your house information, please approve it <here>”.
-
- The email will contain a link that will take user to a page that state to “approve” or “deny” access.
-
-
- If financier added new customer email, then
-
- Send email to customer asking them to provide utility information for their primary house. User will click on link and will be redirected to a page to reset their password, since we already have an account for the user, then user will login and will be taken to the Personal Info Tab to provide utility api information.
-
-
-
- Display ‘view analysis’ button only for ‘complete’ house addresses.
-
- Display “View Analysis” button for primary house ONLY if customer ‘authorized’ it.
-
-
- Implement endpoint to support adding/removing house addresses.
-
- Status columns represent the house analysis status (Pending/Completed)
-
-
- Analysis Tab
-
- This will be same as Homeowner Analysis tab except that we don’t display “Find Vendor and Financier for Home” button.
-
-
-
- Admin Dashboard
-
- Page : #/admin
-
- This page accessed by ‘admin’ user only.
-
- It will list all houses with house analysis status “pending”.
-
- All the fields are manually inserted, take into consideration the comma separator, and the dollar sign ($) for money field.
-
- Proper validation for digits should be added in backend, user don’t need to add the dollar sign for money fields, it should be appended automatically.
-
-
- Implement Upload Image functionality, it will store images to a configurable folder over a network.
-
- User can upload multiple times for same house to replace images.
-
- Upload should be done automatically once user click on “Done”.
-
-
- Clicking “Done” will update house_analysis record in backend with status from “pending” to “completed”.
-
- Validation is needed to verify image is provided, all fields are filled, and data is populated for that house.
-
- On successful storing of data a successful popup will be displayed and record will be removed from the page.
-
-
- Use Amazon S3 to store the image and serve it.
-
HomeOwner Utility Information
We will make the following changes to the HomeOwner Utility Information tab :
-
- Remove existing form fields.
-
- Add new field “Select Utility” drop down field :
-
- Populate it from ‘utilities’ lookup table.
-
-
- Render iframe beneath the Dropdown field on what user select from drop down, you will use the selected Utility#URL to render the iFrame content.
-
- If other is selected then we display Utility Name and store it in otherDetails as json object.
-
-
- The Utility#URL will be UtilityAPI Widget Token URL that is used to authorize UtilityAPI to pull the users information on their behalf. The url is something like this.
-
- Open UtilityAPI.com
-
- Login and navigate to customer portal https://utilityapi.com/form-builder
-
- Update the Settings in that customer portal page to use redirect to url that your application will handle. We are interested in ‘referral’ parameter returned from authorization flow. Store that ‘referral’ in user record.
-
-
- User will fill the form in the iFrame and authorize utilityapi app, then utilityapi.com will redirect by calling the configured redirect to URL in the customer portal.
-
- Implement callback GET endpoint to handle successful callback, we will capture ‘referral’ and associate it with current user.
-
- On successful authorization
-
- Render user account using utilityAPI and render it in page, api call looks like this (this call should be done in server side) https://utilityapi.com/api/accounts.json?access_token=<access-token>&referrals=<referrals>
-
- Then retrieve user services (this is server side call) and display them in drop down list.
-
- Use https://utilityapi.com/api/services.json?access_token=<access-token> and filter the services using the <account_uid> == account#uid from previous call.
-
-
- Display dropdown with list of services, user should select a service in drop down.
-
-
- When user click “Next” we will store the collected information in the backend, and we activate the user service selected by calling https://utilityapi.com/docs#services-modify endpoint by setting active_until to a date in future (i.e. January 2100).
Interval Data Workaround
As we are using demo account to test integration with UtilityAPI.com, it does not return enough interval range information for the demo accounts, it only return 1-2 days interval. And we need 12 days interval to aggregate and calculate past 12 months usage of the house.
You will do the following workaround when retrieving usage information :
-
- All UtilityAPI endpoint URLs should be configurable.
-
- The interval endpoint url should have same format as the one needed by utility api i.e. /services/<uid>/intervals but it will point to local hosting for the interval json file.
-
- You are provided with JSON file that has 12 months intervals.
-
- Implement the /services/<uid>/intervals in your application and return the sample json file as response. so basically the configurable UtiltiyAPI endpoint for interval will be something like http://localhost:8080/services/<uid>/intervals which is an endpoint you are implementing in your app.
-
- In production we will replace the configured URL with the actual UtilityAPI interval URL, and it should work without any problems.
Test Scenarios
Listing here the scenarios that you will test your solution against :
Test Scenario 1
-
- User create a homeowner account.
-
- User provide personal information.
-
- User provide UtilityAPI account information
-
- User set primary address
-
- User set multiple house of interests
-
- Admin logs in and fill the houses solar production information
-
- All houses are marked completed
-
- User next time login can see ‘View Analysis’ button in all houses.
-
- User open “Analysis” tab and view the house analysis, and navigate between completed houses.
Test Scenario 2
-
- User create a homeowner account.
-
- User provide personal information.
-
- User provide UtilityAPI account information
-
- User set primary address
-
- User set Zero house of interests
-
- Admin logs in and fill the houses solar production information
-
- All houses are marked completed
-
- User next time login can see ‘View Analysis’ button in primary house.
-
- User open “Analysis” tab and view the house analysis, and navigate between completed houses.
Test Scenario 3
-
- User create a homeowner account.
-
- User provide personal information.
-
- User DOES NOT provide UtilityAPI account information
-
- User set primary address
-
- User set house of interests
-
- Admin logs in and fill the houses solar production information
-
- All houses are marked completed
-
- User next time login can see ‘View Analysis’ button in all houses.
-
- User open “Analysis” tab and view the house analysis for primary house, the bar chart will only display solar_production information, since user did not provide UtilityAPI information.
Test Scenario 4
-
- User create a financier account.
-
- User provide personal information.
-
- User create customer with non existing email. (customer is a home owner)
-
- User add primary house and house of interests.
-
- Customer receives an email to provide utility api information.
-
- Customer navigate to the website using the link in the email.
-
- Customer gets a reset password page, customer provide a password and get redirected to login page.
-
- Customer login
-
- Customer view Personal Information tab, can update it.
-
- Customer view UtilityAPI Information tab and provide information.
-
- Customer can view and update primary house and house of interests information.
-
- Admin logs in and fill the houses solar production information
-
- All houses are marked completed.
-
- Financier and customer next time login can see ‘View Analysis’ button in all houses.
-
- Financier and customer open “Analysis” tab and view the completed houses information.
Test Scenario 5
-
- User create a financier account.
-
- User provide personal information.
-
- User create customer with non existing email. (customer is a home owner)
-
- User add primary house and house of interests.
-
- Customer receives an email to provide utility api information.
-
- Customer ignores the email.
-
- Admin logs in and fill the houses solar production information
-
- All houses are marked completed.
-
- Financier next time login can see ‘View Analysis’ button in all houses.
-
- Financier open “Analysis” tab and view the completed houses information, the financier can only see the solar_production information of the house since user did not provie UtilityAPI information.
Test Scenario 6
-
- User create a financier account.
-
- User provide personal information.
-
- User create customer with an existing email. (customer is a home owner)
-
- Page will load the associated primary house of the customer as read only.
-
- User creates house of interests.
-
- Customer receives an email to approve financier to access primary house information.
-
- Customer get redirected to website using link in the email to approve/deny access for that financier.
-
- Financier next time login can see ‘View Analysis’ button in primary house if authorized, otherwise, we display “UnAuthorized” or “Pending Authorization” access.
General Notes
-
- The UI prototype is responsive, so your solution must work on responsive views as well, you should not break any UI styling or functionality in responsive views.
-
- Provide a readme file for details about deploying the application, configuring it, and testing locally.
-
- UtilityAPI api access token and widget token URL should be configurable.
Heroku Hosting
The application will be hosted in heroku. You must test your solution in Heroku and provide required scripts and instructions to deploy there.
Documents
Provided in challenge forums :
-
- The UI prototype
-
- Calculation document for the plot chart.
Folder Structure
Root directory
-
- env-sample (this will be a sample of .env file)
-
- app.js
-
- models
-
- views
-
- controllers
-
- public
-
- angularjs
-
- css
-
- js
-
- i
-
-
- .gitignore
-
- config/ folder
-
- READ.md
-
- anything else needed.
Final Submission Guidelines
Deliverables
-
- All source code files and scripts that implement above requirements.
-
- A readme.md file detailing all information needed to setup, configure, and run the app. Use github flavored markup text. It should be part of the git folder submitted
-
- You don't need to submit a word document for deployment guide.
-
- Word document for verification steps.