.cursor/rules/docs/docs-graphql/RULE.md
The apps/docs/resources folder contains the GraphQL endpoint architecture for the docs GraphQL endpoint at /api/graphql. It follows a modular pattern where each top-level query is organized into its own folder with consistent file structure.
Each GraphQL query follows this structure:
resources/
├── queryObject/
│ ├── queryObjectModel.ts # Data models and business logic
│ ├── queryObjectSchema.ts # GraphQL type definitions
│ ├── queryObjectResolver.ts # Query resolver and arguments
│ ├── queryObjectTypes.ts # TypeScript interfaces (optional)
│ └── queryObjectSync.ts # Functions for syncing repo content to the database (optional)
├── utils/
│ ├── connections.ts # GraphQL connection/pagination utilities
│ └── fields.ts # GraphQL field selection utilities
├── rootSchema.ts # Main GraphQL schema with all queries
└── rootSync.ts # Root sync script for syncing to database
globalSearch/) - Vector-based search across all docs contenterror/) - Error code lookup for Supabase servicesrootSchema.tsRootQueryType with all top-level fieldsutils/connections.tscreateCollectionType() for paginated collectionsGraphQLCollectionBuilder for building collection responsesutils/fields.tsgraphQLFields() utility to analyze requested fields in resolversTo add a new GraphQL query, follow these steps:
mkdir resources/newQuery
touch resources/newQuery/newQueryModel.ts
touch resources/newQuery/newQuerySchema.ts
touch resources/newQuery/newQueryResolver.ts
newQuerySchema.ts)import { GraphQLObjectType, GraphQLString } from 'graphql'
export const GRAPHQL_FIELD_NEW_QUERY = 'newQuery' as const
export const GraphQLObjectTypeNewQuery = new GraphQLObjectType({
name: 'NewQuery',
description: 'Description of what this query returns',
fields: {
id: {
type: GraphQLString,
description: 'Unique identifier',
},
// Add other fields...
},
})
newQueryModel.ts)[!NOTE] The data model should be agnostic to GraphQL. It may import argument types from
~/__generated__/graphql, but otherwise all functions and classes should be unaware of whether they are called for GraphQL resolution.
[!TIP] The types in
~/__generated__/graphqlfor a new endpoint will not exist until the code generation is run in the next step.
import { type RootQueryTypeNewQueryArgs } from '~/__generated__/graphql'
import { convertPostgrestToApiError, type ApiErrorGeneric } from '~/app/api/utils'
import { Result } from '~/features/helpers.fn'
import { supabase } from '~/lib/supabase'
export class NewQueryModel {
constructor(
public readonly data: {
id: string
// other properties...
}
) {}
static async loadData(
args: RootQueryTypeNewQueryArgs,
requestedFields: Array<string>
): Promise<Result<NewQueryModel[], ApiErrorGeneric>> {
// Implement data fetching logic
const result = new Result(
await supabase()
.from('your_table')
.select('*')
// Add filters based on args
)
.map((data) => data.map((item) => new NewQueryModel(item)))
.mapError(convertPostgrestToApiError)
return result
}
}