GraphQL

Pagination

List fields are Relay connections. Use first/after or last/before, read pageInfo, and do not treat a single page as the full set.

Every has_many relation in the GraphQL schema is a Relay connection. The list field accepts first, after, last, and before. The result has nodes, edges, pageInfo, and totalCount.

query Rfis($organizationId: ID!, $projectId: ID!, $after: String) {
  organization(id: $organizationId) {
    project(id: $projectId) {
      rfis(first: 50, after: $after) {
        totalCount
        nodes {
          id
          number
          subject
          status
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
    }
  }
}

PageInfo

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

Walk forward with first + after: pageInfo.endCursor while hasNextPage is true. Walk backward with last + before: pageInfo.startCursor while hasPreviousPage is true.

totalCount is the full filtered set, not the page size. Use it to know when you still have pages left, but still follow pageInfo rather than counting nodes yourself.

Edges

edges is the Relay edge list (cursor + node). Prefer nodes unless you need per-item cursors.

Project search is also a connection:

query Search($organizationId: ID!, $projectId: ID!, $query: String!) {
  organization(id: $organizationId) {
    project(id: $projectId) {
      search(query: $query, first: 25) {
        totalCount
        nodes {
          id
          type
          typeDisplayName
          title
          path
          sanitizedHeadline
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
    }
  }
}

search is indexed project content (drawings, documents, submittals, specs, and other searchable records). It is not a substitute for listing a single type with rfis / submittals / and so on.

Completeness

Do not report a total or an "all records" answer from the first page. Loop until hasNextPage is false, or stop after a documented cap and say the result is partial.