Files
Nexus.Reader/src/.documentation/cache/summaries/NexusReader.Data__Migrations__20260503175906_FinalNormalizedSubscriptionArchitecture.cs.json
T
2026-05-25 14:02:56 +02:00

1 line
13 KiB
JSON

{"path":"NexusReader.Data/Migrations/20260503175906_FinalNormalizedSubscriptionArchitecture.cs","purpose":"EF Core migration that alters database schema to introduce normalized subscription plans, tenant scoping, vector columns (pgvector), and related knowledge unit tables; also seeds subscription plan rows.","classification":{"role":"database-config","layer":"data","confidence":0.92,"evidence":["Class inherits Microsoft.EntityFrameworkCore.Migrations.Migration","Uses MigrationBuilder to AlterDatabase, CreateTable, CreateIndex, InsertData and AddForeignKey","Namespace NexusReader.Data.Migrations and filename indicates a migration"]},"className":"FinalNormalizedSubscriptionArchitecture","methods":[{"name":"Up","line":16,"endLine":268,"signature":"(migrationBuilder: MigrationBuilder) -> void","purpose":"Apply schema changes: remove/alter columns, add tenant and vector columns, create KnowledgeUnits/SubscriptionPlans/KnowledgeUnitLinks tables, seed SubscriptionPlans, create indexes and add foreign key.","calls":[],"actions":[{"id":"drop-column_18","kind":"mapping","label":"Drop CurrentPlan from AspNetUsers","line":18,"detail":"migrationBuilder.DropColumn(name: \"CurrentPlan\", table: \"AspNetUsers\")","visibility":"detail-only","confidence":0.7},{"id":"alter-database_22","kind":"mapping","label":"Enable pgvector extension annotation","line":22,"detail":"migrationBuilder.AlterDatabase().Annotation(\"Npgsql:PostgresExtension:vector\", \",,\")","visibility":"detail-only","confidence":0.7},{"id":"alter-column_25","kind":"mapping","label":"Convert CreatedAt in SemanticKnowledgeCache to timestamptz","line":25,"detail":"AlterColumn<DateTime> to type \"timestamp with time zone\"","visibility":"detail-only","confidence":0.7},{"id":"add-column_33","kind":"mapping","label":"Add OriginalText to SemanticKnowledgeCache","line":33,"detail":"AddColumn<string>(name: \"OriginalText\", table: \"SemanticKnowledgeCache\")","visibility":"detail-only","confidence":0.7},{"id":"add-column_40","kind":"mapping","label":"Add TenantId to SemanticKnowledgeCache","line":40,"detail":"AddColumn<string>(name: \"TenantId\", maxLength:128)","visibility":"detail-only","confidence":0.7},{"id":"add-column_48","kind":"mapping","label":"Add Vector column (pgvector) to SemanticKnowledgeCache","line":48,"detail":"AddColumn<Vector>(name: \"Vector\", type: \"vector(1536)\")","visibility":"detail-only","confidence":0.7},{"id":"alter-column_54","kind":"mapping","label":"Convert CompletedDate in QuizResults to timestamptz","line":54,"detail":"AlterColumn<DateTime> to type \"timestamp with time zone\"","visibility":"detail-only","confidence":0.7},{"id":"add-column_62","kind":"mapping","label":"Add TenantId to QuizResults","line":62,"detail":"AddColumn<string>(name: \"TenantId\", maxLength:128)","visibility":"detail-only","confidence":0.7},{"id":"alter-column_70","kind":"mapping","label":"Convert date columns in Ebooks to timestamptz","line":70,"detail":"Alter LastReadDate and AddedDate to timestamptz","visibility":"detail-only","confidence":0.7},{"id":"add-column_87","kind":"mapping","label":"Add TenantId to Ebooks","line":87,"detail":"AddColumn<string>(name: \"TenantId\", maxLength:128)","visibility":"detail-only","confidence":0.7},{"id":"alter-column_95","kind":"mapping","label":"Change AspNetUsers.TenantId from Guid(uuid) to string(128)","line":95,"detail":"AlterColumn<string>(name: \"TenantId\", maxLength:128)","visibility":"detail-only","confidence":0.7},{"id":"add-column_104","kind":"mapping","label":"Add DisplayName to AspNetUsers","line":104,"detail":"AddColumn<string>(name: \"DisplayName\", maxLength:100)","visibility":"detail-only","confidence":0.7},{"id":"add-column_111","kind":"mapping","label":"Add LastAiActionDate to AspNetUsers","line":111,"detail":"AddColumn<DateTime?>(name: \"LastAiActionDate\")","visibility":"detail-only","confidence":0.7},{"id":"add-column_117","kind":"mapping","label":"Add LastReadAt and LastReadPageId to AspNetUsers","line":117,"detail":"AddColumn<DateTime?>(name: \"LastReadAt\"); AddColumn<string>(name: \"LastReadPageId\", maxLength:255)","visibility":"detail-only","confidence":0.7},{"id":"add-column_130","kind":"mapping","label":"Add SubscriptionPlanId integer to AspNetUsers with default 1","line":130,"detail":"AddColumn<int>(name: \"SubscriptionPlanId\", defaultValue:1)","visibility":"detail-only","confidence":0.7},{"id":"create-table_137","kind":"mapping","label":"Create KnowledgeUnits table","line":137,"detail":"Creates columns Id, SourceId, Version, Type, Content, MetadataJson, TenantId, Vector(vector(768)), CreatedAt and primary key on Id","visibility":"detail-only","confidence":0.7},{"id":"create-table_156","kind":"mapping","label":"Create SubscriptionPlans table","line":156,"detail":"Creates Id (identity), PlanName, AITokenLimit, MonthlyPrice, StripeProductId and primary key on Id","visibility":"detail-only","confidence":0.7},{"id":"create-table_172","kind":"mapping","label":"Create KnowledgeUnitLinks table with FKs to KnowledgeUnits","line":172,"detail":"Creates Id (identity), SourceUnitId, TargetUnitId, RelationType and FKs referencing KnowledgeUnits(Id) with cascade delete","visibility":"detail-only","confidence":0.7},{"id":"insert-data_199","kind":"mapping","label":"Seed SubscriptionPlans rows (Free, Basic, Pro, Enterprise)","line":199,"detail":"migrationBuilder.InsertData into SubscriptionPlans with four predefined plans and token/price values","visibility":"detail-only","confidence":0.7},{"id":"create-index_210","kind":"mapping","label":"Create TenantId indexes on multiple tables","line":210,"detail":"Creates indexes: SemanticKnowledgeCache.TenantId, QuizResults.TenantId, Ebooks.TenantId, AspNetUsers.TenantId, plus others for knowledge units and plan name","visibility":"detail-only","confidence":0.7},{"id":"create-index_225","kind":"mapping","label":"Create index for AspNetUsers.SubscriptionPlanId","line":225,"detail":"Index on AspNetUsers.SubscriptionPlanId","visibility":"detail-only","confidence":0.7},{"id":"add-foreign-key_261","kind":"mapping","label":"Link AspNetUsers.SubscriptionPlanId -> SubscriptionPlans.Id (Restrict)","line":261,"detail":"migrationBuilder.AddForeignKey(name: \"FK_AspNetUsers_SubscriptionPlans_SubscriptionPlanId\", onDelete: ReferentialAction.Restrict)","visibility":"detail-only","confidence":0.7}]},{"name":"Down","line":271,"endLine":397,"signature":"(migrationBuilder: MigrationBuilder) -> void","purpose":"Revert schema changes performed in Up: drop created tables, indexes, columns and restore previous column types/values and the dropped CurrentPlan column.","calls":[],"actions":[{"id":"drop-foreign-key_273","kind":"mapping","label":"Remove FK AspNetUsers -> SubscriptionPlans","line":273,"detail":"migrationBuilder.DropForeignKey(name: \"FK_AspNetUsers_SubscriptionPlans_SubscriptionPlanId\")","visibility":"detail-only","confidence":0.7},{"id":"drop-table_277","kind":"mapping","label":"Drop KnowledgeUnitLinks table","line":277,"detail":"migrationBuilder.DropTable(name: \"KnowledgeUnitLinks\")","visibility":"detail-only","confidence":0.7},{"id":"drop-table_280","kind":"mapping","label":"Drop SubscriptionPlans table","line":280,"detail":"migrationBuilder.DropTable(name: \"SubscriptionPlans\")","visibility":"detail-only","confidence":0.7},{"id":"drop-table_283","kind":"mapping","label":"Drop KnowledgeUnits table","line":283,"detail":"migrationBuilder.DropTable(name: \"KnowledgeUnits\")","visibility":"detail-only","confidence":0.7},{"id":"drop-index_286","kind":"mapping","label":"Drop TenantId and related indexes","line":286,"detail":"Drop indexes created in Up (SemanticKnowledgeCache_TenantId, QuizResults_TenantId, etc.)","visibility":"detail-only","confidence":0.7},{"id":"drop-column_306","kind":"mapping","label":"Remove added columns from SemanticKnowledgeCache, QuizResults, Ebooks, AspNetUsers","line":306,"detail":"Drop OriginalText, TenantId, Vector, TenantId (QuizResults/Ebooks), DisplayName, LastAiActionDate, LastReadAt, LastReadPageId, SubscriptionPlanId","visibility":"detail-only","confidence":0.7},{"id":"alter-database_346","kind":"mapping","label":"Remove pgvector extension annotation","line":346,"detail":"migrationBuilder.AlterDatabase().OldAnnotation(\"Npgsql:PostgresExtension:vector\", \",,\")","visibility":"detail-only","confidence":0.7},{"id":"alter-column_349","kind":"mapping","label":"Revert timestamp columns back to without time zone","line":349,"detail":"AlterColumn<DateTime> to type \"timestamp without time zone\" for multiple columns","visibility":"detail-only","confidence":0.7},{"id":"alter-column_382","kind":"mapping","label":"Revert AspNetUsers.TenantId back to Guid/uuid","line":382,"detail":"AlterColumn<Guid>(name: \"TenantId\", type:\"uuid\")","visibility":"detail-only","confidence":0.7},{"id":"add-column_391","kind":"mapping","label":"Restore CurrentPlan on AspNetUsers","line":391,"detail":"AddColumn<string>(name: \"CurrentPlan\", table: \"AspNetUsers\")","visibility":"detail-only","confidence":0.7}]}],"types":[{"name":"KnowledgeUnits (table)","kind":"entity","line":137,"purpose":"Stores normalized knowledge unit records with tenant scoping and vector embedding for semantic search.","fields":[{"name":"Id","type":"string(128)","required":true,"line":141,"description":"Primary key"},{"name":"SourceId","type":"string(128)","required":true,"line":142,"description":"Identifier of the originating source"},{"name":"Version","type":"string(50)","required":true,"line":143,"description":"Source version"},{"name":"Type","type":"int","required":true,"line":144,"description":"Enumerated knowledge unit type"},{"name":"Content","type":"text","required":true,"line":145,"description":"Main text content"},{"name":"MetadataJson","type":"text","required":false,"line":146,"description":"Optional JSON metadata"},{"name":"TenantId","type":"string(128)","required":true,"line":147,"description":"Tenant scoping id"},{"name":"Vector","type":"vector(768)","required":false,"line":148,"description":"Embedding vector for semantic search (pgvector)"},{"name":"CreatedAt","type":"timestamp with time zone","required":true,"line":149,"description":"Creation timestamp"}]},{"name":"SubscriptionPlans (table)","kind":"entity","line":156,"purpose":"Represents normalized subscription plans with token limits, pricing and Stripe product mapping.","fields":[{"name":"Id","type":"int (identity)","required":true,"line":160,"description":"Primary key (identity)"},{"name":"PlanName","type":"string(50)","required":true,"line":162,"description":"Unique plan name"},{"name":"AITokenLimit","type":"int","required":true,"line":163,"description":"Token limit for AI usage"},{"name":"MonthlyPrice","type":"decimal","required":true,"line":164,"description":"Monthly price"},{"name":"StripeProductId","type":"string(50)","required":true,"line":165,"description":"Stripe product mapping id"}]},{"name":"KnowledgeUnitLinks (table)","kind":"entity","line":172,"purpose":"Associative links between knowledge units to model relations; enforces FK constraints to KnowledgeUnits.","fields":[{"name":"Id","type":"int (identity)","required":true,"line":176,"description":"Primary key"},{"name":"SourceUnitId","type":"string(128)","required":true,"line":178,"description":"FK to KnowledgeUnits.Id (source)"},{"name":"TargetUnitId","type":"string(128)","required":true,"line":179,"description":"FK to KnowledgeUnits.Id (target)"},{"name":"RelationType","type":"string(50)","required":true,"line":180,"description":"Type of relation between units"}]}],"serviceRegistrations":[],"startupActions":[],"dependencies":[],"patterns":["EF Core Migration","Schema Migration","Seed Data"],"domainConcepts":["SubscriptionPlan","KnowledgeUnit","Tenant","Vector Embeddings"],"keyDetails":"Adds pgvector extension usage and vector columns (1536 and 768 dims), migrates several dates to timestamptz, normalizes subscriptions into a SubscriptionPlans table seeded with Free/Basic/Pro/Enterprise, introduces tenant scoping columns across multiple tables and creates knowledge unit/link tables with FK constraints.","orchestrationMethods":[],"typedContracts":[{"name":"KnowledgeUnits (table)","kind":"entity","line":137,"fieldCount":9,"evidencePaths":["NexusReader.Data/Migrations/20260503175906_FinalNormalizedSubscriptionArchitecture.cs"]},{"name":"SubscriptionPlans (table)","kind":"entity","line":156,"fieldCount":5,"evidencePaths":["NexusReader.Data/Migrations/20260503175906_FinalNormalizedSubscriptionArchitecture.cs"]},{"name":"KnowledgeUnitLinks (table)","kind":"entity","line":172,"fieldCount":4,"evidencePaths":["NexusReader.Data/Migrations/20260503175906_FinalNormalizedSubscriptionArchitecture.cs"]}],"persistenceInteractions":[],"externalInteractions":[],"evidenceAnchors":[{"kind":"typed-contract","label":"KnowledgeUnits (table)","line":137,"summary":"entity with 9 fields.","confidence":0.8,"evidencePaths":["NexusReader.Data/Migrations/20260503175906_FinalNormalizedSubscriptionArchitecture.cs"]},{"kind":"typed-contract","label":"SubscriptionPlans (table)","line":156,"summary":"entity with 5 fields.","confidence":0.8,"evidencePaths":["NexusReader.Data/Migrations/20260503175906_FinalNormalizedSubscriptionArchitecture.cs"]},{"kind":"typed-contract","label":"KnowledgeUnitLinks (table)","line":172,"summary":"entity with 4 fields.","confidence":0.8,"evidencePaths":["NexusReader.Data/Migrations/20260503175906_FinalNormalizedSubscriptionArchitecture.cs"]}],"cacheMetadata":{"schemaVersion":2,"analysisVersion":"2026-05-23.cache-v1","contentChecksum":"9fa8b87abf4cadae807d24d3f2f91d399c913e2dfcfffd0fea3bf6bbc5b7d8e6","sourceByteSize":15875,"analyzedAt":"2026-05-23T16:24:21.965Z","technology":"dotnet"}}