Indexer Contract

May 4, 2026 · View on GitHub

This document is the authoritative reference for all data the mailing list service sends to the indexer service, which makes resources searchable via the query service.

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


Resource Types


GroupsIO Service

Object type: groupsio_service

Source struct: internal/domain/model/grpsio_service.goGroupsIOService

NATS subject: lfx.index.groupsio_service

Indexed on: create, update, delete of a GroupsIO service (v1 datastream via datastream_service_handler.go).

Data Schema

FieldTypeDescription
uidstringService unique identifier
typestringService type (primary, formation, shared)
domainstringGroups.io domain (e.g. groups.io)
group_idint64 (optional)Groups.io numeric group ID
statusstringService status; emitted as empty string when not populated
sourcestringSource system identifier; always "v1-sync" for v1 datastream records
prefixstringGroups.io group name prefix; emitted as empty string when not populated
global_owners[]stringGlobal owner list; always emitted as null/empty array by v1-sync (not populated by transform)
parent_service_uidstringUID of the parent service for shared type; emitted as empty string by v1-sync
project_uidstringv2 UID of the owning project (resolved from v1 SFID)
project_slugstringSlug of the owning project; emitted as empty string when not populated
project_namestringName of the owning project; emitted as empty string when not populated
urlstringGroups.io URL for the service group; emitted as empty string when not populated
group_namestringGroups.io group name; emitted as empty string when not populated
publicboolWhether the service is publicly accessible; emitted as false when not populated
created_attimestampCreation time (RFC3339)
updated_attimestampLast update time (RFC3339)
system_updated_attimestamp (optional)Last modified by a system process

v1-sync transform note: transformV1ToGrpsIOService populates uid, type, domain, group_id, prefix, project_uid, project_slug, source ("v1-sync"), and timestamps. All other fields (status, global_owners, parent_service_uid, project_name, url, group_name, public) are at their Go zero values and will be serialized as empty strings / false / null.

Tags

Tag FormatExamplePurpose
{uid}abc123Direct lookup by UID
service_uid:{uid}service_uid:abc123Namespaced lookup by UID
project_uid:{value}project_uid:bb4ed8c8-...Find services for a project
project_slug:{value}project_slug:my-projectFind services by project slug
service_type:{value}service_type:primaryFind services by type

All tags are only emitted when the value is non-empty.

Access Control (AccessMessage)

Published to lfx.fga-sync.update_access on create/update. Deleted via lfx.fga-sync.delete_access on delete.

FieldValue
object_typegroupsio_service
publicvalue of GroupsIOService.Public
references.project[project_uid]
references.writerusernames from writers (when settings present)
references.auditorusernames from auditors (when settings present)

Search Behavior (IndexingConfig)

FieldValue
object_id{uid}
publicvalue of GroupsIOService.Public
access_check_objectgroupsio_service:{uid}
access_check_relationviewer
history_check_objectgroupsio_service:{uid}
history_check_relationauditor
sort_nameGetGroupName() falling back to domain
name_and_aliasesGetGroupName(), domain (non-empty values)
fulltextspace-joined non-empty values of GetGroupName(), domain, prefix, type

Parent References

RefCondition
project:{project_uid}Only when project_uid is set

GroupsIO Service Settings

Object type: groupsio_service_settings

Source struct: internal/domain/model/grpsio_service.goGrpsIOServiceSettings

NATS subject: lfx.index.groupsio_service_settings

Indexed on: create/update of a GroupsIO service when writers or auditors are present. Settings share the same UID as their parent service.

Data Schema

FieldTypeDescription
uidstringService UID (same as the parent service)
writers[]objectUsers with write access. Each object has username (string, holds the user ID)
auditors[]objectUsers with audit access. Each object has username (string, holds the user ID)
last_reviewed_atstring (optional)RFC3339 timestamp of the last membership review
last_reviewed_bystring (optional)UID of who performed the last review
last_audited_bystring (optional)UID of who performed the last audit
last_audited_timestring (optional)RFC3339 timestamp of the last audit
created_attimestampCreation time (RFC3339)
updated_attimestampLast update time (RFC3339)

v1-sync build note: buildServiceSettings only populates uid, writers, and auditors. The optional review/audit fields and created_at/updated_at will be at Go zero values (0001-01-01T00:00:00Z for timestamps, null for optional strings).

Tags

Tag FormatExamplePurpose
{uid}abc123Direct lookup by UID
service_uid:{uid}service_uid:abc123Namespaced lookup by UID

Search Behavior (IndexingConfig)

FieldValue
object_id{uid}
access_check_objectgroupsio_service:{uid}
access_check_relationauditor
history_check_objectgroupsio_service:{uid}
history_check_relationauditor

