Kao, Mar 9th
Current user data model
IUserProfile { // src/js/types/User.ts
email?: string
avatar?: string
authProviderId: string
IUserMetadata {
IReadOnlyUserMetadata {
uuid: string
roles: string[]
loginsCount: number
}
IWritableUserMetadata {
name: string
nick: string
bio: string
website?: string
ticksImported?: boolean
collections?: {
climbCollections?: { [key: string]: string[] }
areaCollections?: { [key: string]: string[] }
}
}
}
}
We need a new entity for LCOs. To future-proof this construct, I propose we make it a subtype of a more general construct called an "Organization". It'll have the following data model which is similar in structure to IUserProfile
:
IOrganization: {
type: enum // one of {"local_climbing_organization", …}
avatar?: string
// Organizations have no login, therefore no email/authProviderId as with IUserProfile.
// It is their administrators that can log in and take actions.
IOrganizationMetadata {
IReadOnlyOrganizationMetadata {
uuid: string
}
IWritableOrganizationMetadata {
name: string
nick: string
bio: string
website?: string
email?: string // Email moved here since it is no longer an identifier for the model.
donationLink?: string
hardwareReportLink?: string
instagramLink?: string
collections?: {
areaCollections?: { [key: string]: string[] }
}
}
}
}
One cool idea here: We could also enable users to be associated with organizations. This could be self-declared or supplied by the organization. This would create stronger network effects and accelerate user growth. However, to prevent scope creep, we should take this idea for now.
We need to be able to record that some users are organization administrators. We will allow multiple administrators per organization with no hierarchy amongst these admins. A user can also be admins of multiple organizations at once. For now, the site admin will manually assign users to be organization administrators.
These administrators will have the following abilities:
- Update the organization's
IWritableOrganizationMetadata
via the organization profile page. This includes updating donation/Instagram/email links, and associating theOrganization
with various climbing areas by adding those areas toareaCollections
. - Post notices on routes in their area (eg land-use warnings, raptor closures, etc)
Question here is how to record that a user is an organization administrator.
- Expand
roles
The first option is to expanduser_metadata.roles
which currently supports only two values:
user_admin
, which is a site-wide admin capable of viewing all user metadata (src/pages/api/basecamp/users.ts), and migrating other users (src/pages/api/basecamp/migrate.ts)editor
, which doesn't seem to do anything at the moment. The tricky thing is that anorganization_administrator
role requires us to specify which organizations they are administrators of, so just adding another possible value touser_metadata.roles
is insufficient. Instead perhaps we could updateroles
from[]string
to[]object
so that we record things in this way:
roles: [
{role: user_admin},
{role: organization_admin,
organization: <bcc_uuid>},
{role: organization_admin,
organization: <action_committee_of_eldorado_uuid>},
]
-
New
organization_admin
field Another option is to create a newuser_metadata
field:user_metadata.organization_admin: []string
where the strings are uuids of the organizations the user administers. This would create an additional layer of role-like controls, which may be confusing in future. -
Hybrid I think this is the worst of both worlds, but listing for completeness. Add 'organization_admin' as a possible value for
role
, and then create anotherorganization_admin
field to track which organizations they are admins of.
Overall, I'm leaning toward option 2. Option 1 introduces a polymorphic data structure in the objects in the array, which can be the source of many errors. Option 2's risk is creating bloat in the top layer of the data model, and interference between multiple role-like systems. But if it's just two systems, we should be fine. In future, more site-level roles could just slot into the roles
field. Implementing area admins could be more tricky since they would require a user<>area map analogous to user<>organization map. But I guess then having an area_admin
field just like organization_admin
isn't that bad either.