feat: add OpenAI Projects as first-class assets (Phase 1)#31
Open
feat: add OpenAI Projects as first-class assets (Phase 1)#31
Conversation
- VARCHAR(32) DEFAULT 'gpt' — supports 'gpt' | 'project' - conversation_count + last_conversation_at placeholder columns for Phase 2 - Index ix_gpts_asset_type on asset_type - GPT model + GPTRead schema updated with asset_type field Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract _fetch_paginated() helper: DRY pagination logic shared by GPTs and Projects - Add fetch_all_projects() on ComplianceAPIClient using the /projects endpoint - Add _normalize_project() static method: flattens Projects API envelope, handles nested/flat latest_config variants, always sets asset_type='project' - Add fetch_all_projects() to MockComplianceAPIClient with 12 enterprise mock projects (3 tier-3 production, 4 tier-2 functional, 5 tier-1 experimental) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use asyncio.gather(return_exceptions=True) to fetch GPTs and Projects concurrently - GPT fetch failure propagates (required); Projects failure logs a warning and continues with GPTs only (non-fatal — partial results are better than none) - Set asset_type on each GPT row during the store step - Update log messages to say 'assets' instead of 'GPTs' where appropriate Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- types/index.ts: add asset_type field to GPTItem - Overview.tsx: page subtitle shows GPT+Project breakdown; KPI 'Total Assets' card renders a mini SVG ring chart when projects exist - Portal.tsx: [ All ] [ GPTs ] [ Projects ] filter chip appears when the registry contains at least one project (hidden when GPTs only) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers _normalize_project() edge cases (no latest_config, no instructions, nested config variant, unix timestamp conversion), MockComplianceAPIClient project fetch, partial failure handling via asyncio.gather, and end-to-end asset_type propagation through the API. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Summary
asset_type VARCHAR(32) DEFAULT 'gpt'togptstable + index, plusconversation_count/last_conversation_atplaceholder columns for Phase 2_fetch_paginated()DRY helper; addedfetch_all_projects()+_normalize_project()for the/projectsendpointasyncio.gather; Projects fetch failure is non-fatal (logs warning, continues with GPTs only)asset_typepropagated toGPTItemtype; Overview KPI card shows mini SVG ring chart (GPTs vs Projects breakdown); Employee Portal gets[ All ] [ GPTs ] [ Projects ]filter chip (hidden when no projects exist)_normalize_project()edge cases (no config, no instructions, nested config), mock client, partial failure, and API propagationPre-Landing Review
No issues found.
Eval Results
No prompt-related files changed — evals skipped.
Test plan
ruff format --checkpassestsc --noEmitpassesWhat's next
conversation_count+last_conversation_atcolumns already in place from this PR🤖 Generated with Claude Code