Parent References

RefCondition
groupsio_service:{uid}Always set (uid is the parent service UID)

GroupsIO Mailing List

Object type: groupsio_mailing_list

Source struct: internal/domain/model/grpsio_mailing_list.goGroupsIOMailingList

NATS subject: lfx.index.groupsio_mailing_list

Indexed on: create, update, delete of a GroupsIO mailing list (v1 datastream via datastream_subgroup_handler.go).

Data Schema

FieldTypeDescription
uidstringMailing list unique identifier
group_idint64 (optional)Groups.io numeric group ID
group_namestringGroups.io group name; emitted as empty string when not populated
publicboolWhether the mailing list is publicly accessible
audience_accessstringAccess model: public, approval_required, or invite_only; not populated by v1-sync transform — emitted as empty string
sourcestringSource system identifier; always "v1-sync" for v1 datastream records
typestringList type: announcement, discussion_moderated, or discussion_open
subscriber_countintCurrent number of subscribers
committees[]object (optional)Associated committees. Each has uid (string) and allowed_voting_statuses ([]string)
descriptionstringMailing list description
titlestringMailing list title
subject_tagstringEmail subject tag; emitted as empty string when not populated
service_uidstringUID of the parent GroupsIO service
project_uidstringv2 UID of the owning project (resolved from v1 SFID)
project_namestringName of the owning project; emitted as empty string when not populated
project_slugstringSlug of the owning project; emitted as empty string when not populated
urlstring (optional)Groups.io URL for the subgroup
flags[]string (optional)Warning messages about unusual settings
created_attimestampCreation time (RFC3339)
updated_attimestampLast update time (RFC3339)
system_updated_attimestamp (optional)Last modified by a system process

v1-sync transform note: transformV1ToGrpsIOMailingList populates uid, group_id, group_name, public (from visibility), type, description, title, subject_tag, url, flags, service_uid (from parent_id), project_uid, source ("v1-sync"), subscriber_count, committees, and timestamps. audience_access, project_name, and project_slug are not set by the transform and will be emitted as empty strings.

Tags

Tag FormatExamplePurpose
groupsio_mailing_list_uid:{uid}groupsio_mailing_list_uid:abc123Namespaced lookup by UID
project_uid:{value}project_uid:bb4ed8c8-...Find mailing lists for a project
service_uid:{value}service_uid:abc123Find mailing lists under a service
type:{value}type:announcementFind mailing lists by type
public:{value}public:trueFind mailing lists by public status
audience_access:{value}audience_access:publicFind mailing lists by audience access
committee_uid:{value}committee_uid:061a110a-...Find mailing lists associated with a committee (one tag per committee)
committee_voting_status:{value}committee_voting_status:Voting RepFind mailing lists by committee voting status filter
group_name:{value}group_name:my-projectFind mailing lists by Groups.io group name

Access Control (AccessMessage)

Published to lfx.fga-sync.update_access on create/update. Deleted via lfx.fga-sync.delete_access on delete.

FieldValue
object_typegroupsio_mailing_list
publicvalue of GroupsIOMailingList.Public
references.groupsio_service[service_uid]
references.committeecommittee UIDs (one per associated committee)
references.writerusernames from writers (when settings present)
references.auditorusernames from auditors (when settings present)

Search Behavior (IndexingConfig)

FieldValue
object_id{uid}
publicvalue of GroupsIOMailingList.Public
access_check_objectgroupsio_mailing_list:{uid}
access_check_relationviewer
history_check_objectgroupsio_mailing_list:{uid}
history_check_relationauditor
sort_nametitle falling back to group_name
name_and_aliasestitle, group_name (non-empty values)
fulltextspace-joined non-empty values of title, group_name, description

Parent References

RefCondition
groupsio_service:{service_uid}Always set
project:{project_uid}Only when project_uid is set
committee:{uid}One per associated committee (when committees is non-empty)

Reverse Index

After a successful update, the handler writes a reverse index to v1-mappings:

  • Key: groupsio-subgroup-gid.{group_id} → Value: {uid}

This allows the member and artifact handlers to resolve the mailing list UID from the Groups.io numeric group_id.


GroupsIO Mailing List Settings

Object type: groupsio_mailing_list_settings

Source struct: internal/domain/model/grpsio_mailing_list.goGroupsIOMailingListSettings

NATS subject: lfx.index.groupsio_mailing_list_settings

Indexed on: create/update of a GroupsIO mailing list when writers or auditors are present. Settings share the same UID as their parent mailing list.

Data Schema

