-
Notifications
You must be signed in to change notification settings - Fork 0
Domain & Features
Domain diagram
@startuml Domain Diagram
!theme reddress-lightgreen
skinparam defaultFontName monospaced
title Domain Diagram
interface ProductEntity {
{abstract} +String get id()
{abstract} +String get name()
{abstract} +String? get barcode()
{abstract} +String? get brand()
{abstract} +String? get imageFrontUrl()
{abstract} +String? get imageFrontSmallUrl()
{abstract} +Duration? get expectedShelfLife()
{abstract} +StorageType? get suggestedStorageType()
{abstract} +int? get unsealedLifeTimeInDays()
{abstract} +Measure? get measure()
}
ProductEntity --> StorageType: suggestedStorageType
class ProductModel {
+String id
+String name
+String? barcode
+String? brand
+String? imageFrontUrl
+String? imageFrontSmallUrl
+Duration? expectedShelfLife
+StorageType? suggestedStorageType
+int? unsealedLifeTimeInDays
+Measure? measure
}
class Measure {
+double quantity
+UnitOfMeasure unitOfMeasure
}
ProductModel *-- Measure: measure
Measure *-- UnitOfMeasure: unitOfMeasure
enum UnitOfMeasure {
KILOGRAM
LITER
}
ProductEntity <|-- ProductModel
class User {
+String id
+String email
+String displayName
+List<String> houseIds
}
class House {
+String id
+String name
+String? description
+String ownerId
+List<String> adminIds
+List<String> userIds
}
User --* House: ownerId
User --* HouseUser: userId
HouseUser *-- House: houseId
class HouseUser {
+String userId
+String houseId
+bool isOwner
+bool isAdmin
}
House *-- Storage: houseId
class Storage {
+String id
+String name
+String? description
+StorageType storageType
+String houseId
}
StorageType <-- Storage: storageType
enum StorageType {
FRIDGE
FREEZER
PANTRY
}
' enum ItemCategory {
' MEAT
' FISH
' EGG
' FRUIT
' VEGETABLE
' LEGUMES
' DAIRY
' CEREALS
' }
interface ItemEntity {
{abstract} +String get id()
{abstract} +String get productId()
{abstract} +Date get initialExpiryDate()
{abstract} +DateTime get createdAt()
{abstract} +String get storageId()
{abstract} +DateTime? get openedAt()
{abstract} +int? get unsealedLifeTimeInDays()
{abstract} +int get amount()
---
+Date get actualExpiryDate()
{abstract} +ItemEntity copyWith()
}
ProductEntity <.. ItemEntity: references
class ItemModel {
+String id
+String productId
+Date initialExpiryDate
+DateTime createdAt
+String storageId
+DateTime? openedAt
+int? unsealedLifeTimeInDays
+int amount
+Date get actualExpiryDate()
+ItemEntity copyWith()
}
ItemEntity <|-- ItemModel
Storage *-- ItemEntity: storageId
abstract class Notification {
+String id
+DateTime createdAt
+DateTime scheduledAt
+DateTime? readAt
+NotificationType type
+int localId
+String title
+String body
+int? intVal
+String? stringVal
+bool? boolVal
+DateTime? dateTimeVal
---
+bool get isRead()
}
class UserNotification {
+String userId
}
Notification <|-- UserNotification
User <-- UserNotification: userId
class HouseUserNotification {
+String houseUserId
+int counter
}
Notification <|-- HouseUserNotification
HouseUser <-- HouseUserNotification: houseUserId
enum NotificationType {
DAILY_REMINDER
EXPIRING_ITEMS
EXPIRED_ITEMS
}
Notification *-- NotificationType
@enduml
A Product
is a good that can be purchased and consumed. Think of it as a product
in a supermarket, grocery store, etc., or even something that you made or grew
yourself.
A product has the following properties:
- id*: a unique identifier for the product
- name*: the name of the product
- barcode: the barcode of the product
- brand: the brand of the product
- imageFrontUrl: the URL of the image of the front of the product
- imageFrontSmallUrl: the URL of a smaller version of the image of the front of the product
- expectedShelfLife: how long the product is expected to last after it has been "produced" (e.g. packaged, harvested, etc.)
- unsealedLifeTimeInDays: how long the product is expected to last after it has been opened
-
suggestedStorageType: the suggested
StorageType
for the product - measure: the measure of the product
The measure is a pair of:
- quantity*: a number
- unit of measure*: a unit of measure
The inventory is the whole set of storages and all their items in the user's possession. It is not a real entity, but a concept that can be derived from the user's storages and items.
A storage is a place where items can be stored.
A storage has the following properties:
- id*: a unique identifier for the storage
- name*: the name of the storage
- storageType*: the type of the storage
- description: a description of the storage
A storage has a mandatory type that can be one of the following:
- FRIDGE
- FREEZER
- PANTRY
An item is a product that has been added to the user's inventory.
An item has the following properties:
- id*: a unique identifier for the item
- productId*: the id of the product it refers to
- initialExpiryDate*: the initial expiry date of the item as mentioned on the product's packaging or by common knowledge (e.g., a banana is known to last for a 5 to 7 days)
- createdAt*: the date and time when the item was added to the inventory. This property is determined by the system.
- storageId*: the id of the storage where the item is stored
-
openedAt: the date and time when the item was opened. This property is
null
if the item has not been opened yet. -
unsealedLifeTimeInDays: the number of days the item can last after it has
been opened. This property is initially copied from the product's property
unsealedLifeTimeInDays
and can be changed by the user. - amount*: the number of units of the item. By default, it is 1. See Grouping items for more information.
An item has the following derived properties:
-
actualExpiryDate: the actual expiry date of the item. This property is
determined by the system based on the
openedAt
property:- if the item has not been opened, it is equal to the
initialExpiryDate
- if the item has been opened, it is the minimum between
- the
initialExpiryDate
- the
openedAt
date +unsealedLifeTimeInDays
- the
- if the item has not been opened, it is equal to the
A User
is a person who uses the app. A user can be part of one or more houses.
A House
is defined by a group of users and storages. A house must have at least
one user.
A house has the following properties:
- id*: a unique identifier for the house
- name*: the name of the house, e.g., "Milan Home"
- description: a description of the house
- ownerId*: the id of the user who created the house. This user is the owner of the house. The owner is the only user allowed to delete the house even though a house cannot be deleted it it has other users than the owner themselves. The owner can transfer the ownership to another user by leaving the house.
- adminIds: a list of ids of the users who are admins of the house. Admins can add and remove users from the house (the owner cannot be removed).
NB: it's the house who "owns" the storages with items and not the user!
A notification is a message that the app sends to the user to inform them about something.
A notification has the following properties:
- id*: a unique identifier for the notification
- createdAt*: the date and time when the notification was created
- scheduledAt*: the date and time when the notification is scheduled to be shown to the user via the app local notification system
-
readAt: the date and time when the user read the notification within the
app. This property is
null
if the user has not read the notification yet. - type*: the type of the notification
- localId*: the id assigned to the notification within the local notification system
- title*: the title of the notification
- body*: the content of the notification
A notification has several properties such as intVal, stringVal, boolVal, etc., that can be used to store additional information about the notification. Each notification specific implementation can leverage these properties in a different way.
A notification linked to a specific user regardless of the house they are in.
A notification linked to a specific user in a specific house. If a user is in more than one house, they can have different notifications for each house they're in.
This class of notifications has an additional counter* property. It is used
in case the same notification can be scheduled multiple times. An example is the
EXPIRING_ITEMS
notification. We foresee that a user will have multiple items
that are going to expire soon on a certain day, so we want to show a single
notification for all of them. The counter is used to group these notifications
together.
When we're scheduling a new notification that may have already been scheduled we check if it exists and, in case, increment the counter. On the contrary, if we want to un-schedule a notification, we check:
- if the counter is greater than 1, we decrement the counter
- if the counter is equal to 1, we delete completely the notification
After that the notification is scheduled, when the notification is shown and tapped by the user, the plugin can listen and handle the notification and its payload. It knows If the app is been opened by tapping on a notification or the app was already opened when user taps on it.
On notification tap the plugin run the callback and pass the payload to the notification service
and the service adds the payload on its stream
.
The main app has a bloc listener
with a subscription on the notification service stream, so when a payload is added it triggers the payload handler: for now a notification page is pushed.
...
User has to scan the product's barcode, and, if the product is recognised user should insert some info:
- product expiration date
- storage
- measure (unit of measure and quantity) (e.g. 500 gr)
- units (the number of product he buyer, 2 packs of 500gr cookies)
TBD
See add item discussion to know if user wants to add an item that is the same as an existing item.
User deletes the item from his inventory. User can undo the deletion, in this case a new item with same information is created.
A user can open one item at a time. Opening an item means decrease the unit of the item by 1 each time and creating a new item with the date the user opened the item.
User chooses how many units of the item he has consumed and this value is decrease from the total item units. This action is allow only if the units of the item is greater than 1.
This action is similar to delete item. The item will be removed from the inventory. User can undo the action, in this case a new item with same information is created.
There are several type of notifications.
A notification of type DAILY_REMINDER
is sent to the user every day to remind
them to use the app, e.g., "What did you consume today?".
A notification of type EXPIRING_ITEMS
is sent to the user when one or more
items are going to expire soon, e.g., "You have N items that are going to
expire soon".
Ideally this notification should be sent at a time when the user is likely to decide what they're going to eat next, e.g., in the morning or in the early evening before dinner. The time should be configurable by the user.
A notification of type EXPIRED_ITEMS
is sent to the user when one or more
items have expired, e.g., "You have N items that have expired".
All notifications are listed inside the notifications page.