PeopleStore

This store will hold the data of the users that are involved in the meeting. The basic data (data that is stored in the database) will be enriched with data client-side only, for example:

UserPicURL : The URL of the image the user has active.

: The URL of the image the user has active. IsContact : If the user is a contact of my user.

: If the user is a contact of my user. IsActive: If the user account is active.

And also, for convenience, will create a field myUser inside the store, with the user that is currently connected.

Notice that all the data that is in the store can just be accesed directly in the components. That’s correct, but the idea to have it on the store is because it simplifies the use inside the React components and also allows better testability.

TagsStore

In timefic, Tags are used to provide a structure over the meetings, like a project or area where the meeting belongs to. So, this store is pretty straight forward but, because there are 2 levels of Tags in timefic (project/subject or area/subarea), this store actually serves also to “flatten” the hierarchy and have as a result a record with the parent area name attached to the child.

Meeting. Photo by rawpixel on Unsplash

MeetingsStore

The main store of the module (actually the module has this same name) and also the main collection of the whole application.

When you start modeling the application “everything is in this collection”, until you recognize some data has its own entity and you decide to separate them from this store, like Actions, Agreements and Comments, for example.

So this store must remain simple, be the skeleton of you app and hold this kind of data:

Tags : We attach the name and id of the tag (subject of the meeting) and the parentTag (project that has that subject), so we can display both names later in the UI.

: We attach the name and id of the tag (subject of the meeting) and the parentTag (project that has that subject), so we can display both names later in the UI. LogoURL : The logo that will be displayed later in the minutes

: The logo that will be displayed later in the minutes DateTimeRange: A calculated field to indicate the dates when the meeting should begin and end: the startDate plus the duration.

ContributionsStore

Contributions are notes, in form of text, that attendees can send to the secretary of the meeting to include in the minutes. When an attendee publish it contribution, the secretary receives a notification with the name and picture of the contributor. So, we take that information from PeopleStore and attach to the contribution, so its easy to use later:

Contributor : Name, Picture and Initials of the person that made the contribution.

: Name, Picture and Initials of the person that made the contribution. OwnContributions : A filter over the contributions of the meeting that only shows the contributions that are created by my user and not published yet (they still can be modified).

: A filter over the contributions of the meeting that only shows the contributions that are created by my user and not published yet (they still can be modified). ReceivedContributions: A filter over the contributions of the meeting that only shows the contributions sent to my user and not used yet (once published, they are filtered out of this collection).

Presentations. Photo by Teemu Paananen on Unsplash

PresentationsStore

A Meeting can have zero or one presentation per attendee. When the organizer creates an item on the agenda he can define an attendee to the be presenter of that topic, so a Meeting can end having various presentations.

The main element of the presentation is the slides field, an array of items where each item have some attributes that ends in a URL that will be used to display that slide.

For example, an image will be displayed inside an img tag, but a Google or Office Document will end inside an iframe, with a URL that includes also the service used to display that content.

MembersStore

Members mixes information from People and the Meeting, to have the “meeting point of view of each person”. Fo example, the following fields are attached to each person and used later in business rules and ui elements:

_id, name, email, initials, activePic, isRegistered, color, role, isMe, askedTheFloorCount, hasAskedTheFloor, isChatOn, isMicOn, isVideoOn, isOnline, score, token, isPresenter, isSecretary, peerUID.

This is a central store for the application and also serve the purpose to define collections, or subsets of elements for:

Active Presenter, Active Screen Sharer, All Active Members, Me and Organizer.

ClocksStore. “grayscale photography of pocket watch” by Tristan Colangelo on Unsplash

ClocksStore

In timefic, the clock plays a central role in order for the meeting to be productive. So, the meeting must start on time, each topic must also start and end on time and there is a time also to close the meeting after its finish (and send the minutes to the participants).

This rules are based on certain configurations that come from the MeetingsStore, and are used inside other stores to enhance its business rules (like ActionsStore, AgreementsStore and TopicsStore)