FieldTypeDescription
uidstringMailing list UID (same as the parent mailing list)
writers[]objectUsers with write access. Each object has username (string, holds the user ID)
auditors[]objectUsers with audit access. Each object has username (string, holds the user ID)
last_reviewed_atstring (optional)RFC3339 timestamp of the last membership review
last_reviewed_bystring (optional)UID of who performed the last review
last_audited_bystring (optional)UID of who performed the last audit
last_audited_timestring (optional)RFC3339 timestamp of the last audit
created_attimestampCreation time (RFC3339)
updated_attimestampLast update time (RFC3339)

v1-sync build note: buildMailingListSettings only populates uid, writers, and auditors. The optional review/audit fields and created_at/updated_at will be at Go zero values (0001-01-01T00:00:00Z for timestamps, null for optional strings).

Tags

Tag FormatExamplePurpose
{uid}abc123Direct lookup by UID
mailing_list_uid:{uid}mailing_list_uid:abc123Namespaced lookup by UID

Search Behavior (IndexingConfig)

FieldValue
object_id{uid}
access_check_objectgroupsio_mailing_list:{uid}
access_check_relationauditor
history_check_objectgroupsio_mailing_list:{uid}
history_check_relationauditor

Parent References

RefCondition
groupsio_mailing_list:{uid}Always set (uid is the parent mailing list UID)

GroupsIO Member

Object type: groupsio_member

Source struct: internal/domain/model/grpsio_member.goGrpsIOMember

NATS subject: lfx.index.groupsio_member

Indexed on: create, update, delete of a GroupsIO mailing list member (v1 datastream via datastream_member_handler.go).

Data Schema

FieldTypeDescription
uidstringMember unique identifier
mailing_list_uidstringUID of the parent mailing list (resolved from group_id reverse index)
member_idint64 (optional)Groups.io numeric member ID
group_idint64 (optional)Groups.io numeric group ID
sourcestringSource system identifier; always "v1-sync" for v1 datastream records
user_idstring (optional)User-service ID; omitted when empty
usernamestringGroups.io username (LFID); emitted as empty string when not populated
first_namestringFirst name (split from full_name); emitted as empty string when not populated
last_namestringLast name (split from full_name); emitted as empty string when not populated
emailstringMember email address (RFC 5322); emitted as empty string when not populated
organizationstringMember's organization; emitted as empty string when not populated
job_titlestringMember's job title; emitted as empty string when not populated
groups_emailstring (optional)Lowercase email as recorded by Groups.io; omitted when empty
groups_full_namestring (optional)Lowercase full name as recorded by Groups.io; omitted when empty
committee_emailstring (optional)Lowercase email from committee service; omitted when empty
committee_full_namestring (optional)Lowercase full name from committee service; omitted when empty
committee_idstring (optional)Committee UID if member belongs to a committee; omitted when empty
rolestring (optional)Role within the committee; omitted when empty
voting_statusstring (optional)Voting status (e.g. Voting Rep, Non-Voting); omitted when empty
member_typestringcommittee or direct; emitted as empty string when not populated
delivery_modestringEmail delivery preference; emitted as empty string when not populated
delivery_mode_liststring (optional)Delivery mode as reported by Groups.io; omitted when empty
mod_statusstringModeration status: none, moderator, or owner; emitted as empty string when not populated
statusstringGroups.io membership status (e.g. normal, pending); emitted as empty string when not populated
last_reviewed_atstring or nullRFC3339 timestamp of the last review; emitted as null when not set (not omitted)
last_reviewed_bystring or nullUID of who performed the last review; emitted as null when not set (not omitted)
project_uidstring (optional)v2 UID of the owning project (inherited from parent mailing list); omitted when empty
project_slugstring (optional)URL slug of the owning project (fetched via lfx.projects-api.get_slug); omitted when empty
created_attimestampCreation time (RFC3339)
updated_attimestampLast update time (RFC3339)
system_updated_attimestamp (optional)Last modified by a system process

v1-sync note: project_uid and project_slug are resolved by the subgroup handler (written to groupsio-subgroup-project.{subgroup_uid}) and read by the member handler before indexing. The member handler NAKs if the project mapping is absent, ensuring the subgroup is fully processed first.

Tags

Tag FormatExamplePurpose
{uid}abc123Direct lookup by UID
member_uid:{uid}member_uid:abc123Namespaced lookup by UID
mailing_list_uid:{value}mailing_list_uid:xyz789Find members of a mailing list
username:{value}username:jdoeFind members by username
email:{value}email:jdoe@example.comFind members by email
status:{value}status:normalFind members by Groups.io status
project_uid:{value}project_uid:bb4ed8c8-...Find members belonging to a project

Tags for username, email, status, and project_uid are only emitted when the value is non-empty.

