Product Architecture Planning #5
Replies: 19 comments 86 replies
-
I'm going to paste some of the private discussions and comms I get here below so that I can use it while doing the new planning. I like using the word resources instead of groups! See below. This is from Fernando who is on the FilledStacks team. TLDR;
I saw the last episode of boxtout, excellent! Is a great project, I will try to help when I have some space on my free personal time. Only some suggestions that you could take or not. In the section How will we manage functions as a service of the technical planning and overview, for what you call as groups, I think will be better to take the REST api conventions and call them resources. And, to continue with this convention, the name of the resources on the endpoint should be plural noun on all of them, to have some consistency. Order resource example:
I hope this helps, it is to contribute with my grain of sand 😁 |
Beta Was this translation helpful? Give feedback.
-
This is from Rodrigo over on LinkedIn. Great suggestion around using Express to keep 1 endpoint facing publicly with the redirecting happening internally. Hi Dane, I've been following the Box't Out project you are developing and wanted to share some thoughts with you if that is ok. I saw you wanted to use cloud functions to contain each manager (or service), which makes perfect sense. That made me think that you will probably want to call those managers from within another manager to fetch some data or do some calculation. Let's say you want to create a new user. You might hit the Users Manager service endpoint to achieve that; however, let's say you also need to create a Payments Manager customer. That would mean you need to make separate calls from the client-side or make another HTTP request from the User Manager cloud functions itself. After thinking about that, Express came to mind. What if instead, you have one cloud function that contains all your microservices. Using express you would be able to expose all your endpoints like before, but, you would also be able to call different managers within a manager itself, which leaves the client with a very simple endpoint to hit whenever it needs something. Using express also allows you to take advantage of a lot of middleware that can make our lives easier. For example, logging and even authentication. I've attached a simple diagram better illustrating what I'm talking about. Let me know what you think! |
Beta Was this translation helpful? Give feedback.
-
Maintaining carts: RemoteLets tackle number 1: User adds product to their cart The first and most straight forward idea that I can think of when it comes to the users cart will work as follows. When a user is created we generate a cartId that is attached to their profile. At the same time we create a document in the This makes it so that adding to cart is quite simple in terms of a logic stand point. We can add directly from the app into the firestore DB for the users cart. We can either add is as subcollection or we can add it as an array of items on the document itself. To keep things simple I think the best thing to do would be to add it on the document as an array. This will allow you to always get all the information back in one single call. Total cart cost The obvious way to keep the total cost in sync is to update the price, from the current, based on the action being performed by the user. This includes tax (which will be added to the users profile, depending on how their regions tax works). When a user adds to cart we will make the update call to add the product into the product list on the cart as well as update the price to add the new total to the current total. This functionality exists in the Firestore package to perform atomic updates to values on firestore so we'll use that. So we'll do an update for the total which we will then read from the DB again and set as the new cart locally. This should keep the total and the entire cart in sync locally. I hope Maintaining carts: LocalI wanted to play around with the idea of a local cart on the device. This will reduce the number of updates in the firestore DB and also will allow us to keep the cart local until checkout meaning we don't have to track it on the backend. I've never done it this way and I prefer tracking everything on the backend. Doing it this way means that if we build a web client they will have to replicate the cart functionality for the application locally as well. So we'll use something like hive to build the cart up locally, this will allow us to keep track of the products in the cart as well as the totals for it. the good thing about this is that there's less writes and reads from the DB. This appears upfront to be easier than keeping it on the backend and syncing it up. So I'm leaning towards this option. Lets see where the rest of the steps take us. Please leave replies in the thread for this message on this discussion if you have any thoughts on any of this. |
Beta Was this translation helpful? Give feedback.
-
Adding a Payment MethodThis is point number 3. I realise that number 2 isn't actually a step in code but more of a feeling haha. Before a user can checkout they need to have a payment method that the money can be deducted from. We'll need to find a payment provide when the time comes to make use of. PayPal v2 api and stripe is not available in South Africa so I'll probably as someone in the team or that I work with to create a stripe account for me that we can use. So that will be left to later. The one thing that we can tackle is how the payment method will be stored and where that will be. When adding a payment method from the app we'll add that into the payment processor we'll be using and request the token associated with that payment. We'll put that payment token onto the users account as preffered payment method as well as into a collection of payment methods on the users account. This will be so that we can keep track of multiple payment methods for the user. |
Beta Was this translation helpful? Give feedback.
-
Checkout processOkay here we go, this is quite a big one. The checkout process, this covers step 4 in the steps laid out in the discussion original post. Lets start out with the way that we want to use this in the code. I want to call a single api call on the backend for
Using the steps above we can populate an cart from the users device onto the restaurant app. This is a big step to get over. This allows us to then also track on the device the orders status as well as receive updates for it. See below the proposed response format for api resposes in our resources. Response FormatWe should have a consistent response format that all api requests can serialise to. This will make it so that it's easy to determine if there's an error and get the error information as well. No error {
"data": {
"orderId": 12345
},
"error": null,
} With error {
"data": null,
"error": {
"message": "The payment method used does not have enough funds"
}
} |
Beta Was this translation helpful? Give feedback.
-
Restaurant AppSteps 5-9 all happens from the restaurant app and driver app. The customer mobile app will already be reachable through direct notifications using the latest device token as updated on the start of every launch. In addition to that the client application will be listening to the order in real time that's being viewed. This leaves us only the restaurant app and services involved to detail for these 3 steps. Order updatesWhen the order shows up in the restaurant list through the real-time query stream the user can tap on it and then mark it as preparing and send a time in minutes. When this is done there will be a cloud function listening to updates on orders (mentioned already in the above post) that will check the latest status, and send out the appropriate push notification. We might have to maintain two collections of orders, one with the full orders, and one with a simple orders list that can listened too in the listing views so that we don't read all that information. But we'll look at that later on Once the status is updated to Preparing and we have a time we let the user know their status has been updated. When the order is ready we go through the same process as above. The restaurant app updates the order on firestore, the cloud function sends out the push notification and gets the drivers involved. Once the order reaches a certain status (ready for pickup) we send it out to the closest drivers (at the beginning, just all the drivers in the area) and the one who accepts the order first will be assigned to it. They then get the order with the delivery address and pick up address and do the rest. The driver app will also be allowed to update the status of the order. They need to mark it as picked up as well as delivered and be able to accept a tip (which we'll plan later). And that's basically it. Next up we'll go over the technical insights discovered through this process. |
Beta Was this translation helpful? Give feedback.
-
Technical InsightsSo what did we learn from doing this? Well the first thing is that we'll have different types of cloud functions which we can categorise and locate accordingly in the source code. We have:
In addition to that we have uncovered a few of the concepts that we'll need to details out now to get this architecture to work properly. We'll go from the top down and see what we'll require in terms of the modelling of the data to be able to achieve what we want. Data models and collection structureLets start with the most basic things. Everything on the restaurant side.
Those are the models that we'll require from the restaurant side. Next up lest look at the models that will be required from the user side.
That's the only major model I can identify at this point. Of course the models used to represent things like the Address, PaymentMethod and AccountDetails will be models as well but those aren't important in carrying over the data from the client to the restaurant and back. Those can be stored as strings if we're lazy (which we are not). But that's how I determine if they're worth mentioning in this document. Next up is the meat of the process. All the models involved in connecting the consumer to the producer.
That's all the major models required that we can identify based on the most important process in the entire product. Getting what the user ordered to them in a manner that keeps every party involved up to date with what's happening. These are not "The complete models" we will be adding and taking away properties as we develop but this does give us an idea of what we have and will need going forward. This now makes it so that we have 2 of the initial requirements for this document complete.
Next up we have to go over the collections that will be required on firestore to allow us to move data how we described above. That's up next. |
Beta Was this translation helpful? Give feedback.
-
Firestore CollectionsIn this section we go over the collections we'll require to get the information from the client through the system and back to the client. We can follow the same path as what we did with the models above. We'll look at the collections the restaurants will need.
The structure above will allow use to apply well defined security rules from the highest level down and also allow us to easily find products / options for specific restaurants with their specific menu's. Next up is the user:
The we can move onto the collection required for these two to communicate with each other and make their exchange.
That will cover all the collections for this process. With these collections we have sufficient points of interception in case we want to add additional functionality / functions to do more. It covers our scenario and if we can get away with only these collections we'll have a very lean system on our hands to maintain. Which is great for the long run. With this we have covered
And I made a mistake above. We actually covered the last point which is Establish the usage of the cloud functions and their intentions in the part above this. The first portion under Technical Insights. Which concludes my rough planning. I hope this is insightful. I will use all the posts form this discussion and create a well formatted document that has everything in it which we will discuss in the next video coming out next week. |
Beta Was this translation helpful? Give feedback.
-
Hi, Dane and the Filled Stacks Community. Firstly, I think this is a fantastic initiative. I'd like to discuss the reasoning behind choosing the Firebase suite of products as well as the purpose of cloud functions. To begin, in your video you mentioned that Firebase was chosen due to this being a small team project. Firebase certainly offers an 'out of the box' infrastructure requiring very little to no setup cost. However, surely this comes with the downside of less configurability and lower performance when compared with the ''traditional' way of doing things: a REST API with an underlying SQL database? To give you an example, say that an end-user is attempting to search for a restaurant based on their name. Ideally, the logic for this should be server-side. Thus, using SQL this would be a simple 'like' query. Whereas in Firebase, as I understand it, the logic for this function needs to be client-side or you have to look at a third-party solution such as Algolia. For reference, refer to these docs: https://firebase.google.com/docs/firestore/solutions/search. Consequently, how you do balance the trade-off between the lack of functionality of Firebase versus going with an infrastructure that requires longer to set up? On a different note, what purpose will the cloud functions serve? Will the cloud functions handle all database querying so as to abstract the underlying Firestore storage? Or will the cloud functions only handle queries that the Firestore engine is not capable of: such as the search query mentioned above. The reason for this question is because in a 'traditional architecture set up' with a server and SQL database - the client interface would not access the SQL database directly. Rather, the database would be abstracted through an API. However, Firebase offers Firestore security rules, which enables the client to access the Firestore database securely. |
Beta Was this translation helpful? Give feedback.
-
Real-time delivery updatesI think for a service such as this, having the ability to track the progress of an order/delivery is fundamental. Customer-sideThe customer wants to track their food as soon as that order becomes "active". We can define active as whatever we want, but a good start is when the order has been confirmed by the restaurant. I believe you guys already mentioned push notifications as a means to notify customers of delivery milestones (i.e. picked up food at a restaurant); however, enabling the customer to open up their app and see in real-time where their food is, complemented by push notifications, would bring a lot of value to the user. Restaurant-sideI think the same concept applies here. It is important for the restaurant to know where the delivery driver is when an order has already been assigned to that delivery driver. This would give the restaurants more transparency on the delivery cycle and enable them to contact the customer in case something goes wrong for example. How to implement this?Real-time data is fairly easily achieved with Firebase, for that reason, I don't think it would be too much of a pain to implement this. However, one thing we need to take into consideration is how we are going to listen to the delivery driver's location. There are multiple ways we could achieve that, but we should keep battery life, data costs, read/writes frequency in mind. Approach 1: Listen to device location at all times (expensive, but very accurate position data)Approach 2: Listen to significant device location changes (cheap, but not very accurate)Approach 3: ?GeofencingAnother feature I thought this service could benefit from is Geofencing. Instead of depending on the delivery driver to press "Here" or "Picked up food" buttons to update delivery status, we could use geofence events to automatically trigger whatever functionality we want (including sending push notifications to the end-user), and also prevent drivers from saying they've arrived when in fact they haven't for example. How?We can use the device's geofence API to setup geofence regions along the world and listen to entry/exit events of those regions. This is a native feature, but there are many packages available that can be used to achieve this. Example:
|
Beta Was this translation helpful? Give feedback.
-
Delivery ETADue to the nature of this service means that we need to be very fast at delivering the food. However, that is not always possible. Maybe there is not a close driver around the restaurant in question, or the restaurant is understaffed at that particular time. These things happen and are inevitable. However, one thing we can do is to provide the customer with real-time updates as I mentioned above, and the most accurate delivery ETA possible. These features all serve the purpose to minimize customers' anxiety. Calculate distance?One strategy to give the customer an ETA is to calculate the distance between driver -> restaurant and restaurant -> customer, however, this is wouldn't be accurate for many reasons. One of them being the fact that we are not taking into consideration the time it takes for the food to be ready. In the best-case scenario, the time it takes for a driver to drive to the restaurant is the time it takes for the restaurant to prepare the food -- but that is not always the case. Machine learningA better approach to this problem, in my opinion, is to harness the power of machine learning to give us the best possible delivery ETA to our customers. To do this, we will some data. To make it simple, we can find some open-source data collections on this (I'm sure there are plenty out there) and use that to train a machine learning model. ParametersThese are just my suggestions, please feel free add/suggest. To better understand how we can create a decent prediction model, we first need to understand what determines the time it takes to prepare the food?
These are just a few I could come up with. But gathering data on x amount of restaurants for these given parameters would allow us to create a pretty decent machine learning model, which in turn would enable us to provide our customers with the most accurate delivery ETA possible. Accurate Delivery ETAFinally the accurate delivery ETA would be composed of three variables: DistanceA: Distance from driver to the restaurant Let me know what you guys think! |
Beta Was this translation helpful? Give feedback.
-
We need a process in place to handle cancellations. This issue is most relevant to figure out internally who is going to pay for the order, delivery, etc. |
Beta Was this translation helpful? Give feedback.
-
Do we gonna implement this using firebase or firestore? |
Beta Was this translation helpful? Give feedback.
-
Hi may be this is stupid to ask, app like ride-sharing, delivery heavily depends on streaming platform like Kafka, what is the possibility of using that kind of streaming platform in this app. |
Beta Was this translation helpful? Give feedback.
-
I assume you are storing historical lat,long for the delivery? We, at Burro, store it in an entity called a “run”. We save it on the drivers phone every 3 seconds and send up the dataset at arrival milestone in case the cell connection fails. This allows driver to capture for tax and other purposes when using personal car. |
Beta Was this translation helpful? Give feedback.
-
How do you plan to implement the real-time feature in 'Box-Out' by cloud function? |
Beta Was this translation helpful? Give feedback.
-
Let's discuss the functionality of the restaurant manager and restaurant application. As I understand it, the above two pieces of software will fundamentally enable resturants to upload products and receive orders. However, is the process too dependant on manual input? I ask this for a few reasons: Firstly, considering restaurants within the context of SA, they already have food delivery applications setups such as Mr D and Uber Eats. Each time they get an order, a restaurant worker still has to manually input the order into their POS system. This may lead to wrongful input into the POS system. Secondly, the uploading of products is manual as well. Restaurants are required to upload their products to the restaurant manager application. As a result, the products displayed to the end-user may no longer be available at the restaurant since the restaurant may have forgotten to update them. With each new 'service' that is proposed to a restaurant - the restaurant owner has to evaluate how much labour is needed in order to get the service functioning. Therefore, should the 'food delivery service' integrate directly with the POS system? Although this may reduce manual input and labour - one has to consider whether the POS system in the restaurant enables this form of integration. Certain POS systems have API's that services can tap into but this will not be universal. Having spoken to a few restaurant owners, they are all for new ways to get orders. But, as mentioned before, they are concerned with the added manual labour that occurs when a new 'service ' is added. Consequently, in an ideal world, the POS system integration sounds great. But there are a few too many logistical implications. What do you guys think about this? |
Beta Was this translation helpful? Give feedback.
-
Hi Dane Absolutely love your stuff, you're the reason I have begun my flutter development journey while still in second-year software development studies. I have a quick question about the actual HTTPS requests and responses. Have you thought about the data compression to be used? I have not seen it mentioned in the docs but apologies if it has and I've missed it. I believe that GZIP compression could be quite beneficial to make things even more efficient especially in the case of using express as our server architecture. What are your thoughts? |
Beta Was this translation helpful? Give feedback.
-
How's caching handled? In the thread above it mentions Firebase automatically caches for 28 days but wondering if this applies to Cloud Functions (/Hosting?) as well? Looking at say, the function for fetching orders - how would this be invalidated for new orders? Perhaps with a reactive hook? I know Cloud Functions take a little longer than straight calls to Firebase but do help cut the reads down. Would love to know a little more about how this all works. Loving the videos, thank you so much! Switched over to Stacked 8 months ago and never looked back! |
Beta Was this translation helpful? Give feedback.
-
As mentioned at the end of the new video you can watch here this is the discussion where you can ask questions about the Technical Product Architecture. If you have suggestions please leave them below. The process of determining the best technical architecture is the same one we followed to determine the high level overview of the product architecture. We will walk through the largest and most important use case and technically detail what needs to happen or what would be the best way to do this. The scenario is as follows:
These are the high-level steps for the most important process in this service. We will use this to determine the following technical details that would be required before we start writing any code.
Once we have all this information we will have a better idea of what we are building which will give us a better platform to work off when planning the actual development work. Once the decisions have been made all of this will be moved into a document in the Wiki which will detail everything that has been decided.
Please share your ideas below if you have any.
Beta Was this translation helpful? Give feedback.
All reactions