The following fields are created and re-evaluated after each second or “tick” in the clock:

SecondsToStart , seconds that lasts for the meeting to start.

, seconds that lasts for the meeting to start. SecondsToSuspend : Time to start, we are going to wait no more that this seconds…

: Time to start, we are going to wait no more that this seconds… SecondsElapsed , or the meeting total seconds from its beginning.

, or the meeting total seconds from its beginning. SecondsToFinish , seconds that lasts for the meeting to end.

, seconds that lasts for the meeting to end. SecondsToSecretaryClose , or the seconds that remains to the secretary to deliver the minutes to the organizer.

, or the seconds that remains to the secretary to deliver the minutes to the organizer. SecondsToClose, or the seconds that remains to the organizer to close the meeting and send the minutes.

TopicsStore

Another central store in the application. A topic is like a “mini-meeting”, because it has defined some time to start, some total time to last, notes, etc.

Here are some elements that belong to this store that we are going only mention, at least for the purpose of this post:

UI related : myTopics, myActiveTopic, newTopicObject, myMeetingAgenda, myTopicsChatSelector,

: myTopics, myActiveTopic, newTopicObject, myMeetingAgenda, myTopicsChatSelector, Time related: secondsRemainingInActiveTopic, secondsElapsedInActiveTopic, activeTopicProgress, extendedSecondsConsumed and meetingAgendaTimer.

Outcomes. “A person drafting a marketing campaign plan in a notebook on their lap” by rawpixel on Unsplash

ActionsStore, AgreementsStore, CommentsStore and MessagesStore

This stores (plus the notes inside the TopicsStore) are the “outcomes stores” or stores that holds information generated by the users, during the meeting, that will be in the minutes or another digital form available after the meeting ends.

They are conceptually similar but holds different data and business rules. Its not my intention to go into a lot of detail for this stores, but here you have some fields they had:

ActionsStore : myActions, newActionObject, mySelectedAction, mySelectablePeople, mySelectableDays, mySelectableHours, myAssignedActions.

: myActions, newActionObject, mySelectedAction, mySelectablePeople, mySelectableDays, mySelectableHours, myAssignedActions. AgreementsStore : myAgreements, newAgreementObject, myAgreementsDisplayedInForm, mySelectedAgreement, myOpenedAgreement, secondsRemainingInAgreement.

: myAgreements, newAgreementObject, myAgreementsDisplayedInForm, mySelectedAgreement, myOpenedAgreement, secondsRemainingInAgreement. CommentsStore : myComments, myComment, attendeesComments, unreadedCommentsCount.

: myComments, myComment, attendeesComments, unreadedCommentsCount. MessagesStore: myMessages, myActiveTopicMessages, unreadedMessagesCount.

Final words

When you design your stores you want them to be:

Structurally similar , although they hold different data, all the primitives to define a store remains the same: you will have primitive (observable) values, derived (computed) values, actions to modify observables and reactions to catch events that also needs to be reflected in the data of the store.

, although they hold different data, all the primitives to define a store remains the same: you will have primitive (observable) values, derived (computed) values, actions to modify observables and reactions to catch events that also needs to be reflected in the data of the store. Semantically separated , avoid mixing domains as much as possible. A pure domain should represent an entity in your model (like Actions, Agreements, Comments, etc.) or some channel where data comes in (like Clocks and Alerts) or a compound store that needs to mix concepts in order to represent business rules.

, avoid mixing domains as much as possible. A pure domain should represent an entity in your model (like Actions, Agreements, Comments, etc.) or some channel where data comes in (like Clocks and Alerts) or a compound store that needs to mix concepts in order to represent business rules. Atomically divided, or divided in parts that “cant be divided further”, so you are forced to give this part a name and, with that, make clear for everyone else (the other stores) the purpose of each element.

I hope this post, and this series, can help anybody who is trying to model the data of the next application that will improve our lifes!

Cheers form Chile 🇨🇱!