Closed BartoszJarocki closed 2 years ago
There are at least two ways to accomplish the goal of having team prompt activity with recurrence in mind.
teamPrompt
TeamPromptResponse
table which would store the team prompt responsesfields
id
createdAt
updatedAt
creatorId
meetingId
content
reactjis
questions a. should we store it in rethink or pg? any potential issues with storing that in pg?
Discussion
table [postgres]
teamPromptResponse
to discussionTopicType
enumAt this point, we need to figure out how to handle recurrence
For example, we have a team prompt meeting, interval set to daily
. In this case, each day will be a new meeting phase.
Changes needed
NewMeeting
table [rethinkdb]
teamPrompt
isRecurring
, interval
[daily, weekly, monthly, yearly?], startDate
(with tz), endDate
(with tz)Example JSON structure of a meeting
{
"id": "...",
"createdBy": "...",
"createdAt": "...",
"endedAt": "...",
"meetingNumber": 1,
"meetingType": "teamPrompt", // new type
"name": "Async Standup #1",
"isRecurring": true, // new field
"interval": "daily", // new field
"startDate": "...", // new field
"endDate": "...", // new field
"summarySentAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211686.138,
"timezone": "+00:00"
},
"teamId": "...",
"templateId": "...",
"updatedAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211683.29,
"timezone": "+00:00"
},
"phases": [
{
"id": "...",
"phaseType": "responses", // new type
"stages": [
{
"id": "...",
"phaseType": "responses",
"startAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211647.127,
"timezone": "+00:00"
},
"endAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211650.609,
"timezone": "+00:00"
},
"isComplete": true,
"isNavigable": true,
"isNavigableByFacilitator": true
}
]
},
{
"id": "...",
"phaseType": "responses",
"stages": [
{
"id": "...",
"phaseType": "responses",
"startAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211647.127,
"timezone": "+00:00"
},
"endAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211650.609,
"timezone": "+00:00"
},
"isComplete": false,
"isNavigable": true,
"isNavigableByFacilitator": true
}
]
}
]
}
NewMeeting
data model NewMeetin
, for example summarySentAt
, endedAt
, startDate
, endDate
For example, we have a team prompt meeting, interval set to daily
. In this case, each day will be a new meeting.
New Meeting
table [rethink]
parentMeetingId
field which will store the meeting id that groups all the sub meetingsmeetingParentId
on the dashboardRoot meeting
{
"id": "parentId",
"parentMeetingId" : null, // new field
"createdBy": "...",
"createdAt": "...",
"endedAt": "...",
"meetingNumber": 1,
"meetingType": "teamPrompt",
"name": "Async Standup #1",
"isRecurring": true,
"interval": "daily",
"startDate": "...",
"endDate": "...",
"summarySentAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211686.138,
"timezone": "+00:00"
},
"teamId": "...",
"templateId": "...",
"updatedAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211683.29,
"timezone": "+00:00"
},
"phases": [] // do we need anything here?
}
Child meeting, representing an instance of the given interval, ie. day in the daily standup
{
"id": "...",
"parentMeetingId" : "parentId",
"createdBy": "...",
"createdAt": "...",
"endedAt": "...",
"meetingNumber": 1,
"meetingType": "teamPrompt", // do we need a special type for a child meeting?
"name": "Async Standup #1",
"startDate": "...",
"endDate": "...",
"summarySentAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211686.138,
"timezone": "+00:00"
},
"teamId": "...",
"templateId": "...",
"updatedAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211683.29,
"timezone": "+00:00"
},
"phases": [
{
"id": "...",
"phaseType": "responses",
"stages": [
{
"id": "...",
"phaseType": "responses",
"startAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211647.127,
"timezone": "+00:00"
},
"endAt": {
"$reql_type$": "TIME",
"epoch_time": 1644211650.609,
"timezone": "+00:00"
},
"isComplete": true,
"isNavigable": true,
"isNavigableByFacilitator": true
}
]
}
]
}
NewMeeting
data modelScheduledJobs
tableScheduledJobType
, something like MEETING_NEW_PHASE_START
, MEETING_END
and MEETING_START
, tbd@BartoszJarocki Didn't look into the details yet if it would work, but since you want to discuss this with Matt I just wanted to put the idea out there: How about having 1 meeting for standups and add multiple phases for the recurrenses.
@Dschoordsch I think that's exactly what I proposed as a first solution in First way - each interval instance is a new meeting phase
. ie. one root meeting, then each recurrence is a phase
edit: I improved wording, recurrence
sounds way better than interval instance
, thank you!
@mattkrick just a thought, in solution one where each day is a new phase, we wouldn't have to fetch everything if we store data in PG (we could fetch +/- X days of the current date and paginate if needed). Creating all the tables related to the meeting in pg is a pretty big lift though, so I'm not sure if we should do that now
I probably should've been more clear about what's needed for the current scope and what's for the future. The initial scope can be found here: https://www.notion.so/parabol/Stand-up-MVP-27ebad512e754eb0ae740cdb7326a080#b570682f1fa04c8eb48ef93eced37ffa
To actually implement this, we don't need recurrence, thus we don't need any changes to the NewMeeting
table, for now. Changes needed:
teamPrompt
Once we have that, we can figure out the recurrence (it'll be at the same time when we'll be adding the day picker to the meeting). It'd be nice to have that discussed already, but I don't want to slow down the development. The reason I also proposed some solutions to recurrence is I believe it'll require some changes to the NewMeeting
table and wanted us to be prepared.
TLDR
Let me know what do you think CC @mattkrick @Dschoordsch
Edit: I updated initial comment to make it clear
I think you''re right with the safe to try™ part.
Reading through all this, I think it might be useful to have a separate Recurrance
table with a 1:n relationship to NewMeeting
. This way we wouldn't bend the NewMeeting
meeting type too much which in the long term would understanding the logic difficult.
Use case dashboard: We show open meetings as we do now. If Recurrance
is linked we can show history of meetings. If the meeting is recurring, there should be one open instance. We might want to have a 'meeting did not start yet' stage, but it's probably best to just open the next one straight after the last one was closed.
As your Metrics Representative, I'd like to invite us think about from metrics perspective too. I have following teaser questions:
Also CC @tghanken for insights
From a data modeling perspective, I prefer the method outlined by @Dschoordsch where we create a Recurrence
table.
I have concerns about the approach outlined in First way - each recurrence is a new meeting phase
as it would make it more difficult to extend recurrence to existing and future multi-phase meeting types. If we implemented recurrence as phases, would we then need to nest phases within phases if we wanted to implement recurrence for retros?
add new fields related to recurrence,
isRecurring
,interval
[daily, weekly, monthly, yearly?]
Would it make sense to store the data internally in a crontab style (or something similar) format? We could start by implementing simple cases (daily, weekly, etc.) in the product, but this would allow us to open up more options for users in the future without backend data manipulation.
- How do we define "number of meetings held" for stand-up? In a recurrence setting, say a daily activity, we probably would like each day to be counted as a distinct meeting?
- What's the definition of "meeting completed" in this sense? Again, for a daily activity, do we mark the activity/meeting as completed at midnight each day?
I agree with what you've outlined here. Each "instance" of a recurrence should count as a full meeting from a metrics perspective. We likely want some sort of participation check in place so that we don't inflate numbers if someone sets a recurring meeting and never uses it. Should a meeting be marked as complete at all if no one participates?
- Thinking out of box, should we still track the same old set of metrics or we could introduce new metrics for async stand-up?
For the most part, I think using the same metrics works, as we should treat each instance of a recurrence as an individual meeting. However, I think it would also be helpful to monitor usage at the "Recurrence" level as well:
I'll keep thinking through this and see if there's any additional metrics that I think would be helpful.
@Dschoordsch @tianrunhe @tghanken this is awesome, thank you for the feedback!
Seems like the best option is to treat each recurrence as a separate meeting. Having another table with 1:n relation will do the job and it won't require NewMeeting
table modification (very little, at most). At te beginning we won't be restricting standup
to have only one active meeting (timezone differences etc) so we'll have to figure out how to show only the parent
on the dashboard. Having recurrence as a separate meeting also means that day/week/whaverver navigator could simply change the URL to a different meeting id (so we can link to the proper day/meeting), I like that direction!
How do we define "number of meetings held" for stand-up? In a recurrence setting, say a daily activity, we probably would like each day to be counted as a distinct meeting?
I guess the right answer is to count each day/week etc as a separate meeting
What's the definition of "meeting completed" in this sense? Again, for a daily activity, do we mark the activity/meeting as completed at midnight each day?
For the start, there will be no restrictions and we won't be closing meetings automatically (it's not in the current scope so it's subject to change anytime)
I haven't forgotten about this! will dive in this weekend. don't let me hold anything up if you're waiting on something. you have my full support moving forward!
Extra questions (some discussed during our 1:1):
Thoughts:
/meetings
query simple (no need to group on recurrence) and use a LIMIT 1 in the DB queries. If we don't restrict this now it may be extra work laterstartStandupMeeting
mutation closes the previous meeting so if the cronjob fails they can just manually open the next?What does an ended meeting look like? Is it immutable? Can a team member still add their updates? Depending on the definition of ended, can multiple child meetings be open at the same time? How do we encourage facilitators to close meetings?
This is more a UX question and I don't think we have an answer yet. CC @ackernaut
Is there a 1:1 relationship between Recurrence & Template? If so, could we merge them into the same table? Pros/cons?
I don't think it's 1:1. IMO users should be able to create as many team prompt meetings with different templates as they wish. Same as regular meetings.
Perhaps rename Recurrence to MeetingSeries (a little more specific since we might use "recurrence" in other places)
Sounds good!
If we can guarantee that a meeting series only has 1 open meeting at a time we can keep the /meetings query simple (no need to group on recurrence) and use a LIMIT 1 in the DB queries. If we don't restrict this now it may be extra work later
I don't think there will be any restrictions at the beginning as we don't want to make too many assumptions about how our users would like it to work. Timezones are a big issue there (when to close the meeting?) but that's just my personal opinion. CC @ackernaut
Cronjobs can fail, how can we build the system in a way that a failed cronjob doesn't ruin the meeting series? E.g. perhaps the startStandupMeeting mutation closes the previous meeting so if the cronjob fails they can just manually open the next?
IMO there should be a way to close/open the next meeting manually but that's also my personal take. CC @ackernaut
Can we build in PG? Laying the groundwork here would make the migration much easier later
I think all new tables should go to PG
@mattkrick These are all really good questions about recurrence and I hope it'll allow us to shape this feature nicely. If you think it'd be beneficial we can have some sync time with @ackernaut to discuss something that'd be safe to try with recurrence, I'm all for it.
Regarding the current phase, let's summarize implementation steps
teamPrompt
to export type MeetingTypeEnum = 'poker' | 'retrospective' | 'action'
TeamPromptResponse
with fields id, createdAt, updatedAt, creatorId, meetingId, content, reactjis
Discussion
table add new enum field teamPromptResponse
to discussionTopicType
enumAsync standup
related to teamPrompt
meeting (from UI perspective the meeting will show as Async Standup
(hardcoded), design details here: https://github.com/ParabolInc/parabol/issues/5918 @mattkrick please let me know if that sounds good. I'll start the implementation of the ☝🏻 while we continue to shape the recurrence with @ackernaut.
Here are my thoughts:
My real opinion is that a ‘recurring meeting’ is just one activity (i.e. meeting) and each ‘day’ instance is a phase, not a separate meeting. This is our standup, we answer e.g. M-T-T-F because Wed is focus day. We open 1 phase in advance of the current day, but I’m routed to the current day initially. Past days are completed phases.
I can go back to those conversations. We can pull stats at any time. If I end the recurring meeting, I think threads are threads and should stay alive, meaning I can edit responses, comments, and add new comments. If I do, folks should receive at least an in-app notification. If the conversations go stale naturally, we’re fine.
Terry & I discussed during our 1:1
Things we both agree on:
Remaining questions for @ackernaut
My notes after discussing with Matt:
I assume the response card should be editable as long as the meeting is open? To fix a typo, to go back and link something for clarity, etc.
👍
I think for recurrence we just close by day (not a time) and pick a timezone (e.g. Fri, CT)
Could we reuse the pattern for the meeting phase complete date/time picker? That pattern avoids timezones by just using local time & may look simpler to the user. Plus time may matter, e.g. if it's a standup, it closes by 10AM. if it's a friday ship, it closes by 4PM.
Re: time picker for ending each instance
Could we reuse the pattern for the meeting phase complete date/time picker?
Yeah, I’m simmering on that idea. I think it’s probably a good pattern, and will have an upcoming design task to further refine the details of recurrence. I can explore more there.
Create a standup database schema while keeping in mind that, standup is only one type of the possible use of the new meeting type.
team prompt
might be a more appropriate name for internal use.This issue involves designing and architecting data structures for a new meeting type. 1 . how the data structure should look like?
Before writing any code, it is required to outline the solution and discuss it with the maintainer.
AC: