Skip to main content

Ropa & Organizational Unit

Source: src/models/ropa.ts

Each Organization has one Ropa document per configured locale, referenced via Organization.ropas[].ropaId. The Ropa document is the container for all Organizational Units and their activities for that locale.

Ropa

One Ropa document = one org × one locale.

FieldTypeRequiredNotes
orgIdStringOrganization._id cast to string; used for scoped queries.
orgShortNameString2–32 chars; denormalized copy of Organization.shortName for cache key construction.
localeString2-letter lowercase code, e.g. "es". Matches /^[a-z]{2}$/.
ousOU[]All organizational units for this locale, each containing activities.
createdAt / updatedAtDateManaged by timestamps: true.

Indexes

IndexTypeNotes
{ orgId: 1 }NormalPrimary lookup by organization.
{ "ous.activities.activityId": 1 }SparseFast activity lookup across all OUs without scanning the full document.

Organizational Unit (OU)

Nested inside Ropa.ous[].

FieldTypeRequiredNotes
ouIdNumberUnique per Ropa; assigned from Organization.highestOuId.
ouNameStringDisplay name.
ouColorStringHex color used in the UI to visually distinguish OUs.
templateIdObjectIdOptional reference to a Template document. When set, overrides the org-level template fallback for all activities in this OU that do not have their own templateId.
activitiesActivity[]See Activity.

Document structure

Ropa
└── ous[]
├── ouId, ouName, ouColor, templateId
└── activities[]
├── activityId, activityName, ...
└── templateId (activity-specific override)

To find an activity:

  1. Fetch Organization by shortName → get ropaId from ropas[] matching the target locale.
  2. Fetch Ropa by _id.
  3. Iterate ous[].activities[] to find the entry matching activityId.

The sparse index on { "ous.activities.activityId": 1 } supports step 3 at the database level when querying via aggregation or $elemMatch.