Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start new meeting sprint numero uno #121

Closed
8 of 25 tasks
jordanh opened this issue Jul 18, 2016 · 6 comments
Closed
8 of 25 tasks

Start new meeting sprint numero uno #121

jordanh opened this issue Jul 18, 2016 · 6 comments
Assignees

Comments

@jordanh
Copy link
Contributor

jordanh commented Jul 18, 2016

Issue - Enhancement

In this sprint we'll implement:

  1. The beginnings of implementing a designed version of the lobby
  2. Scaffolding out layouts/components and events for:
    1. Check-in round
    2. Project updates
    3. Adding agenda items
    4. Progressing through agenda items, adding projects and actions
    5. Pre-summarizing and offering to end the meeting, or add another agenda item
    6. A placeholder for displaying the meeting summary, and a link to return to the team dashboard

Let's temporarily stick all of the state we need as state on the top-level container to discover what and where we need to put the domain state (in the DB, in a duck, etc.) and what we need to subscribe to.

We will also ignore HotKeys for now.

Here's our checklist:

  • Team lobby:
    • Team lobby layout implemented
    • Team members and avatars listed
    • Team members have gray badge when offline
    • Team members have cool themed badge when online
    • "Share this meeting" long-form link (we'll tackle shorts later) accurate
    • Start meeting button implemented
  • Check-in round:
    • List of team members rendered into cards
    • Cards processed one at a time (ignore animation for now)
    • Attendees receive checks-marks after check-in (only a green check, we assume all check-in status are "good")
    • When all attendees have checked-in "This wraps up our check-in round" is displayed
    • Some indication of progress? How many more folks to loop through displayed?
  • Project updates section scaffolded:
    • We can click through all attendees again.
    • Placeholder for four-column project list rendered
    • Some indication of progress? How many more folks to loop through displayed?
  • Whatcha need?/Agenda building section scaffolded:
    • Ability to add items to list (but not reorder)
  • Process agenda items scaffolded:
    • Can add new projects, can add new actions
    • Can add item description
    • Can assign item to single owner
    • Can navigate forward to next item
    • Can navigate back (via requests list)
  • Pre-summary/end meeting screen
    • Rolls up count requests processed, and totals for actions and projects created
    • Button to end meeting added
    • Can still add requests (and will navigate to it as soon as it's created)
  • Actual meeting summary
    • Placeholder for real meeting summary
    • Link back to team dashboard
  • Estimated effort: 5 points (see CONTRIBUTING.md)
@mattkrick
Copy link
Member

question about participant meta data, how much we want?

  • were they in the meeting?
  • how long were they in the meeting?
  • how many devices did they use during the meeting?

my thought is to go NSA style & collect it all. For example, if we capture authToken, joinedAt, leftAt of every single socket, we could calculate some really cool stuff:

  • how long they were in the meeting: max(connections.leftAt) - min(connections.joinedAt)
  • how many tabs they had open (overlapping times that use the same authToken)
  • how many devices (or browsers) they used (overlapping times that use a different authToken)
  • connectivity-quality heuristics (TOL for a connection with the same authToken)
  • the estimated time the meeting ended (critical mass of sockets leaving)

of course, this depends on #68 since a mid-meeting renewal would just screw us up.
My thought there is that if the token has less than X days left, renew it on the socket handshake, but that's OOS for the MVP.

@jordanh
Copy link
Contributor Author

jordanh commented Jul 20, 2016

my thought is to go NSA style & collect it all.

😆

What you've got here is really cool.

Let's define which data I think we'd need and what metadata would be nice to have.

So, data:

  • Output – projects and actions; written as a changelog with each row having a parentId to create an audit trail
  • Attendance – participant-level data for each meeting answering two questions: did the team member attend the meeting? And, what time did they join the meeting? The former is probably an enum (ABSENT, PRESENT_AFTER_CHECKIN, PRESENT_AT_CHECKIN). We won't account for folks that left early. Showing up is enough at this level.
  • MeetingHistory – the changes in Output recorded at the end of a meeting. Simple meeting duration (click of 'Start meeting' from lobby until 'End meeting' before meeting summary). Also, perhaps this table also contains Attendance data...

So, metadata:

I think you have it exactly correct. It's all the connection-level stuff. I think the minimum set is authToken, joinedAt, and leftAt.

For user-facing value, I think we could eventually write a task that rolls some of this data up into a little monthly report like Slack does. For example, "most attentive award goes to X, flakiest attendee award goes to Y."

For internal facing value, I think we'll come up with ALL KINDS of uses for this metadata.

One question.

Question: What does TOL stand for?

@mattkrick
Copy link
Member

TOL- time of life. Is that not a thing? Seeing it again, I don't think that's a thing...

2 comments:

  • I don't like the word output. output is vague. I'd prefer the word task. I could see projects and actions being in a family called tasks. I could see output being anything that comes after hitting the enter key.
  • I see attendance as being a 2nd (or 3rd) class citizen. It's not really data, rather it's a value computed from meta data. Sure, we can compute it & cache it somewhere for performance sake, but given authToken.exp, joinedAt, leftAt, we can always calculate it. The only exception here is the traveling salesman who logs into the lobby & never checks in because he'd rather schmooze with the booth babes.

@mattkrick
Copy link
Member

mattkrick commented Jul 21, 2016

Moved the issue over to cashay to keep this clean. mattkrick/cashay#87.

@mattkrick
Copy link
Member

GAH, subscriptions are hard.
Let's say we want the following:

    teamMembers {
      isActive
      isLead
      isFacilitator
      user {
        picture
        preferredName
      }
    }

This would be hunky dory if it was all one table, but it's not. user is a separate table. So, we have some options:

  • duplicate picture, preferredName into the teamMember table. These things will rarely change, so the extra writes & keeping everything in sync isn't too hard.
  • use the realtime event-driven subscriptions, per above. I'm less in love with this now than before. The reason why is because it's essentially sending a message to someone, telling them to ask for a message. First, we have to have a channel and handler for that message, which means we'll probably piggyback on the presence channel, which isn't intuitive. Next, we have to make sure to send that message on every trigger (change avatar, change name, add team member, remove team member, update team member). Also, we'd have to write 2 additional queries: getTeamMember(id)... and getUser(id) { preferredName, picture}.
  • subscribe to TeamMembers without the user. then, wait until all of the initial documents make it to the client, grab the IDs, and call a second cashay.subscribe(userQuery, {variables: {teamMembers: [1,2,3]}}). This sucks because we'd have to send a changefeed state message saying "yup, you got em all". Then, if some punk decided to accept his invitation while the meeting was in progress, we'd have to stop the subscription, create a new one with the new guy, re-receive all the previous docs, yeah....
  • Subscribe to a union. If we union TeamMember and User, then we can pass in a teamId and get all the TeamMembers, but to get all the associated Users, we'd either have to save an array of teams on the User table, or do something super awkward like:
r.db('actionDevelopment').table('User')
  .filter(doc => r.db('actionDevelopment').table('TeamMember')
  .getAll(doc('id'), {index: 'userId'})
  .filter({teamId})
  .isEmpty()
  .not()
  )

And, once we establish that, we'd still have to do some magic to figure out what teamMember the doc is referring to.

So, after spending far too long figuring out all of the options we got, it seems like the first option is the fastest to implement, easiest, most scalable, and most flexible. Denormalizing data before we even get an MVP out reeks of premature optimization, but it really is the best option (under the assumption that space is cheap, computations are expensive, and client payload should be minimized at all costs). Welcome to the Real Time Web™

@mattkrick
Copy link
Member

Closing this issue in favor of bite-sized chunks.

@jordanh jordanh removed the building label Jul 28, 2016
@mattkrick mattkrick mentioned this issue Jul 28, 2016
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants