Challenge Overview
Hot 4 Solar! web application purpose is to helping find potential customers who are most prepared to buy solar panels.
The goal of this challenge is to build the application backend of the application and integrate it with the frontend UI prototype.
Challenge Requirements
You will address the following in this challenge :
Technology Stack
-
- You will use Python, Django, MySQL and JQuery Ajax stack in this challenge.
-
- You are encouraged to use Django REST Framework.
-
- Use open source ORM module for database.
Entity Models
-
- Locations
-
- id
-
- permitId
-
- address
-
- zipcode
-
- long
-
- lat
-
- installationDate
-
- contractorId
-
-
- LocationsData
-
- id
-
- location_id
-
- averageCostPerWatt
-
- projection
-
- hotness
-
-
Contractors
-
- id
-
- name
-
-
AggregatedLocationsData
-
- id
-
- zipcode
-
- averageCostPerWatt
-
- projection
-
- hotness
-
- locations (array of location ids)
-
- averageGrowth
-
- increments (array of key/value, key represents date, and value is +/- integer that represents the installation count happened in given date)
-
Note the following :
-
You can add more models as needed, and suggest changes to the models above.
Backend Functionality
We need the following backend functionality for the Ajax Calls from frontend :
-
- Note that response should be in JSON format.
GET /locations
-
- This endpoint will be used to retrieve installers rendered in the map screen.
-
- This will retrieve locations.
-
- Filtering parameters are optional, we can filter by any field in the locations model.
-
- We need a filtering parameters to allow retrieval of locations within provided lon/lat range passed from frontend, the range will be pulled from google geocode api.
-
- Refer to this SO question to understand how to search long/lat using google geocoding
-
-
- This will retrieve all locations matched the search.
GET /contractors
-
- This endpoint will be used to retrieve contractors popup rendered in the map screen.
-
- This returns list of contractors in database.
-
- We need long/lat range parameters same as in GET /locations endpoint to filter contractors by address.
-
- The response should include the contractor id and name.
GET /locations/statistics
-
- This endpoint will be used to retrieve statics popup rendered in the map screen.
-
- This will get statistics of provided location ids or long/lat range, one of these parameters must present, if neither then return error.
-
- Locations will be passed in query string as comma separated location ids.
-
- Radius parameter (optional) will be passed, we will not need this parameter in backend logic, and we will include it in response.
-
- If long/lat range then we need to retrieve the locations that fall within the long/lat range, we only need the location ids.
-
- Using location ids :
-
- using LocationData of passed in locationIds calculate average of following fields :
-
- hotness
-
- averageCostPerWatt
-
- projection
-
-
- Prediction chart plot data :
-
- Group locations by year using installation date
-
- For each group calculate the average cost/watt from LocationData.
-
- The x-axix will be the years, and left y-axix will be the average cost/watt.
-
-
-
- Response will include following fields :
-
- hotness
-
- averageCostPerWatt
-
- projection
-
- growth
-
- predictionChart (object with array of plots)
-
GET /locations/statistics/aggregate
-
- This endpoint will be used to retrieve statistics list the the list view page.
-
- input parameters are :
-
- long/lat google gecode range same as above endpoints.
-
- offset
-
- limit
-
- sortColumn
-
- sortOrder
-
-
- Using google reverse geocoding, get list of zipcodes in the provided long/lat range, and retrieve all data from AggregatedLocationsData that related to the zipcodes with pagination.
-
- We also need to aggregate summary of the data retrieved to be displayed at top summary section in the page, the aggregation will be calculate these fields (pagination does not apply here):
-
- locations count
-
- average hotness from all locations
-
- average projection from all locations
-
average cost/watt from all locations
-
-
- Note the following about returned data :
-
- Pagination should be enforced in this case.
-
- Pagination parameters :
-
- offset (0 by default) - page number
-
- limit (10 by default) - page size
-
- sortBy (optional) - default to zipcode
-
- sortOrder (optional) - default to ascending
-
-
-
- response fields will be :
-
- pagination information
-
- total
-
- offset
-
- limit
-
- sortBy
-
- sortOrder
-
-
- summary :
-
- installersCount
-
- hotness
-
- projection
-
- cost/watt
-
-
- locationData array, each element will be a LocationData record.
-
GET /locations/statistics/export
-
- This endpoint will be used to perform the export feature the the list view page.
-
- Input parameters :
-
- long/lat google gecode range same as above endpoints.
-
- SortColumn
-
- SortOrder
-
-
- Same logic as /locations/statistics/aggregate endpoint except that we don’t apply pagination to retrieve data.
-
- Export AggregatedLocations to csv file format.
-
- The logic for retrieving data should be same as GET /locations/statics/aggregate endpoint.
-
- Sorting should be applied to exported data as passed.
GET /locations/timeline
-
- This will retrieve locations on provided datetime for timeline feature in this screen.
-
- The input parameters are :
-
- long/lat google gecode range same as above endpoints.
-
- period : week, month, quarter, year
-
-
- Group locations using installation_date as follow depends on the period parameter :
-
- week : group by day
-
- month : group by week
-
- quarter : group by week
-
- year : group by month
-
-
- Return the locations, response structure should be 2d array, the first array level is the grouped period, i.e. week period each item in array represents a day, the second dimension array is the locations long/lat. you don’t need to include any other informations.
Job Scheduler
Create a script that populate AggregatedLocationsData table.
Run by job scheduler out of the box that does the following :
-
- Cleanup existing AggregatedLocationData table.
-
- Aggregate Locations documents by zipcode.
-
- For each Locations group :
-
- Get AggregatedLocationsData of group zipcode if exists to be updated.
-
- Store the location ids in AggregatedLocationsData#locations field.
-
- Calculate Growth
-
- Group locations by installation date and calculate the percentage of increase in number of locations between the current month and the preceding month. It can be positive or negative.
-
- Store the value in AggergatedLocationsData#averageGrowth
-
- It is a percentage value.
-
-
- Calculate the average Cost / Watts for locations and store it in averageCostPerWatt field.
-
- Calculate the average Projection for locations and store it in averageProjection field.
-
- Calculate the average Hotness for locations and store it in averageHotness field.
-
- Calculate Increments in past 30 days
-
- Get latest date in the increments array if exist, if not exist then we calculate the increments for all locations in group.
-
- Group locations by installation date
-
- Put the date and locations count in key/value pair and store it in increments array.
-
-
- Update/Store the information in AggregatedLocations document.
-
Frontend Pages
You are provided with UI prototype in challenge forums, and you will implement the following pages, note the following :
-
- The pages should be django templates.
-
- All interaction within the dashboard page (i.e. switching from map view to list view, playing timeline .. etc. will be via ajax call.
Landing Page
-
- Page : home.html
-
- This page will has static content, and will be mainly for navigation to other pages
Signup Page, My Account Pages and Login Popup
These will be dummy pages in this challenge, you will convert them to python template but no real backend to support them. For login use same way for login and displaying invalid login as in ui prototype.
Dashboard Page
-
- Page : dashboard.html
-
- By default the map view tab is selected, other tabs are inactive.
-
- By default the map will render USA map.
-
- By default Location input field is empty, this field should support auto complete feature using google geocode API.
-
- The flow when user select or enter an address in location input field :
-
- Retrieve the address lon/lat bounds (northeast and southeast) from google geocode api.
-
- Call GET /locations endpoint to retrieve locations
-
- Render the locations as red markers in the map as shown in the UI prototype
-
-
- The map support clustering, this functionality should still exist.
-
- User can select a radius in the map by clicking single click on map then when (+) cursor appears, click and drag to create a circle layer :
-
- Return the lon/lat boundaries of the created layer.
-
- Call GET /locations/statistics endpoint by passing the required input parameter
-
- The response will be rendered in the right side div that appeared
-
-
- Heat map button :
-
- Clicking on the button will create a heatmap for the locations as currently done in the UI prototype.
-
-
- Installers button :
-
- It will display a popup with installers contractor names that represent currently rendered locations on the map, user can filter the locations by unchecking/checking the options.
-
- Clicking on the button will display popup with contractors pulled from GET /contractors endpoint
-
- By default All options are selected.
-
- When user toggle the selected contractor to hide/show locations associated with that contractor.
-
-
- Timeline button :
-
- This will display a timeline player control, it will give user a timeline view of the history of installers in a given period.
-
- Logic and flow:
-
- User already selected/provided a location in location input field.
-
- User click on Timeline button, a call made to GET /locations/timeline with default period. By default it will select per week period,
-
- When user changes the period another call should be made to backend.
-
- Play/stop/pause buttons should be disabled during call to backend.
-
- The timeline play and render locations as shown in UI prototype.
-
- Period dropdown should be disabled while timeline is running.
-
- When timeline finish it should reset the data in map.
-
-
- When
-
is be implemented as shown
-
Call GET /contractors to get list of contractors to fill the Installers popup
-
-
- List View button
-
- This will display a list view of aggregated locations data.
-
- It will be empty if no address is provided.
-
- If address is provided it will make a call to GET /locations/statistics/aggregate endpoint
-
- The page will support pagination/sorting in server side as implemented in the aggregate endpoint.
-
- Export button will call /locations/statistics/export endpoint.
-
Validation
Add proper validation for input parameters :
-
- Input parameter if required should not be empty or null.
-
- Input parameter should be in proper format, i.e. datetime.
Logging
-
- Add proper logging for method entry, method exit at INFO level.
-
- Add proper logging for input parameters, and return parameters at DEBUG level.
-
- Add proper logging for errors in ERROR level.
Test Data
Build a test data script that generate data in table, please make the addresses in San Francisco city.
Hosting
It is preferred if you provide scripts and steps to deploy the application on Heroku.
Documentation
Provide a detailed README documentation for how to setup and configure the application.
Configurations
You are expected to use environment variables to store sensitive information and environment-specific configurations.
Abstracting and Design Patterns
Please make sure to create helper/interface to include the common code/functionality.
Also please make sure your design is flexible, use facade design pattern and adapter design pattern (and any other proper design pattern) to enable future extensibility of the solution.
Coding Standard
Follow python coding best practices : PEP 8 for the main text, and PEP 257 for docstring conventions
Technology
-
- Python version 3.x running on Ubuntu
-
- MySQL Latest stable version.
-
- Django 1.8.x
-
- AngularJS
-
- Bootstrap
Final Submission Guidelines
Deliverable
-
- All source code that implement the requirement.
-
- README in markup language
-
- Verification document contains steps to verify your solution.
-
- Test data generator script.