feat: GraphQL API Layer with Lighthouse PHP (#13)#31
Closed
Conversation
added 8 commits
March 15, 2026 16:09
- Install nuwave/lighthouse ^6.65 and mll-lab/laravel-graphiql ^4.0 (dev) - Publish lighthouse config with Sanctum guard + AttemptAuthentication middleware - Scaffold graphql/schema.graphql with Space, Content, ContentVersion, ContentType types - Public queries: contentBySlug, contents (no @guard) - Authenticated queries: space, spaces, content, contentTypes, contentVersion (@guard) - Create resolver classes: ContentBySlugQuery, ContentsQuery, ContentTypesQuery, SpaceContentsQuery - JSON and DateTime scalars defined - pint --test: pass, phpstan analyse --level=5: pass
- Add enums: ContentStatus, BriefStatus, PipelineRunStatus, MediaSource - Add cursor pagination connections: PipelineRunConnection, ContentBriefConnection, MediaAssetConnection, PageConnection with PageInfo - Add types: Persona (system_prompt excluded), ContentPipeline, PipelineRun, ContentBrief, MediaAsset, Vocabulary, TaxonomyTerm, Webhook, Page, PageComponent, ContentBlock - Add queries: personas, pipelines, pipelineRun, mediaAssets, vocabularies, briefs, webhooks (all @guard), pages (public) - Add resolver classes for each new query
- Add Mutation type to graphql/schema.graphql with 12 mutations: createContent, updateContent, publishContent, unpublishContent, deleteContent, createBrief, updateBrief, triggerPipeline, approvePipelineRun, rejectPipelineRun, updateMediaAsset, deleteMediaAsset - Define input types: CreateContentInput, UpdateContentInput, CreateBriefInput, UpdateBriefInput, UpdateMediaAssetInput - Create 12 resolver classes in app/GraphQL/Mutations/: - CreateContent: creates Content + initial ContentVersion, syncs taxonomy terms - UpdateContent: creates new version on title/body change, patches content fields - PublishContent / UnpublishContent: delegates to Content::publish() - DeleteContent: soft delete via SoftDeletes trait - CreateBrief: creates ContentBrief, triggers active pipeline via PipelineExecutor - UpdateBrief: patches brief fields - TriggerPipeline: dispatches PipelineExecutor::start with optional existing content - ApprovePipelineRun / RejectPipelineRun: mirrors PipelineAdminController logic - UpdateMediaAsset / DeleteMediaAsset: CRUD on media metadata - All mutations use AuthorizationService::authorize() for permission checks - All mutations write AuditLog entries via AuthorizationService::log() - All mutations protected by @guard directive (Lighthouse Sanctum)
- Add @with directives on all frequently-accessed relationships: - Content: space, contentType, currentVersion, draftVersion, heroImage, taxonomyTerms - ContentVersion: content, blocks - PipelineRun: pipeline, content - Space: contentTypes - ContentPipeline: space - ContentBrief, MediaAsset, Vocabulary, Persona, Webhook, Page, PageComponent, ContentBlock - Add @Complexity(resolver: PaginatedComplexity) on all paginated fields: - contents, spaces contents, pipelines runs, mediaAssets, briefs, pages - Add @can directives on all mutations for policy-gated operations: - createContent, updateContent, publishContent, unpublishContent, deleteContent - createBrief, updateBrief, triggerPipeline, approvePipelineRun, rejectPipelineRun - updateMediaAsset, deleteMediaAsset - Create PaginatedComplexity resolver: complexity = childComplexity * first - Update config/lighthouse.php: - max_query_complexity: 500 (env: LIGHTHOUSE_MAX_COMPLEXITY) - max_query_depth: 10 (env: LIGHTHOUSE_MAX_DEPTH) - pagination default_count: 20, max_count: 100 - batchload_relations already enabled
- Add Subscription type to schema with 4 fields: contentPublished(spaceId), contentUpdated(contentId), pipelineRunUpdated(runId), pipelineRunCompleted(spaceId) - Add subscription resolvers with authorize() + filter() in app/GraphQL/Subscriptions/ - Add domain events: ContentPublishedEvent, PipelineRunUpdatedEvent - Wire events into PublishContent and ApprovePipelineRun mutations - Register EventServiceProvider that broadcasts via Lighthouse Subscription::broadcast() - Configure lighthouse.php: default broadcaster=log, storage=array (dev-safe)
…ware - Enable APQ (persisted_queries) with env override LIGHTHOUSE_PERSISTED_QUERIES - Configure query cache store to use 'file' in dev, 'redis' in production - Add App\GraphQL\Middleware namespace to directives lookup in lighthouse.php - Register CostTrackingMiddleware in field_middleware array - Create CostTrackingMiddleware: tracks field, query_hash, complexity_score, execution_time_ms, user_id per field resolution via Log::debug - Add @cache(maxAge: 30) to contentBySlug and content queries - Add @cache(maxAge: 60) to contents list and pages list queries - Add @cache(maxAge: 300) to contentTypes, vocabularies, Space.contentTypes, and Vocabulary.terms (stable references that rarely change) - Pipeline-related fields have no @cache (real-time data)
- GraphQLQueryTest: 9 tests covering spaces, content by slug, cursor pagination, auth guard, admin queries, eager loading, personas (security: no system_prompt), media assets, taxonomies - GraphQLMutationTest: 6 tests covering create/publish/delete content, trigger pipeline (Queue::fake), unauthorized user, input validation - GraphQLSubscriptionTest: 2 schema-level tests verifying subscription types are defined (contentPublished, pipelineRunUpdated, etc.) - PaginatedComplexityTest: 5 unit tests for complexity resolver Supporting fixes: - Add ContentPipelinePolicy with admin bypass + trigger/approve/create - Add global Gate::before admin bypass in AppServiceProvider - Register SubscriptionServiceProvider in bootstrap/providers.php - Add PAUSED_FOR_REVIEW to PipelineRunStatus enum in schema
Contributor
Author
|
Already merged to dev via squash. Closing stale PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This PR implements the GraphQL API Layer for Numen, powered by Lighthouse PHP.
Changes
Quality & Testing
Implementation Details
Related