Add locationId to Credits usage event GraphQL type
What does this MR do and why?
GitlabSubscriptionUsageUserEvent#location resolves a Credits usage event's project
or group through a batch loader. When that record has been deleted — or the viewer
cannot see it — the field resolves to null, and the raw reference the historical
billing event still carries becomes invisible to API consumers. A valid credit charge
then looks unattributable.
This MR adds locationId, a Global ID returned regardless of whether the record
resolves. It follows the same project-over-namespace precedence as #location, so
the two fields always describe the same record.
Why clients can safely branch on this
location is a Project | Group union, and both members carry type-level
authorization (read_project / read_group). When the viewer lacks access, GraphQL
nulls the field out before any resolver code could observe why — so the backend
cannot cheaply distinguish "deleted" from "not visible".
That is deliberate here. Clients can read location == null && locationId != null as
a single state covering both causes, without the backend duplicating a permission
check or disclosing which of the two applies. This matches how GitLab answers 404
rather than 403 for records the viewer may not be allowed to know about.
Split from the frontend change
Per the multiversion compatibility guidance,
this backend-only MR must be merged and deployed before the frontend consumes the
field. @gl_introduced covers GitLab Self-Managed but
explicitly does not mitigate the GitLab.com canary window.
The frontend follow-up is !249076 (closed).
References
Screenshots or screen recordings
No user-visible change in this MR — it only adds a GraphQL field. The UI change and its screenshots are in the frontend follow-up.
How to set up and validate locally
query {
subscriptionUsage(namespacePath: "<group>") {
usersUsage {
users(username: "<username>") {
nodes {
events {
nodes {
location { __typename ... on Project { id name } ... on Group { id name } }
locationId
}
}
}
}
}
}
}locationId is populated for every event that carries a project_id or
namespace_id, including events whose location comes back null.
MR acceptance checklist
- Unit tests cover the three
#location_idbranches: project ID present, only a namespace ID, and neither. - Request specs cover a resolvable project, a deleted project, an inaccessible private project, and a deleted group.
-
doc/api/graphql/reference/_index.mdandpublic/-/graphql/introspection_result.jsonregenerated for the new field. - No feature flag: the field is additive and cannot change an existing response.
- No database or migration changes.