FGA Contract

April 7, 2026 · View on GitHub

This document is the authoritative reference for all messages the mailing list service sends to the fga-sync service, which writes and deletes OpenFGA relationship tuples to enforce access control.

The full OpenFGA type definitions (relations, schema) for all object types are defined in the platform model.

Update this document in the same PR as any change to FGA message construction.


Object Types


Message Format

This service uses four FGA operation types:

SubjectOperationUsed for
lfx.fga-sync.update_accessupdate_accessCreate and update — sets object-level access config and references
lfx.fga-sync.member_putmember_putAdds a user to one or more relations on an object
lfx.fga-sync.member_removemember_removeRemoves a user from an object; sent on member delete. An empty relations array removes all relations for that user on the object
lfx.fga-sync.delete_accessdelete_accessDelete — removes all FGA tuples for the object

GroupsIO Service

Source struct: internal/domain/model/GroupsIOService (base + settings)

Synced on: create, update, delete of a GroupsIO service.

update_access

Published to lfx.fga-sync.update_access on service create or update.

Message Envelope

FieldValue
object_typegroupsio_service
operationupdate_access

Data Fields

These fields are carried inside the message data object.

FieldValue
uidService UID
publicGroupsIOService.Public (passed through directly)

Relations

RelationValueCondition
writerUsernames from GroupsIOServiceSettings.WritersOnly when Writers is non-empty
auditorUsernames from GroupsIOServiceSettings.AuditorsOnly when Auditors is non-empty

Usernames are extracted from the Username pointer of each UserInfo entry. Users with a nil or empty Username are skipped.

References

ReferenceValueCondition
projectGroupsIOService.ProjectUIDAlways

Delete

On delete, a delete_access message is sent to lfx.fga-sync.delete_access with only the service uid — all FGA tuples for groupsio_service:{uid} are removed by the fga-sync service.


GroupsIO Mailing List

Source struct: internal/domain/model/GroupsIOMailingList (base + settings)

Synced on: create, update, delete of a GroupsIO mailing list (subgroup). Member changes are synced separately via member_put and member_remove.

update_access

Published to lfx.fga-sync.update_access on mailing list create or update.

Message Envelope

FieldValue
object_typegroupsio_mailing_list
operationupdate_access

Data Fields

These fields are carried inside the message data object.

FieldValue
uidMailing list UID
publicGroupsIOMailingList.Public (passed through directly)

Relations

RelationValueCondition
writerUsernames from GroupsIOMailingListSettings.WritersOnly when Writers is non-empty
auditorUsernames from GroupsIOMailingListSettings.AuditorsOnly when Auditors is non-empty

Usernames are extracted from the Username pointer of each UserInfo entry. Users with a nil or empty Username are skipped.

References

ReferenceValueCondition
groupsio_serviceGroupsIOMailingList.ServiceUIDAlways
committeeCommitteeUID per committeeOne entry per committee with a non-empty UID

Exclude Relations

exclude_relations: ["member"] — always set. Individual mailing list members are managed via member_put and member_remove and must not be overwritten by the update_access handler.

member_put (Member Create/Update)

Published to lfx.fga-sync.member_put when a member event is processed and the member has a non-empty Username. The username is resolved to an Auth0 sub value via principal.FromUsername before sending.

The object UID is the parent mailing list UID, not the member UID. The parent is resolved from the group_id → mailing list reverse index.

Message Envelope

FieldValue
object_typegroupsio_mailing_list
operationmember_put

Data Fields

FieldValueCondition
uidMailingListUID (parent mailing list)Always
usernameAuth0 sub of the memberAlways (skipped if Username is empty)
relations["member"]Always

member_remove (Member Delete)

Published to lfx.fga-sync.member_remove when a member delete event is processed and the stored mapping contains a non-empty username. The username is resolved to an Auth0 sub value via principal.FromUsername before sending.

The object UID is the parent mailing list UID, recovered from the stored member mapping (uid|username|mailingListUID).

FieldValue
object_typegroupsio_mailing_list
uidMailingListUID (parent mailing list)
usernameAuth0 sub of the member
relations[] (empty — removes all relations for the user)

Delete

On delete, a delete_access message is sent to lfx.fga-sync.delete_access with only the mailing list uid — all FGA tuples for groupsio_mailing_list:{uid} are removed by the fga-sync service.


Triggers

OperationObject TypeSubjectNotes
Create/update GroupsIO servicegroupsio_servicelfx.fga-sync.update_accessAlways sent
Delete GroupsIO servicegroupsio_servicelfx.fga-sync.delete_accessAlways sent
Create/update mailing listgroupsio_mailing_listlfx.fga-sync.update_accessAlways sent
Delete mailing listgroupsio_mailing_listlfx.fga-sync.delete_accessAlways sent
Create/update member (with username)groupsio_mailing_listlfx.fga-sync.member_putSkipped if Username is empty
Delete member (with username)groupsio_mailing_listlfx.fga-sync.member_removeSkipped if stored mapping has no username