Access Control (AccessMessage)

When a member has a non-empty username, the handler also publishes an FGA membership message:

  • Put member: lfx.fga-sync.member_put on create/update
  • Remove member: lfx.fga-sync.member_remove on delete

The message is a GenericFGAMessage with object_type: groupsio_mailing_list, operation: member_put / member_remove, and a FGAMemberPutData payload containing uid (the mailing list UID), username (principal), and relations: ["member"].

Username transform: The username field in this FGA payload is not the raw Groups.io/LFID username. It is the principal value derived via principal.FromUsername(member.Username), which produces an Auth0-style subject (e.g. auth0|...). Downstream FGA consumers should expect this format.

Search Behavior (IndexingConfig)

FieldValue
object_id{uid}
access_check_objectgroupsio_mailing_list:{mailing_list_uid}
access_check_relationviewer
history_check_objectgroupsio_mailing_list:{mailing_list_uid}
history_check_relationauditor
sort_namelast_name + ", " + first_name, falling back to last_name, first_name, or username
name_and_aliasesfull name (first_name + " " + last_name), username, email (non-empty values)
fulltextspace-joined non-empty values of first_name, last_name, email, organization, job_title

Parent References

RefCondition
groupsio_mailing_list:{mailing_list_uid}Always set
project:{project_uid}Only when project_uid is set

GroupsIO Artifact

Object type: groupsio_artifact

Source struct: internal/domain/model/grpsio_artifact.goGroupsIOArtifact

NATS subject: lfx.index.groupsio_artifact

Indexed on: create, update, delete of a GroupsIO subgroup artifact (v1 datastream via datastream_artifact_handler.go).

Data Schema

FieldTypeDescription
artifact_idstringArtifact unique identifier
group_iduint64Groups.io numeric group ID
project_uidstring (optional)v2 UID of the owning project (resolved from v1 SFID)
committee_uidstring (optional)v2 UID of the associated committee (resolved from v1 SFID)
typestring (optional)Artifact type (e.g. file, link)
media_typestring (optional)MIME type of the file
filenamestring (optional)Filename of the artifact
link_urlstring (optional)URL for link-type artifacts
download_urlstring (optional)Groups.io download URL
s3_keystring (optional)S3 object key
file_uploadedbool (optional)Whether the file has been uploaded; omitted for link-type artifacts
file_upload_statusstring (optional)Upload status (e.g. completed)
file_uploaded_attimestamp (optional)When the file was uploaded
message_ids[]uint64 (optional)IDs of associated Groups.io messages; not populated by transformV1ToGroupsIOArtifact — omitted from v1-sync payloads
last_posted_attimestamp (optional)When the artifact was last posted
last_posted_message_iduint64 (optional)ID of the last posted message; not populated by transformV1ToGroupsIOArtifact — omitted from v1-sync payloads
descriptionstring (optional)Artifact description
created_byobject (optional)User who created the artifact (id, username, name, email, profile_picture); not populated by transformV1ToGroupsIOArtifact — omitted from v1-sync payloads
last_modified_byobject (optional)User who last modified the artifact; not populated by transformV1ToGroupsIOArtifact — omitted from v1-sync payloads
created_attimestampCreation time (RFC3339)
updated_attimestampLast update time (RFC3339)

Tags

Tag FormatExamplePurpose
{artifact_id}a323373e-...Direct lookup by artifact ID
group_artifact_id:{artifact_id}group_artifact_id:a323373e-...Namespaced lookup by artifact ID
group_id:{value}group_id:118856Find artifacts for a Groups.io group
project_uid:{value}project_uid:bb4ed8c8-...Find artifacts for a project
committee_uid:{value}committee_uid:061a110a-...Find artifacts for a committee

project_uid and committee_uid tags are only emitted when the value is non-empty.

Access Control (IndexingConfig)

Artifacts use a typed IndexingConfig. No FGA AccessMessage is published — access is checked at query time via the indexing config.

FieldValue
object_id{artifact_id}
publicfalse (always)
access_check_objectgroupsio_mailing_list:{mailing_list_uid}
access_check_relationviewer
history_check_objectgroupsio_mailing_list:{mailing_list_uid}
history_check_relationauditor

Search Behavior

FieldValue
fulltextfilename (or link_url) + + description
name_and_aliasesfilename, link_url (non-empty values only)
sort_namefilename if set, otherwise link_url
publicfalse (always)

Parent References

RefCondition
project:{project_uid}Only when project_uid is set
committee:{committee_uid}Only when committee_uid is set
groupsio_mailing_list:{group_id}Always set (numeric Groups.io group ID — the artifact model does not carry a mailing list UID)