Zernike Facilities is in the process of building a new parkinglot - P7. P7 will be ticketless and will keep track of which parking places are available/occupied. This inspired management to order the creation of a new parking app and to upgrade the old parking lots to the new system. As a future engineer you receive the order to develop the new system that will manage the parking lots.
ParkingLottable:lot_idcolumn- data type: BINARY(16), storing an UUID, SMALLINT is also possible;
- description: Primary key, to store an unique identifier for each parking lot;
namecolumn- data type: VARCHAR(15), variable-length string with limit of 15 characters;
- description: to store the name of the parking lot (e.g. "Zernike P7");
locationcolumn- data type: VARCHAR(50), variable-length string with limit of 50 characters;
- description: to store information about the location of the lot;
capacity_allcolumn- data type: SMALLINT UNSIGNED, max. 65535;
- description: to store the number of all parking spaces (charing + non-charging) at the parking lot;
capacity_electriccolumn- data type: SMALLINT UNSIGNED, max. 65535;
- description: to store the number of charging parking spaces at the parking lot;
ParkingSpacetable:space_idcolumn- data type: SMALLINT UNSIGNED, max. 65535;
- description: Primary key, to store an unique identifier for each parking space/spot;
lot_idcolumn- data type: BINARY(16), storing an UUID;
- description: Foreign key, referring to an instance of the "parent" table, specifying to which parking lot does this space belong to;
space_typecolumn- data type: VARCHAR(15), variable-length string with limit of 15 characters;
- description: to store information about the type of the parking space (charing/non-chargin);
sensor_idcolumn- data type: SMALLINT UNSIGNED, max. 65535;
- description: if sensor is present, to uniquely identify which one is attached to the parking space;
is_occupiedcolumn- data type: BIT, either 0 or 1;
- description: Binary number (0 or 1) to represent the current state (either free or occupied) of the parking space;
hourly_tariffcolumn- data type: DECIMAL(3,2), efficient way to store numbers representing monetary value;
- description: to specify the parking fee of the space per hour;
CarRecordtable: (a record stores infomation about a single visit of a car to the parking lot, i.e. history)record_idcolumn- data type: BINARY(16), storing an UUID, INT or BIGINT is also possible;
- description: Primary key, to store an unique indentifier for each record;
license_platecolumn- data type: VARCHAR(10), variable-length string with limit of 10 characters. License plates are usually not longer than 10 characters;
- description: Foreign key, referring to an instance of the Car table, specifying to which car does this record belong to;
space_idcolumn- data type: SMALLINT UNSIGNED, max. 65535;
- description: Foreign key, referring to an instance of the ParkingSpace table, specifying based on which parking space was this record created (i.e. where was the car parked during this visit/record);
check_incolumn- data type: DATETIME;
- description: to store information about the check-in time of the car;
check_outcolumn- data type: DATETIME;
- description: to store information about the check-out time of the car;
is_paidcolumn- data type: BIT, either 0 or 1;
- description: Binary number (0/1) to specify if the parking visit is paid or not.
Cartable:license_platecolumn- data type: VARCHAR(10), variable-length string with limit of 10 characters. License plates are usually not longer than 10 characters;
- description: Primary key, to store the license plate information of the car which uniquely identifies it;
owner_idcolumn- data type: BINARY(16), UUIDs address security concerns and prevent guessing of the owner id;
- description: Foreign key, referring to an instance of the CarOwner table, specifying to which owner does this car belong to;
brand_namecolumn- data type: VARCHAR(20), variable-length string with limit of 20 characters;
- description: to store information about the brand of the car;
fuel_typecolumn- data type: VARCHAR(10), variable-length string with limit of 10 characters;
- description: to store information about the fuel type of the car;
CarOwnertable;owner_idcolumn- data type: BINARY(16), UUIDs address security concerns and prevent guessing of the owner id;
- description: Primary key, to store an unique identifier for each owner;
customer_typecolumn- data type: VARCHAR(10), variable-length string with limit of 10 characters (Student/Hanze/RUG);
- description: to store infomation about the relation the owner has to the parking lot, e.g. working at Hanze UAS or RUG, or beign a student;
student_employee_codecolumn- data type: CHAR(10), constant-length string with limit of 10 characters, university codes are usually standard and have constant length;
- description: if available, to store information about the unique code related to the universities;
discount_ratecolumn- data type: DECIMAL(4,2), efficient way to store numbers representing percentage value;
- description: to store information about the discount the owner receives for his parking records;
first_namecolumn- data type: VARCHAR(20), variable-length string with limit of 20 characters;
- description: to store information about the first name of the owner;
surnamecolumn- data type: VARCHAR(20), variable-length string with limit of 20 characters;
- description: to store information about the surname of the owner;
tel_numbercolumn- data type: CHAR(10), constant-length string with limit of 10 characters, telephone numbers are usually standard and have constant length;
- description: to store the telephone number of the owner;
emailcolumn- data type: VARCHAR(30), variable-length string with limit of 30 characters;
- description: to store the email of the owner;
passwordcolumn- data type: CHAR(82), constant-length string with limit of 82 characters, hashing algorithms produces large strings which are difficult to reverse;
- description: to store a hashed version of the password of the owner, used for login and verification with the app;
payment_methodcolumn- data type: VARCHAR(15), variable-length string with limit of 15 characters (manual/direct debit);
- description: to store information about the method the owner prefers to pay out his parking cost (via manual payments or direct debit);
Users- can login or register and receive information through the Zernike Parking app, thus require SELECT, INSERT, UPDATE privileges (parking_system_read + parking_system_write ROLEs)Billboard- should request and receive information about the parking spaces, thus requires SELECT privileges (parking_system_read ROLE)Ticket booth- can register visitors and request an overview of the available spaces, thus requires SELECT, INSERT, UPDATE privileges (parking_system_read + parking_system_write ROLEs)Cameras- require INSERT, UPDATE privileges to store information about the license plate and the parking spaces of the cars (parking_system_write ROLE)Sensors- require UPDATE privileges to store information about the parking spaces, whether they are free or occupied (parking_system_write ROLE)Finance app- should request past information about the overall state of the lot, thus requires SELECT privileges (parking_system_read ROLE)Maintenance app- should have access to all and thus require complete admin privileges
The application will use a MySQL database.
Note: I will be using the MySQL connector/Python as my database API wrapper.
mysql-connectoris an all-in python module supported by MySQL.
Pipenv is a tool that creates a virtualenv and manages the project dependencies.
The application will be based on the micro web framework - Flask.
A Blueprint is a way to organize a group of related views and other code. A "view" function is the code you write to respond to requests to your application. Flask uses patterns to match the incoming request URL to the view that should handle it. The view returns data that Flask turns into an outgoing response. Rather than registering views and other code directly with an application, they are collected and registered together with a blueprint. Then the blueprint is registered with the application when it is available in the factory function.
Templates are files, usually html, that contain static data as well as placeholders for dynamic data. A template is rendered with specific data to produce a final document. Flask uses the Jinja template library to render templates.
Responses will have the form: (Enveloped)
{
"data": "Mixed type holding the content of the response",
"meesage": "Description of what happened"
}Subsequent response definitions will only detail the expected value of the data field.
Definition
POST /auth/register
Arguments
"email":stringan unique email address of the customer"password":stringa password of minimum length 8 characters"customer_type":stringthe type of customer (working at RUG/Hanze)"student_employee_code":stringthe student/employee unquie university code"first_name":stringthe first name of the customer"surname":stringthe surname name of the customer"tel_number":stringthe phone number of the customer"payment_method":stringthe preferred payment method for the customer
"owner_id":uuidis generated and stored in addition
Response
201 Createdon success
Definition
POST /auth/login
Arguments
"email":string"password":string
Response
204 No Contenton success
"owner_id":uuidis stored in cookies of the session
Definition
POST /api/v1/users/register-car
Arguments
"license_plate":stringlicense plate of the car"brand_name":stringbrand of the car"fuel_type":stringfuel type of the car
"owner_id":uuidis read from the cookies
Response
201 Createdon success
{
"license_plate": "AAABB123",
"brand_name": "Volvo",
"fuel_type": "Gasoline",
"owner_id": "123e4567-e89b-12d3-a456-426614174000"
}Definition
GET /api/v1/users/invoice
Arguments
"month":stringthe month, specifying the invoice
"owner_id":uuidis read from the cookies
If there is no active session, the user is redirected to login
Response
500 Internal Server Erroron failure200 OKon success
Containing a list of car records with parking time and total cost
{
"0": {
"license_plate": "AAABB123",
"check_in": "2020-05-12 10:00:00",
"check_out": "2020-05-13 10:30:00",
"total_time": "24.50",
"parking_cost": "29.40"
},
"1": {
"license_plate": "AAABB123",
"check_in": "2020-05-19 10:00:00",
"check_out": "2020-05-19 11:00:00",
"total_time": "1.00",
"parking_cost": "1.20"
}
}Definition
GET /api/v1/billboard/info?is-occupied=
Arguments
"is-occupied":booleanrequest either free (=0) or occupied (=1) spaces
Response
500 Internal Server Erroron failure200 OKon success
{
"0": {
"name": "Zernike P7",
"non_charging": 45,
"charging": 10,
},
"1": {
"name": "Zernike P6",
"non_charging": 10,
"charging": 25,
}
}Definition
GET /api/v1/maintenance/list-cars?with-owner=
Arguments
"with-owner":booleanrequest data with owner information (with-owner=1), default=0
Response
500 Internal Server Erroron failure200 OKon success
{
"0": {
"license_plate": "AAABB123",
"brand_name": "Volvo",
"fuel_type": "Diesel",
},
"1": {
"license_plate": "AAABB124",
"brand_name": "BMW",
"fuel_type": "Gasoline",
}
}or if with-owner=1
{
"0": {
"license_plate": "AAABB123",
"brand_name": "Volvo",
"first_name": "First",
"surname": "Surname",
"space_id": "46",
"discount_rate": "10",
},
"1": {
"license_plate": "AAABB124",
"brand_name": "BMW",
"first_name": "Firstname",
"surname": "Surname",
"space_id": "32",
"discount_rate": "20",
}
}Checking if the amount of checked-in cars corresponds to the amount of cars detected by the sensors
Definition
GET /api/v1/maintenance/sensor-alert
Response
500 Internal Server Erroron failure200 OKon success
{
"detected": "20",
"checked_in": "19",
"alert": "true",
}Definition
GET /api/v1/maintenance/overview-cars?group-by=
Arguments
"group-by": stringrequest data grouped by eitherhour, day, month or year
Response
500 Internal Server Erroron failure200 OKon success
if group-by=hour
{
"0": {
"year": "2020",
"month": "5",
"day": "19",
"hour": "12",
"n_cars": "10",
},
}or if group-by=day
{
"0": {
"year": "2020",
"month": "5",
"day": "19",
"n_cars": "50",
},
}or if group-by=month
{
"0": {
"year": "2020",
"month": "5",
"n_cars": "1000",
},
}or if group-by=year
{
"0": {
"year": "2020",
"n_cars": "10000",
},
}Definition
GET /api/v1/finance/list-cars?start-date=&end-date=
Arguments
"start-date": stringstarting date filter, must be in format%Y-%m-%d %H:%M:%S"end-date": stringending date filter, must be in format%Y-%m-%d %H:%M:%S
If no arguments are given, the request will be redirected to respond with list of currently parked cars
Response
500 Internal Server Erroron failure200 OKon success
{
"0": {
"owner_id": "123e4567-e89b-12d3-a456-426614174000",
"license_plate": "AAABB123",
"brand_name": "Volvo",
"fuel_type": "Gasoline"
}
}Definition
GET /api/v1/finance/invoices/<email>/<month>
Arguments
"email": string"month": string
Response
500 Internal Server Erroron failure200 OKon success
{
"0": {
"license_plate": "AAABB123",
"check_in": "2020-05-19 10:00:00",
"check_out": "2020-05-19 11:00:00",
"total_time": "1.00",
"parking_cost": "1.20",
"is_paid": "0",
}
}Definition
GET /api/v1/finance/invoices/all
Response
500 Internal Server Erroron failure200 OKon success
{
"owner_id": {
"January":{
"0":{
"owner_id": "123e4567-e89b-12d3-a456-426614174000",
"license_plate": "AAABB123",
"space_id": "46",
"check_in": "2020-05-19 10:00:00",
"check_out": "2020-05-19 11:00:00",
"total_time": "1.00",
"parking_cost": "1.20",
"is_paid": "0",
}
}
}
}Definition
GET /api/v1/finance/unpaid
Response
500 Internal Server Erroron failure200 OKon success
{
"0": {
"record_id": "123e4567-e89b-12d3-a456-426614174000",
"license_plate": "AAABB123",
"space_id": "46",
"check_in": "2020-05-19 10:00:00",
"check_out": "2020-05-19 11:00:00",
"total_time": "1.00",
"parking_cost": "1.20",
"is_paid": "0",
}
}