15 Parts of How I Built Food Delivery App, Lessons & Ideas through Laravel and Vue
Tags: laravel, vue, architecture, design
Published: 2020-10-07 18:09:43

note: currently, website is down, I'll fix it soon


## **Introduction**



There are a lot of apps made for food delivery for big cities, but not a lot of them are made for the **small** cities.

The article covers how the app is made, its structure, common problems, and **solutions**.

Why article might be important to you?

Do you plan to make a delivery app, or you want to buy one, or are you interested in starting a delivery app?

Or you want to see how a problem can be solved using the web?

Then, this content is for you.

*“Make sure you understand the fundamental principles, i.e., the trunk and big branches, before you get into the leaves/details, or there is nothing for them to hang on to.”*  - Elon Musk

[Here](https://dostava-online.com) is the app. Take a look.

There is a big chance that the app data will be populated by random users because access to almost every account is open to the public. **Please** don't populate the application with unrelated stuff. If you cannot log in, try to make a new account.

------

Link: *https://dostava-online.com*

**User** credentials:

- Phone number: +387 99/999-999

- Email: johndoe@gmail.com

- Password: 123123123

------

Link: *https://dostava-online.com/restaurant*

**Restaurant** credentials:

- 1
  - Phone number: +387 22/222-222
  - Email: ristus@gmail.com
  - Password: 123123123

- 2
  - Phone number: +387 33/333-333
  - Email: star@gmail.com
  - Password: 123123123

------

Link: *https://dostava-online.com/admin*

**Admin** credentials:

- Phone number: +387 11/111-111

- Email: dostava.online@gmail.com

- Password: 123123123

------



## **Overview**



- on the main page are shown:
  - top 3 foods, according to the selling/ratings
  - all restaurants sorted according to the sales/ratings/sponsorship/availability
- cart for users
- additions for foods, *free* and *paid* additions
- multiple user addresses
- delivery/pick up as soon as possible or at the desired time
- delivery/pick up food
- 6 types of notifications for users; order is:
  - accepted
  - not accepted
  - in the making
  - in delivery
  - delivered
  - you can come to pick up the food
- ingredients of each dish
- one click for the switch of the food availability on the restaurant side
- complete CRUD of foods for restaurant
- food categories
- admin dashboard for sales overview, confirmations, sponsorships

-----

## **Technical overview**



- Laravel 6, Vue 2.0, Vuex, Vuetify, Socket.io (Laravel-echo), Node, Redis, MySQL, OAuth 2.0
- Webpush notifications implemented for users and restaurants
- Slack notifications for admins
- Multiauth
- Caching of the majority of cachable resources - on back end and front end
- Backup 3-5 times/week
- Image watermarks
- No Laravel mix; advanced webpack configuration
- Full tested; ~800 tests (features and unit tests)
- Fully extendable and testable structure for algorithms for sorting the top 3 foods on the back end
- user/restaurant/admin SPAs separated
- HTTP 2.0 for lazy loading Vue components; production raw ~400 files
- Fully separated API and front end
- Custom artisan commands for production testing
- Easily extendable for multiple cities
- Easily connectable to the mobile app (separate API made with that in mind)
- Mobile-first design

-----

## **Database plan**



Number of tables: **46**

-----

- **Problem**: cart items should be seen from all the devices, so saving items in the cookies memory or browser database is not going to help because the user is going to check the cart from the various devices

- **Solution**: complete cart concept is on the back end

  ------

- **Problem**: a history of the transactions

- **Solution**: same tables of the cart solution prefixed with *finished*

  -----

- **Problem**: Multiple user addresses (so the user can type in address once and access it anytime with ease)

- **Solution**: *home_address* on main **user** table, and *user_address* table; one-to-many relationship

  -----

- **Problem**: cart also should contain paid and free additions

- **Solution**: *shopping_cart*, *shopping_item*, *shopping_item_free_addition*, *shopping_item_paid_addition*; **one-to-many** relationships

  ------

- **Problem**: duplication of free/paid additions and ingredients

- **Solution**: free/paid additions and ingredients **link** tables

  ------

- **Problem**: some restaurants don't work on the weekends, but all of them work on weekdays on regular

- **Solution**: separate table for weekends with **one-to-one** relationship

  ------

- **Problem**: different delivery prices for the different locations

- **Solution**: *default_delivery_price* on *restaurant* table and *delivery* table; **one-to-many** relationship

  ------

- **Problem**: monthly restaurant fees

- **Solution**: Laravel scheduler empowered with cron

  ------

- **Problem**: food categories

- **Solution**: separate table, **one-to-many** relationship

  ------

There are also [Telescope](https://laravel.com/docs/8.x/telescope) tables, OAuth tables, notifications, failed_jobs, migrations, three types of users (user, restaurant, admin)...

-----

## **Order process**



- Put items with/without free/paid additions in the cart from the main page/restaurant page
- Go to the cart page
- Choose if you are coming for the food or desired address for delivery 
- Choose if delivery/pick up is as soon as possible or at the desired time

After the successful order, the restaurant can either accept or decline the order.

If the 10 minutes pass and the restaurant still didn't accept or decline the order, the user can decline the order.

Declining from the restaurant can happen for various reasons, such as the restaurant forgetting to set unavailability to the dish.

-----

## **Order process visualisation**



Order process diagram, user side:

![userDiagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tznw7gn0f624epa3i7ap.png)

Order process diagram, restaurant side:

![restaurantDiagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1lnhakssni9dhau6qeuh.png)

-----

## **History overview**



The history problem is easily solved. After the order is finished, the job is added to the Laravel queue, so its **non-blocking**.
What job will do is a transfer from the active carts to the finished carts, everything has *finished* table - cart, items and free/paid additions.

The problem that arises is changing the price of the additions/food in finished orders because *finished* items/additions are linked to the current info. The solution is to make a serialized snapshot of relevant data at a time. Not implemented in this system yet.

-----

## **Queues**



There are **6** queues required for the application to run correctly (250-350 MB of RAM).

All of them are powered through Redis. 

- general queue
- queue for restaurant notifications
- queue for user notifications
- queue for admin notifications
- queue for processing images

The general queue is at the frontier for the most other queues and for the non-critical data.
Because this application is heavily notification dependent, there are 3 separate queues for the notifications, of which restaurant queue has high priority.

-----

## **Cron jobs overview**



In the background of this application, **6** processes are running alternately.

- monthly fee event (calculate restaurants debts)
- hourly check which sponsorship is expired
- hourly remove old inactive shopping carts
- daily clean old backups
- daily backup database
- weekly backup files

-----

## **Security**



Laravel framework is trying to be as secure as possible.

Every user input is checked **both** on the client and server-side.

Backup is done daily.

Many barriers to preventing DOS attacks, from the application side and at the OS.

-----

## **Validations and notifications**



Every form is done with a **heavy** focus on the details.

From the typing incorrect answers to the correct and recommended.

Notifications are done via web-push notifications and in-application notifications. In-application notifications are done using a basic Laravel package that does (almost) a great job.



## **Data duplication in the database**



A lot of the food has the same ingredients, so having a lot of ingredients duplicates does not make **any** sense.
The same situation is with the paid and free additions.

The solution is to make *link* tables. So, e.g. multiple dishes can link to the same ingredient, without duplication.

-----

## **Deactivation**



Food, paid/free addition, user, restaurant, admin tables are all soft-deleted, which means that the data will remain in the database, just it won't be shown anywhere like it was deleted. Data **remains** for analytics, marketing purposes...

-----

## **Business model**



The business model at its core is the same as the [Grubhub](https://www.grubhub.com/) model. 10% of the order price. A business model based on the **value**, the best type of business model (subjective).

App profits could be extended by bringing in delivery extension, so the independent delivery man/woman can work and make some cash.

------

## **Story**



The web application is made for the small cities and the places around the city. Most of the big food delivery companies include the only city and that is the place where this application **differs** from the others.

The application is a nice startup for the focus on the first city. The structure is easily **extendible** for multiple cities.

The application was translated from Bosnian into English in a rush. There are some English mistakes.

This is also my second big project, which I did for the 6 months and 21 days, with only 3 days rest. #hustleCulture 🤣

What I **learned**: 

- Laravel - in and out

- Vue - a lot of it (community, thank you for this gift)

- Webpack - headache is the correct translation

- MVC - the structure of in-development independent separate parts (if I have to describe it using my words)

- SCSS - nice addition to the basic CSS

- **Real** problem of software development: maintaining the same speed of development in a big, robust system where it's so easy to lose the pace; so the only way to go is quality, clean code, implementing defined principles

- Redis - fascinating pub-sub; fascinating speed; and the hard thing, not coupled to the Redis strictly, but often related to it - cache invalidation... Nice place to look for logical creativity.

- Simple is **better**

- Better spend more time at the **planning** the database structure than to support bad design weeks/months later

- ORM is the nice, fast way to go (didn't have touch with the systems where performance is the real issue, but I assume then the ORM is not the best option)

- Ubuntu is easy, understanding the **permission** system in the multi-user operating system is one of the key concepts to the security (next stage for me is cloud). The scaling problem for the VPS-based solutions is easy to notice, so the huge arise in the cloud makes sense.

- Using packages is a **messy** thing

- GraphQL is a way to go in the **big** APIs, REST will waste so much because of its inflexibility

- Developing **detailed** front end schemes before even deciding which technologies to use on the back end is the way to prevent a lot of the regrets

- Writing important code without testing is a **crime**

- PHP is **nice** and evolving, but at the enterprise always Java/C# is gonna be used

- Most of the deaths on this planet in the last 25 years are caused by **Javascript**. And that's a fact 😂

  

Thank you for reading. ☄️