From 66b80117b11d36c85ad79d6ed31afdb16e8e7025 Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Tue, 5 May 2026 10:51:11 +0200 Subject: [PATCH] Refactor: remove PayloadCMS, use MDX for content and TSX for design, use direct email for contact --- apps/web/app/(payload)/actions.ts | 13 - .../(payload)/admin/[[...segments]]/page.tsx | 26 - apps/web/app/(payload)/admin/importMap.js | 120 - apps/web/app/(payload)/api/[...slug]/route.ts | 16 - apps/web/app/(payload)/layout.tsx | 20 - apps/web/next.config.mjs | 6 +- apps/web/package.json | 26 +- apps/web/payload.config.ts | 137 - apps/web/src/actions/contact.ts | 21 +- apps/web/src/components/PayloadRichText.tsx | 389 -- apps/web/src/content-engine/definitions.ts | 8 +- ...nforme-insights-ohne-user-ueberwachung.mdx | 10 + .../build-first-digital-architecture.mdx | 6 + .../builder-systems-threaten-independence.mdx | 6 + .../posts/clean-code-for-business-value.mdx | 8 + .../posts/crm-synchronization-headless.mdx | 26 + .../posts/digital-longevity-architecture.mdx | 9 + .../posts/fixed-price-digital-projects.mdx | 6 + .../posts/gdpr-conformity-system-approach.mdx | 21 + ...it-ihr-wichtigster-b2b-umsatzhebel-ist.mdx | 25 + .../posts/green-it-sustainable-web.mdx | 10 + .../hidden-costs-of-wordpress-plugins.mdx | 6 + .../maintenance-for-headless-systems.mdx | 8 + .../content/posts/no-us-cloud-platforms.mdx | 6 + .../posts/professional-hosting-operations.mdx | 15 + .../posts/responsive-design-high-fidelity.mdx | 8 + .../posts/slow-loading-costs-customers.mdx | 6 + .../posts/website-without-cookie-banners.mdx | 13 + .../content/posts/why-agencies-are-slow.mdx | 16 + .../content/posts/why-no-templates-matter.mdx | 6 + .../why-websites-break-after-updates.mdx | 8 + apps/web/src/lib/posts.ts | 79 +- .../20260227_171023_crm_collections.json | 2868 ------------- .../20260227_171023_crm_collections.ts | 392 -- apps/web/src/migrations/20260301_151838.json | 3671 ----------------- apps/web/src/migrations/20260301_151838.ts | 155 - apps/web/src/migrations/index.ts | 15 - .../blocks/ArchitectureBuilderBlock.ts | 22 - .../payload/blocks/ArticleBlockquoteBlock.ts | 53 - .../src/payload/blocks/ArticleMemeBlock.ts | 47 - .../src/payload/blocks/ArticleQuoteBlock.ts | 97 - .../web/src/payload/blocks/BoldNumberBlock.ts | 72 - apps/web/src/payload/blocks/ButtonBlock.ts | 62 - apps/web/src/payload/blocks/CarouselBlock.ts | 51 - .../src/payload/blocks/ComparisonRowBlock.ts | 102 - .../src/payload/blocks/DiagramFlowBlock.ts | 29 - .../src/payload/blocks/DiagramGanttBlock.ts | 29 - .../web/src/payload/blocks/DiagramPieBlock.ts | 29 - .../payload/blocks/DiagramSequenceBlock.ts | 29 - .../src/payload/blocks/DiagramStateBlock.ts | 29 - .../payload/blocks/DiagramTimelineBlock.ts | 29 - .../blocks/DigitalAssetVisualizerBlock.ts | 21 - .../src/payload/blocks/ExternalLinkBlock.ts | 42 - .../web/src/payload/blocks/FAQSectionBlock.ts | 40 - apps/web/src/payload/blocks/H2Block.ts | 24 - apps/web/src/payload/blocks/H3Block.ts | 24 - apps/web/src/payload/blocks/HeadingBlock.ts | 50 - apps/web/src/payload/blocks/IconListBlock.ts | 69 - apps/web/src/payload/blocks/ImageTextBlock.ts | 46 - .../web/src/payload/blocks/LeadMagnetBlock.ts | 81 - .../src/payload/blocks/LeadParagraphBlock.ts | 36 - .../src/payload/blocks/LinkedInEmbedBlock.ts | 22 - .../payload/blocks/LoadTimeSimulatorBlock.ts | 25 - apps/web/src/payload/blocks/MarkerBlock.ts | 45 - apps/web/src/payload/blocks/MemeCardBlock.ts | 51 - apps/web/src/payload/blocks/MermaidBlock.ts | 68 - apps/web/src/payload/blocks/MetricBarBlock.ts | 62 - apps/web/src/payload/blocks/ParagraphBlock.ts | 36 - .../payload/blocks/PerformanceChartBlock.ts | 29 - .../blocks/PerformanceROICalculatorBlock.ts | 34 - .../blocks/PremiumComparisonChartBlock.ts | 108 - apps/web/src/payload/blocks/RevealBlock.ts | 44 - .../blocks/RevenueLossCalculatorBlock.ts | 29 - apps/web/src/payload/blocks/SectionBlock.ts | 36 - .../src/payload/blocks/StatsDisplayBlock.ts | 53 - apps/web/src/payload/blocks/StatsGridBlock.ts | 49 - apps/web/src/payload/blocks/TLDRBlock.ts | 35 - .../src/payload/blocks/TrackedLinkBlock.ts | 41 - .../src/payload/blocks/TwitterEmbedBlock.ts | 22 - .../src/payload/blocks/WaterfallChartBlock.ts | 64 - .../src/payload/blocks/WebVitalsScoreBlock.ts | 46 - .../src/payload/blocks/YouTubeEmbedBlock.ts | 41 - apps/web/src/payload/blocks/allBlocks.ts | 104 - apps/web/src/payload/blocks/index.ts | 45 - apps/web/src/payload/blocks/types.ts | 8 - .../src/payload/collections/ContextFiles.ts | 55 - .../collections/ContextFiles/seed/ABOUT.md | 123 - .../collections/ContextFiles/seed/AGBS.md | 154 - .../collections/ContextFiles/seed/AUDIENCE.md | 33 - .../ContextFiles/seed/AUTOMATION.md | 76 - .../ContextFiles/seed/CONTENT_RULES.md | 65 - .../ContextFiles/seed/ESTIMATION_GUIDE.md | 99 - .../collections/ContextFiles/seed/KEYWORDS.md | 68 - .../ContextFiles/seed/LANDING_PAGE.md | 238 -- .../ContextFiles/seed/MAINTENANCE.md | 35 - .../collections/ContextFiles/seed/PRICING.md | 234 -- .../ContextFiles/seed/PRINCIPLES.md | 43 - .../ContextFiles/seed/STANDARDS.md | 36 - .../ContextFiles/seed/STYLEGUIDE.md | 88 - .../collections/ContextFiles/seed/TECH.md | 98 - .../collections/ContextFiles/seed/TONE.md | 53 - .../collections/ContextFiles/seed/WEBSITES.md | 136 - .../collections/ContextFiles/seed/WORDING.md | 56 - .../src/payload/collections/CrmAccounts.ts | 189 - .../src/payload/collections/CrmContacts.ts | 145 - .../payload/collections/CrmInteractions.ts | 143 - apps/web/src/payload/collections/CrmTopics.ts | 78 - apps/web/src/payload/collections/Inquiries.ts | 98 - apps/web/src/payload/collections/Media.ts | 65 - apps/web/src/payload/collections/Posts.ts | 121 - apps/web/src/payload/collections/Projects.ts | 192 - apps/web/src/payload/collections/Redirects.ts | 33 - apps/web/src/payload/collections/Users.ts | 13 - .../payload/components/AiAnalyzeButton.tsx | 100 - .../src/payload/components/BulkMailButton.tsx | 147 - .../payload/components/ColorPicker/index.tsx | 144 - .../components/ConvertInquiryButton.tsx | 88 - .../payload/components/IconSelector/index.tsx | 191 - .../payload/components/TagSelector/index.tsx | 131 - apps/web/src/payload/endpoints/aiEndpoint.ts | 226 - .../src/payload/endpoints/bulkMailEndpoint.ts | 191 - .../endpoints/convertInquiryEndpoint.ts | 89 - .../web/src/payload/endpoints/emailWebhook.ts | 125 - .../src/payload/endpoints/projectsEndpoint.ts | 0 .../payload/views/GanttChart/GanttChart.css | 214 - .../src/payload/views/GanttChart/index.tsx | 255 -- docker-compose.dev.yml | 19 - docker-compose.yml | 19 - package.json | 7 - scripts/extract-to-mdx.js | 70 + tmp_posts.json | 1 + 131 files changed, 331 insertions(+), 14844 deletions(-) delete mode 100644 apps/web/app/(payload)/actions.ts delete mode 100644 apps/web/app/(payload)/admin/[[...segments]]/page.tsx delete mode 100644 apps/web/app/(payload)/admin/importMap.js delete mode 100644 apps/web/app/(payload)/api/[...slug]/route.ts delete mode 100644 apps/web/app/(payload)/layout.tsx delete mode 100644 apps/web/payload.config.ts delete mode 100644 apps/web/src/components/PayloadRichText.tsx create mode 100644 apps/web/src/content/posts/analytics-ohne-tracking-dsgvo-konforme-insights-ohne-user-ueberwachung.mdx create mode 100644 apps/web/src/content/posts/build-first-digital-architecture.mdx create mode 100644 apps/web/src/content/posts/builder-systems-threaten-independence.mdx create mode 100644 apps/web/src/content/posts/clean-code-for-business-value.mdx create mode 100644 apps/web/src/content/posts/crm-synchronization-headless.mdx create mode 100644 apps/web/src/content/posts/digital-longevity-architecture.mdx create mode 100644 apps/web/src/content/posts/fixed-price-digital-projects.mdx create mode 100644 apps/web/src/content/posts/gdpr-conformity-system-approach.mdx create mode 100644 apps/web/src/content/posts/google-pagespeed-guide-warum-ladezeit-ihr-wichtigster-b2b-umsatzhebel-ist.mdx create mode 100644 apps/web/src/content/posts/green-it-sustainable-web.mdx create mode 100644 apps/web/src/content/posts/hidden-costs-of-wordpress-plugins.mdx create mode 100644 apps/web/src/content/posts/maintenance-for-headless-systems.mdx create mode 100644 apps/web/src/content/posts/no-us-cloud-platforms.mdx create mode 100644 apps/web/src/content/posts/professional-hosting-operations.mdx create mode 100644 apps/web/src/content/posts/responsive-design-high-fidelity.mdx create mode 100644 apps/web/src/content/posts/slow-loading-costs-customers.mdx create mode 100644 apps/web/src/content/posts/website-without-cookie-banners.mdx create mode 100644 apps/web/src/content/posts/why-agencies-are-slow.mdx create mode 100644 apps/web/src/content/posts/why-no-templates-matter.mdx create mode 100644 apps/web/src/content/posts/why-websites-break-after-updates.mdx delete mode 100644 apps/web/src/migrations/20260227_171023_crm_collections.json delete mode 100644 apps/web/src/migrations/20260227_171023_crm_collections.ts delete mode 100644 apps/web/src/migrations/20260301_151838.json delete mode 100644 apps/web/src/migrations/20260301_151838.ts delete mode 100644 apps/web/src/migrations/index.ts delete mode 100644 apps/web/src/payload/blocks/ArchitectureBuilderBlock.ts delete mode 100644 apps/web/src/payload/blocks/ArticleBlockquoteBlock.ts delete mode 100644 apps/web/src/payload/blocks/ArticleMemeBlock.ts delete mode 100644 apps/web/src/payload/blocks/ArticleQuoteBlock.ts delete mode 100644 apps/web/src/payload/blocks/BoldNumberBlock.ts delete mode 100644 apps/web/src/payload/blocks/ButtonBlock.ts delete mode 100644 apps/web/src/payload/blocks/CarouselBlock.ts delete mode 100644 apps/web/src/payload/blocks/ComparisonRowBlock.ts delete mode 100644 apps/web/src/payload/blocks/DiagramFlowBlock.ts delete mode 100644 apps/web/src/payload/blocks/DiagramGanttBlock.ts delete mode 100644 apps/web/src/payload/blocks/DiagramPieBlock.ts delete mode 100644 apps/web/src/payload/blocks/DiagramSequenceBlock.ts delete mode 100644 apps/web/src/payload/blocks/DiagramStateBlock.ts delete mode 100644 apps/web/src/payload/blocks/DiagramTimelineBlock.ts delete mode 100644 apps/web/src/payload/blocks/DigitalAssetVisualizerBlock.ts delete mode 100644 apps/web/src/payload/blocks/ExternalLinkBlock.ts delete mode 100644 apps/web/src/payload/blocks/FAQSectionBlock.ts delete mode 100644 apps/web/src/payload/blocks/H2Block.ts delete mode 100644 apps/web/src/payload/blocks/H3Block.ts delete mode 100644 apps/web/src/payload/blocks/HeadingBlock.ts delete mode 100644 apps/web/src/payload/blocks/IconListBlock.ts delete mode 100644 apps/web/src/payload/blocks/ImageTextBlock.ts delete mode 100644 apps/web/src/payload/blocks/LeadMagnetBlock.ts delete mode 100644 apps/web/src/payload/blocks/LeadParagraphBlock.ts delete mode 100644 apps/web/src/payload/blocks/LinkedInEmbedBlock.ts delete mode 100644 apps/web/src/payload/blocks/LoadTimeSimulatorBlock.ts delete mode 100644 apps/web/src/payload/blocks/MarkerBlock.ts delete mode 100644 apps/web/src/payload/blocks/MemeCardBlock.ts delete mode 100644 apps/web/src/payload/blocks/MermaidBlock.ts delete mode 100644 apps/web/src/payload/blocks/MetricBarBlock.ts delete mode 100644 apps/web/src/payload/blocks/ParagraphBlock.ts delete mode 100644 apps/web/src/payload/blocks/PerformanceChartBlock.ts delete mode 100644 apps/web/src/payload/blocks/PerformanceROICalculatorBlock.ts delete mode 100644 apps/web/src/payload/blocks/PremiumComparisonChartBlock.ts delete mode 100644 apps/web/src/payload/blocks/RevealBlock.ts delete mode 100644 apps/web/src/payload/blocks/RevenueLossCalculatorBlock.ts delete mode 100644 apps/web/src/payload/blocks/SectionBlock.ts delete mode 100644 apps/web/src/payload/blocks/StatsDisplayBlock.ts delete mode 100644 apps/web/src/payload/blocks/StatsGridBlock.ts delete mode 100644 apps/web/src/payload/blocks/TLDRBlock.ts delete mode 100644 apps/web/src/payload/blocks/TrackedLinkBlock.ts delete mode 100644 apps/web/src/payload/blocks/TwitterEmbedBlock.ts delete mode 100644 apps/web/src/payload/blocks/WaterfallChartBlock.ts delete mode 100644 apps/web/src/payload/blocks/WebVitalsScoreBlock.ts delete mode 100644 apps/web/src/payload/blocks/YouTubeEmbedBlock.ts delete mode 100644 apps/web/src/payload/blocks/allBlocks.ts delete mode 100644 apps/web/src/payload/blocks/index.ts delete mode 100644 apps/web/src/payload/blocks/types.ts delete mode 100644 apps/web/src/payload/collections/ContextFiles.ts delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/ABOUT.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/AGBS.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/AUDIENCE.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/AUTOMATION.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/CONTENT_RULES.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/ESTIMATION_GUIDE.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/KEYWORDS.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/LANDING_PAGE.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/MAINTENANCE.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/PRICING.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/PRINCIPLES.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/STANDARDS.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/STYLEGUIDE.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/TECH.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/TONE.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/WEBSITES.md delete mode 100644 apps/web/src/payload/collections/ContextFiles/seed/WORDING.md delete mode 100644 apps/web/src/payload/collections/CrmAccounts.ts delete mode 100644 apps/web/src/payload/collections/CrmContacts.ts delete mode 100644 apps/web/src/payload/collections/CrmInteractions.ts delete mode 100644 apps/web/src/payload/collections/CrmTopics.ts delete mode 100644 apps/web/src/payload/collections/Inquiries.ts delete mode 100644 apps/web/src/payload/collections/Media.ts delete mode 100644 apps/web/src/payload/collections/Posts.ts delete mode 100644 apps/web/src/payload/collections/Projects.ts delete mode 100644 apps/web/src/payload/collections/Redirects.ts delete mode 100644 apps/web/src/payload/collections/Users.ts delete mode 100644 apps/web/src/payload/components/AiAnalyzeButton.tsx delete mode 100644 apps/web/src/payload/components/BulkMailButton.tsx delete mode 100644 apps/web/src/payload/components/ColorPicker/index.tsx delete mode 100644 apps/web/src/payload/components/ConvertInquiryButton.tsx delete mode 100644 apps/web/src/payload/components/IconSelector/index.tsx delete mode 100644 apps/web/src/payload/components/TagSelector/index.tsx delete mode 100644 apps/web/src/payload/endpoints/aiEndpoint.ts delete mode 100644 apps/web/src/payload/endpoints/bulkMailEndpoint.ts delete mode 100644 apps/web/src/payload/endpoints/convertInquiryEndpoint.ts delete mode 100644 apps/web/src/payload/endpoints/emailWebhook.ts delete mode 100644 apps/web/src/payload/endpoints/projectsEndpoint.ts delete mode 100644 apps/web/src/payload/views/GanttChart/GanttChart.css delete mode 100644 apps/web/src/payload/views/GanttChart/index.tsx create mode 100644 scripts/extract-to-mdx.js create mode 100644 tmp_posts.json diff --git a/apps/web/app/(payload)/actions.ts b/apps/web/app/(payload)/actions.ts deleted file mode 100644 index c46ac4b..0000000 --- a/apps/web/app/(payload)/actions.ts +++ /dev/null @@ -1,13 +0,0 @@ -"use server"; -import { handleServerFunctions as payloadHandleServerFunctions } from "@payloadcms/next/layouts"; -import config from "@payload-config"; -// @ts-ignore - Payload generates this file during the build process -import { importMap } from "./admin/importMap"; - -export const handleServerFunctions = async (args: any) => { - return payloadHandleServerFunctions({ - ...args, - config, - importMap, - }); -}; diff --git a/apps/web/app/(payload)/admin/[[...segments]]/page.tsx b/apps/web/app/(payload)/admin/[[...segments]]/page.tsx deleted file mode 100644 index cbdd0b5..0000000 --- a/apps/web/app/(payload)/admin/[[...segments]]/page.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import type { Metadata } from "next"; - -import configPromise from "@payload-config"; -import { RootPage, generatePageMetadata } from "@payloadcms/next/views"; -// @ts-ignore - Payload generates this file during the build process -import { importMap } from "../importMap"; - -type Args = { - params: Promise<{ - segments: string[]; - }>; - searchParams: Promise<{ - [key: string]: string | string[]; - }>; -}; - -export const generateMetadata = async ({ - params, - searchParams, -}: Args): Promise => - generatePageMetadata({ config: configPromise, params, searchParams }); - -const Page = async ({ params, searchParams }: Args) => - RootPage({ config: configPromise, importMap, params, searchParams }); - -export default Page; diff --git a/apps/web/app/(payload)/admin/importMap.js b/apps/web/app/(payload)/admin/importMap.js deleted file mode 100644 index 5deabbc..0000000 --- a/apps/web/app/(payload)/admin/importMap.js +++ /dev/null @@ -1,120 +0,0 @@ -import { AiMediaButtons as AiMediaButtons_1d402a78164f07306f77dce953e62e11 } from "@mintel/payload-ai/components/AiMediaButtons"; -import { OptimizeButton as OptimizeButton_338ff118e214cff355f6d710d1a381fb } from "@mintel/payload-ai/components/OptimizeButton"; -import { GenerateSlugButton as GenerateSlugButton_5baeea8510d263708dd253e86d55e0b4 } from "@mintel/payload-ai/components/FieldGenerators/GenerateSlugButton"; -import { default as default_76cec558bd86098fa1dab70b12eb818f } from "@/src/payload/components/TagSelector"; -import { GenerateThumbnailButton as GenerateThumbnailButton_e5e8c00f1c031f15175fef0ff67513dc } from "@mintel/payload-ai/components/FieldGenerators/GenerateThumbnailButton"; -import { RscEntryLexicalCell as RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e } from "@payloadcms/richtext-lexical/rsc"; -import { RscEntryLexicalField as RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e } from "@payloadcms/richtext-lexical/rsc"; -import { LexicalDiffComponent as LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e } from "@payloadcms/richtext-lexical/rsc"; -import { BlocksFeatureClient as BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { AiFieldButton as AiFieldButton_9125bc0af442fbb1889d8de3dff98501 } from "@mintel/payload-ai/components/FieldGenerators/AiFieldButton"; -import { InlineToolbarFeatureClient as InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { UploadFeatureClient as UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { BlockquoteFeatureClient as BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { RelationshipFeatureClient as RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { LinkFeatureClient as LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { ChecklistFeatureClient as ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { OrderedListFeatureClient as OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { UnorderedListFeatureClient as UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { IndentFeatureClient as IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { AlignFeatureClient as AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { HeadingFeatureClient as HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { ParagraphFeatureClient as ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { InlineCodeFeatureClient as InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { SuperscriptFeatureClient as SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { SubscriptFeatureClient as SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { StrikethroughFeatureClient as StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { UnderlineFeatureClient as UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { BoldFeatureClient as BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from "@payloadcms/richtext-lexical/client"; -import { default as default_2ebf44fdf8ebc607cf0de30cff485248 } from "@/src/payload/components/ColorPicker"; -import { default as default_a1c6da8fb7dd9846a8b07123ff256d09 } from "@/src/payload/components/IconSelector"; -import { ConvertInquiryButton as ConvertInquiryButton_09fd670bce023a947ab66e4eebea5168 } from "@/src/payload/components/ConvertInquiryButton"; -import { AiAnalyzeButton as AiAnalyzeButton_51a6009c2b12d068d736ffd2b8182c71 } from "@/src/payload/components/AiAnalyzeButton"; -import { BulkMailButton as BulkMailButton_ebc54eabb8a07878581b0043bd687708 } from "@/src/payload/components/BulkMailButton"; -import { GanttChartView as GanttChartView_0162b82db971e8f1e27fbdd0aaa2f1f4 } from "@/src/payload/views/GanttChart"; -import { ChatWindowProvider as ChatWindowProvider_258e2d0901cb901e46c3eeed91676211 } from "@mintel/payload-ai/components/ChatWindow/index"; -import { S3ClientUploadHandler as S3ClientUploadHandler_f97aa6c64367fa259c5bc0567239ef24 } from "@payloadcms/storage-s3/client"; -import { CollectionCards as CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1 } from "@payloadcms/next/rsc"; - -export const importMap = { - "@mintel/payload-ai/components/AiMediaButtons#AiMediaButtons": - AiMediaButtons_1d402a78164f07306f77dce953e62e11, - "@mintel/payload-ai/components/OptimizeButton#OptimizeButton": - OptimizeButton_338ff118e214cff355f6d710d1a381fb, - "@mintel/payload-ai/components/FieldGenerators/GenerateSlugButton#GenerateSlugButton": - GenerateSlugButton_5baeea8510d263708dd253e86d55e0b4, - "@/src/payload/components/TagSelector#default": - default_76cec558bd86098fa1dab70b12eb818f, - "@mintel/payload-ai/components/FieldGenerators/GenerateThumbnailButton#GenerateThumbnailButton": - GenerateThumbnailButton_e5e8c00f1c031f15175fef0ff67513dc, - "@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": - RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e, - "@payloadcms/richtext-lexical/rsc#RscEntryLexicalField": - RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e, - "@payloadcms/richtext-lexical/rsc#LexicalDiffComponent": - LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e, - "@payloadcms/richtext-lexical/client#BlocksFeatureClient": - BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton": - AiFieldButton_9125bc0af442fbb1889d8de3dff98501, - "@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient": - InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": - HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#UploadFeatureClient": - UploadFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#BlockquoteFeatureClient": - BlockquoteFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#RelationshipFeatureClient": - RelationshipFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#LinkFeatureClient": - LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#ChecklistFeatureClient": - ChecklistFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#OrderedListFeatureClient": - OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#UnorderedListFeatureClient": - UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#IndentFeatureClient": - IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#AlignFeatureClient": - AlignFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#HeadingFeatureClient": - HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#ParagraphFeatureClient": - ParagraphFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#InlineCodeFeatureClient": - InlineCodeFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#SuperscriptFeatureClient": - SuperscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#SubscriptFeatureClient": - SubscriptFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#StrikethroughFeatureClient": - StrikethroughFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#UnderlineFeatureClient": - UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#BoldFeatureClient": - BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#ItalicFeatureClient": - ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@/src/payload/components/ColorPicker#default": - default_2ebf44fdf8ebc607cf0de30cff485248, - "@/src/payload/components/IconSelector#default": - default_a1c6da8fb7dd9846a8b07123ff256d09, - "@/src/payload/components/ConvertInquiryButton#ConvertInquiryButton": - ConvertInquiryButton_09fd670bce023a947ab66e4eebea5168, - "@/src/payload/components/AiAnalyzeButton#AiAnalyzeButton": - AiAnalyzeButton_51a6009c2b12d068d736ffd2b8182c71, - "@/src/payload/components/BulkMailButton#BulkMailButton": - BulkMailButton_ebc54eabb8a07878581b0043bd687708, - "@/src/payload/views/GanttChart#GanttChartView": - GanttChartView_0162b82db971e8f1e27fbdd0aaa2f1f4, - "@mintel/payload-ai/components/ChatWindow/index#ChatWindowProvider": - ChatWindowProvider_258e2d0901cb901e46c3eeed91676211, - "@payloadcms/storage-s3/client#S3ClientUploadHandler": - S3ClientUploadHandler_f97aa6c64367fa259c5bc0567239ef24, - "@payloadcms/next/rsc#CollectionCards": - CollectionCards_f9c02e79a4aed9a3924487c0cd4cafb1, -}; diff --git a/apps/web/app/(payload)/api/[...slug]/route.ts b/apps/web/app/(payload)/api/[...slug]/route.ts deleted file mode 100644 index 06c5bad..0000000 --- a/apps/web/app/(payload)/api/[...slug]/route.ts +++ /dev/null @@ -1,16 +0,0 @@ -import config from "@payload-config"; -import { - REST_DELETE, - REST_GET, - REST_OPTIONS, - REST_PATCH, - REST_POST, - REST_PUT, -} from "@payloadcms/next/routes"; - -export const GET = REST_GET(config); -export const POST = REST_POST(config); -export const DELETE = REST_DELETE(config); -export const OPTIONS = REST_OPTIONS(config); -export const PATCH = REST_PATCH(config); -export const PUT = REST_PUT(config); diff --git a/apps/web/app/(payload)/layout.tsx b/apps/web/app/(payload)/layout.tsx deleted file mode 100644 index cd7e216..0000000 --- a/apps/web/app/(payload)/layout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import configPromise from "@payload-config"; -import "@payloadcms/next/css"; -import { RootLayout } from "@payloadcms/next/layouts"; -import React from "react"; - -import { handleServerFunctions } from "./actions"; -// @ts-ignore - Payload generates this file during the build process -import { importMap } from "./admin/importMap"; - -export default function Layout({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); -} diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index e0a7a88..3cf5bfa 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -1,5 +1,5 @@ import withMintelConfig from "@mintel/next-config"; -import { withPayload } from '@payloadcms/next/withPayload'; + import createMDX from '@next/mdx'; import path from 'path'; import { fileURLToPath } from 'url'; @@ -21,7 +21,7 @@ const nextConfig = { '@mintel/concept-engine', '@mintel/estimation-engine', '@mintel/meme-generator', - '@mintel/payload-ai', + '@mintel/pdf', '@mintel/thumbnail-generator' ], @@ -80,4 +80,4 @@ if (config.serverActions) { delete config.serverActions; } -export default withPayload(config); +export default config; diff --git a/apps/web/package.json b/apps/web/package.json index fe23560..9a04d87 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -4,10 +4,9 @@ "version": "0.1.0", "description": "Technical problem solver's blog - practical insights and learning notes", "scripts": { - "dev": "pnpm run seed:context && next dev --webpack --hostname 0.0.0.0", - "dev:native": "DATABASE_URI=postgres://payload:payload@127.0.0.1:54321/payload PAYLOAD_SECRET=dev-secret pnpm run seed:context && DATABASE_URI=postgres://payload:payload@127.0.0.1:54321/payload PAYLOAD_SECRET=dev-secret next dev --webpack", - "seed:context": "node --import tsx --experimental-loader ./ignore-css.mjs ./seed-context.ts", - "build": "payload generate:importmap && next build --webpack", + "dev": "next dev --webpack --hostname 0.0.0.0", + "dev:native": "next dev --webpack", + "build": "next build --webpack", "start": "next start", "lint": "eslint app src scripts video", "test": "echo \"No tests configured\"", @@ -24,13 +23,7 @@ "typecheck": "tsc --noEmit", "check:og": "tsx scripts/check-og-images.ts", "check:forms": "tsx scripts/check-forms.ts", - "cms:push:testing": "bash ./scripts/cms-sync.sh push testing", - "cms:pull:testing": "bash ./scripts/cms-sync.sh pull testing", - "cms:push:staging": "bash ./scripts/cms-sync.sh push staging", - "cms:pull:staging": "bash ./scripts/cms-sync.sh pull staging", - "cms:push:prod": "bash ./scripts/cms-sync.sh push prod", - "cms:pull:prod": "bash ./scripts/cms-sync.sh pull prod", - "db:restore": "bash ./scripts/restore-db.sh" + "check:forms": "tsx scripts/check-forms.ts" }, "dependencies": { "@aws-sdk/client-s3": "^3.750.0", @@ -41,7 +34,7 @@ "@mintel/content-engine": "link:../../../at-mintel/packages/content-engine", "@mintel/estimation-engine": "link:../../../at-mintel/packages/estimation-engine", "@mintel/meme-generator": "link:../../../at-mintel/packages/meme-generator", - "@mintel/payload-ai": "link:../../../at-mintel/packages/payload-ai", + "@mintel/meme-generator": "link:../../../at-mintel/packages/meme-generator", "@mintel/pdf": "link:../../../at-mintel/packages/pdf-library", "@mintel/thumbnail-generator": "link:../../../at-mintel/packages/thumbnail-generator", "@next/mdx": "^16.1.6", @@ -50,12 +43,7 @@ "@opentelemetry/context-async-hooks": "^2.1.0", "@opentelemetry/core": "^2.1.0", "@opentelemetry/sdk-trace-base": "^2.1.0", - "@payloadcms/db-postgres": "^3.77.0", - "@payloadcms/email-nodemailer": "^3.77.0", - "@payloadcms/next": "^3.77.0", - "@payloadcms/richtext-lexical": "^3.77.0", - "@payloadcms/storage-s3": "^3.77.0", - "@payloadcms/ui": "^3.77.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", "@react-pdf/renderer": "^4.3.2", "@remotion/bundler": "^4.0.414", "@remotion/cli": "^4.0.414", @@ -85,7 +73,7 @@ "next": "^16.1.6", "next-mdx-remote": "^6.0.0", "nodemailer": "^8.0.1", - "payload": "^3.77.0", + "nodemailer": "^8.0.1", "playwright": "^1.58.1", "prismjs": "^1.30.0", "puppeteer": "^24.36.1", diff --git a/apps/web/payload.config.ts b/apps/web/payload.config.ts deleted file mode 100644 index c2a2155..0000000 --- a/apps/web/payload.config.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { buildConfig } from "payload"; -// Triggering config re-analysis for blocks visibility - V4 -import { postgresAdapter } from "@payloadcms/db-postgres"; -import { lexicalEditor, BlocksFeature } from "@payloadcms/richtext-lexical"; -import { payloadBlocks } from "./src/payload/blocks/allBlocks"; -import { nodemailerAdapter } from "@payloadcms/email-nodemailer"; -import { s3Storage } from "@payloadcms/storage-s3"; -import path from "path"; -import { fileURLToPath } from "url"; -import sharp from "sharp"; - -import { Users } from "./src/payload/collections/Users"; -import { Media } from "./src/payload/collections/Media"; -import { Posts } from "./src/payload/collections/Posts"; -import { emailWebhookHandler } from "./src/payload/endpoints/emailWebhook"; -import { aiEndpointHandler } from "./src/payload/endpoints/aiEndpoint"; -import { Inquiries } from "./src/payload/collections/Inquiries"; -import { Redirects } from "./src/payload/collections/Redirects"; -import { ContextFiles } from "./src/payload/collections/ContextFiles"; -import { CrmAccounts } from "./src/payload/collections/CrmAccounts"; -import { CrmContacts } from "./src/payload/collections/CrmContacts"; -import { CrmInteractions } from "./src/payload/collections/CrmInteractions"; -import { CrmTopics } from "./src/payload/collections/CrmTopics"; -import { Projects } from "./src/payload/collections/Projects"; - -const filename = fileURLToPath(import.meta.url); -const dirname = path.dirname(filename); - -const isCLI = - process.argv.includes("migrate") || - process.argv.includes("generate:importmap") || - process.argv.includes("build"); -let aiPlugin: any; -if (!isCLI) { - const { payloadChatPlugin } = await import("@mintel/payload-ai"); - aiPlugin = payloadChatPlugin({ - enabled: true, - mcpServers: [], - renderChatBubble: false, // disable dynamic injection since it's added statically below - }); -} - -export default buildConfig({ - admin: { - user: Users.slug, - importMap: { - baseDir: path.resolve(dirname), - }, - components: { - providers: [ - "@mintel/payload-ai/components/ChatWindow/index#ChatWindowProvider", - ], - }, - }, - collections: [ - Users, - Media, - Posts, - Inquiries, - Redirects, - ContextFiles, - CrmAccounts, - CrmContacts, - CrmTopics, - CrmInteractions, - Projects, - ], - globals: [ - /* AiSettings as any */ - ], - email: isCLI - ? undefined - : nodemailerAdapter({ - defaultFromAddress: process.env.MAIL_FROM || "info@mintel.me", - defaultFromName: "Mintel.me", - transportOptions: { - host: process.env.MAIL_HOST || "localhost", - port: parseInt(process.env.MAIL_PORT || "587", 10), - auth: { - user: process.env.MAIL_USERNAME || "user", - pass: process.env.MAIL_PASSWORD || "pass", - }, - ...(process.env.MAIL_HOST ? {} : { ignoreTLS: true }), - }, - }), - editor: lexicalEditor({ - features: ({ defaultFeatures }) => [ - ...defaultFeatures, - BlocksFeature({ - blocks: payloadBlocks, - }), - ], - }), - secret: process.env.PAYLOAD_SECRET || "fallback-secret-for-dev", - typescript: { - outputFile: path.resolve(dirname, "payload-types.ts"), - }, - db: postgresAdapter({ - pool: { - connectionString: - process.env.DATABASE_URI || process.env.POSTGRES_URI || "", - }, - push: false, - }), - sharp, - plugins: [ - ...(process.env.S3_ENDPOINT - ? [ - s3Storage({ - collections: { - media: { - prefix: `${process.env.S3_PREFIX || "mintel-me"}/media`, - }, - }, - bucket: process.env.S3_BUCKET || "", - config: { - credentials: { - accessKeyId: process.env.S3_ACCESS_KEY || "", - secretAccessKey: process.env.S3_SECRET_KEY || "", - }, - region: process.env.S3_REGION || "fsn1", - endpoint: process.env.S3_ENDPOINT, - forcePathStyle: true, - }, - }), - ] - : []), - ...(aiPlugin ? [aiPlugin] : []), - ], - endpoints: [ - { - path: "/crm/incoming-email", - method: "post", - handler: emailWebhookHandler, - }, - ], -}); diff --git a/apps/web/src/actions/contact.ts b/apps/web/src/actions/contact.ts index 6207fe3..186b6bd 100644 --- a/apps/web/src/actions/contact.ts +++ b/apps/web/src/actions/contact.ts @@ -5,8 +5,6 @@ import { getInquiryEmailHtml, getConfirmationEmailHtml, } from "../components/ContactForm/EmailTemplates"; -import { getPayload } from "payload"; -import configPromise from "@payload-config"; export async function sendContactInquiry(data: { name: string; @@ -21,24 +19,7 @@ export async function sendContactInquiry(data: { config?: any; }) { try { - // 1. Save to Payload CMS (Replaces Directus) - const payload = await getPayload({ config: configPromise }); - await payload.create({ - collection: "inquiries", - data: { - name: data.name, - email: data.email, - phone: data.phone, - role: data.role, - companyName: data.companyName, - projectType: data.projectType, - deadline: data.deadline, - message: data.message, - isFreeText: data.isFreeText, - config: data.config || null, - }, - }); - + // Payload removed, directly send emails // 2. Send Inquiry to Marc const inquiryResult = await sendEmail({ subject: `[PROJEKT] ${data.isFreeText ? "DIREKTANFRAGE" : "KONFIGURATION"}: ${data.companyName || data.name}`, diff --git a/apps/web/src/components/PayloadRichText.tsx b/apps/web/src/components/PayloadRichText.tsx deleted file mode 100644 index f9f28db..0000000 --- a/apps/web/src/components/PayloadRichText.tsx +++ /dev/null @@ -1,389 +0,0 @@ -import { - RichText, - defaultJSXConverters, -} from "@payloadcms/richtext-lexical/react"; -import type { JSXConverters } from "@payloadcms/richtext-lexical/react"; -import { MemeCard } from "@/src/components/MemeCard"; -import { Mermaid } from "@/src/components/Mermaid"; -import { LeadMagnet } from "@/src/components/LeadMagnet"; -import { ComparisonRow } from "@/src/components/Landing/ComparisonRow"; -import { mdxComponents } from "../content-engine/components"; -import React from "react"; - -/** - * Renders markdown-style inline links [text](/url) as tags. - * Used by mintelP blocks which store body text with links. - */ -function renderInlineMarkdown(text: string): React.ReactNode { - if (!text) return null; - const parts = text.split(/(\[[^\]]+\]\([^)]+\)|[^<]*<\/Marker>)/); - return parts.map((part, i) => { - const linkMatch = part.match(/\[([^\]]+)\]\(([^)]+)\)/); - if (linkMatch) { - return ( - - {linkMatch[1]} - - ); - } - const markerMatch = part.match(/([^<]*)<\/Marker>/); - if (markerMatch) { - return ( - - {markerMatch[1]} - - ); - } - return {part}; - }); -} - -const jsxConverters: JSXConverters = { - ...defaultJSXConverters, - // Override paragraph to filter out leftover raw text - paragraph: ({ node, nodesToJSX }: any) => { - const children = node?.children; - if ( - children?.length === 1 && - children[0]?.type === "text" && - children[0]?.text?.trim()?.startsWith("<") && - children[0]?.text?.trim()?.endsWith("/>") - ) { - return null; // suppress raw JSX component text like - } - return

{nodesToJSX({ nodes: children })}

; - }, - blocks: { - memeCard: ({ node }: any) => ( -
- -
- ), - mermaid: ({ node }: any) => ( -
- - {node.fields.chartDefinition} - -
- ), - leadMagnet: ({ node }: any) => ( -
- -
- ), - comparisonRow: ({ node }: any) => ( - - ), - // --- Core text blocks --- - mintelP: ({ node }: any) => ( -

- {renderInlineMarkdown(node.fields.text)} -

- ), - mintelTldr: ({ node }: any) => ( - {node.fields.content} - ), - // --- MDX Registry Injections --- - leadParagraph: ({ node }: any) => ( - - {node.fields.text} - - ), - articleBlockquote: ({ node }: any) => ( - - {node.fields.quote} - {node.fields.author && ` - ${node.fields.author}`} - - ), - mintelH2: ({ node }: any) => ( - {node.fields.text} - ), - mintelH3: ({ node }: any) => ( - {node.fields.text} - ), - mintelHeading: ({ node }: any) => { - const displayLevel = node.fields.displayLevel || "h2"; - if (displayLevel === "h3") - return {node.fields.text}; - return {node.fields.text}; - }, - statsDisplay: ({ node }: any) => ( - - ), - diagramState: ({ node }: any) => ( -
- - {node.fields.definition} - -
- ), - diagramTimeline: ({ node }: any) => ( -
- - {node.fields.definition} - -
- ), - diagramGantt: ({ node }: any) => ( -
- - {node.fields.definition} - -
- ), - diagramPie: ({ node }: any) => ( -
- - {node.fields.definition} - -
- ), - diagramSequence: ({ node }: any) => ( -
- - {node.fields.definition} - -
- ), - diagramFlow: ({ node }: any) => ( -
- - {node.fields.definition} - -
- ), - - waterfallChart: ({ node }: any) => ( - - ), - premiumComparisonChart: ({ node }: any) => ( - - ), - iconList: ({ node }: any) => ( - - {node.fields.items?.map((item: any, i: number) => { - const isCheck = item.icon === "check" || !item.icon; - const isCross = item.icon === "x" || item.icon === "cross"; - const isBullet = item.icon === "circle" || item.icon === "bullet"; - return ( - // @ts-ignore - - {item.title || item.description} - - ); - })} - - ), - statsGrid: ({ node }: any) => { - const rawStats = node.fields.stats || []; - let statsStr = ""; - if (Array.isArray(rawStats)) { - statsStr = rawStats - .map((s: any) => `${s.value || ""}|${s.label || ""}`) - .join("~"); - } else if (typeof rawStats === "string") { - statsStr = rawStats; - } - return ; - }, - metricBar: ({ node }: any) => ( - - ), - carousel: ({ node }: any) => ( - ({ - title: s.title || s.caption || "Slide", - content: s.content || s.caption || "", - icon: undefined, - })) || [] - } - /> - ), - imageText: ({ node }: any) => ( - - {node.fields.text} - - ), - revenueLossCalculator: ({ node }: any) => ( - - ), - performanceChart: ({ node }: any) => , - performanceROICalculator: ({ node }: any) => ( -
- -
- ), - loadTimeSimulator: ({ node }: any) => ( -
- -
- ), - architectureBuilder: ({ node }: any) => ( -
- -
- ), - digitalAssetVisualizer: ({ node }: any) => ( -
- -
- ), - - twitterEmbed: ({ node }: any) => ( - - ), - youTubeEmbed: ({ node }: any) => ( - - ), - linkedInEmbed: ({ node }: any) => ( - - ), - externalLink: ({ node }: any) => ( - - {node.fields.label} - - ), - trackedLink: ({ node }: any) => ( - - {node.fields.label} - - ), - articleMeme: ({ node }: any) => ( - - ), - marker: ({ node }: any) => ( - - {node.fields.text} - - ), - boldNumber: ({ node }: any) => ( - - ), - webVitalsScore: ({ node }: any) => ( - - ), - buttonBlock: ({ node }: any) => ( - - {node.fields.label} - - ), - articleQuote: ({ node }: any) => ( - - ), - reveal: ({ node }: any) => ( - - {/* Reveal component takes children, which in MDX is nested content */} - - - ), - section: ({ node }: any) => ( - - - - ), - tableOfContents: () => , - faqSection: ({ node }: any) => ( - - - - ), - }, -}; - -export function PayloadRichText({ data }: { data: any }) { - if (!data) return null; - - return ( -
- -
- ); -} diff --git a/apps/web/src/content-engine/definitions.ts b/apps/web/src/content-engine/definitions.ts index 6128774..68ea5d4 100644 --- a/apps/web/src/content-engine/definitions.ts +++ b/apps/web/src/content-engine/definitions.ts @@ -1,9 +1,3 @@ import { ComponentDefinition } from "@mintel/content-engine"; -import { allComponentDefinitions } from "../payload/blocks/allBlocks"; -/** - * Single Source of Truth for all MDX component definitions. - * Now dynamically generated from individual Payload block definitions. - */ -export const componentDefinitions: ComponentDefinition[] = - allComponentDefinitions; +export const componentDefinitions: ComponentDefinition[] = []; diff --git a/apps/web/src/content/posts/analytics-ohne-tracking-dsgvo-konforme-insights-ohne-user-ueberwachung.mdx b/apps/web/src/content/posts/analytics-ohne-tracking-dsgvo-konforme-insights-ohne-user-ueberwachung.mdx new file mode 100644 index 0000000..aaa18a3 --- /dev/null +++ b/apps/web/src/content/posts/analytics-ohne-tracking-dsgvo-konforme-insights-ohne-user-ueberwachung.mdx @@ -0,0 +1,10 @@ +--- +title: "Analytics ohne Tracking: DSGVO-konforme Insights ohne User-Überwachung" +date: "2026-02-09T00:00:00.000Z" +description: "Erfahren Sie, wie moderne Digital-Architektur präzise Besucherströme misst, ohne die Privatsphäre zu verletzen oder nervige Cookie-Banner zu benötigen." +tags: ["privacy", "analytics"] +--- + + + +**TL;DR:** Klassisches Tracking via Google Analytics verliert durch Consent-Ablehnung bis zu 70% der Daten. Privacy-First Analytics arbeitet serverseitig (First-Party), kommt ohne Banner aus und liefert 100% genauere Trends bei maximalem Datenschutz und signifikant besserem PageSpeed. diff --git a/apps/web/src/content/posts/build-first-digital-architecture.mdx b/apps/web/src/content/posts/build-first-digital-architecture.mdx new file mode 100644 index 0000000..f2dc250 --- /dev/null +++ b/apps/web/src/content/posts/build-first-digital-architecture.mdx @@ -0,0 +1,6 @@ +--- +title: "Build vs. Buy: Warum Build-First die einzige Strategie für B2B-Marktführer ist" +date: "2026-02-05T00:00:00.000Z" +description: "Software-Miete vs. digitales Eigentum: Erfahren Sie, warum Bespoke Software laut Deloitte und McKinsey den ROI maximiert und Ihre Unabhängigkeit im B2B sichert." +tags: ["architecture", "business", "roi"] +--- diff --git a/apps/web/src/content/posts/builder-systems-threaten-independence.mdx b/apps/web/src/content/posts/builder-systems-threaten-independence.mdx new file mode 100644 index 0000000..1e80d46 --- /dev/null +++ b/apps/web/src/content/posts/builder-systems-threaten-independence.mdx @@ -0,0 +1,6 @@ +--- +title: "Vendor Lock-In vermeiden: Warum Baukasten-Systeme Ihre Unabhängigkeit bedrohen" +date: "2026-02-08T00:00:00.000Z" +description: "Erfahren Sie, wie proprietäre Systeme und SaaS-Baukästen Ihre digitale Souveränität gefährden und warum eine cloud-agnostische Architektur Ihr wertvollstes Business-Asset ist." +tags: ["architecture", "business"] +--- diff --git a/apps/web/src/content/posts/clean-code-for-business-value.mdx b/apps/web/src/content/posts/clean-code-for-business-value.mdx new file mode 100644 index 0000000..7fc3490 --- /dev/null +++ b/apps/web/src/content/posts/clean-code-for-business-value.mdx @@ -0,0 +1,8 @@ +--- +title: "Der ROI von Clean Code: Warum technische Qualität Ihr Business skaliert" +date: "2026-01-30T00:00:00.000Z" +description: "Software-Engineering als Wertanlage: Wie Clean Code die Wartungskosten um bis zu 80% senkt und die Time-to-Market für neue Features massiv beschleunigt." +tags: ["development", "business", "software-architecture"] +--- + +**TL;DR:** Unsauberer Code ("Technical Debt") frisst bis zu 80% Ihres IT-Budgets für reine Wartung. Clean Code reduziert die Debugging-Zeit um 30% und ermöglicht es Teams, 70% ihrer Zeit in echte Innovation statt in Bugfixing zu investieren. diff --git a/apps/web/src/content/posts/crm-synchronization-headless.mdx b/apps/web/src/content/posts/crm-synchronization-headless.mdx new file mode 100644 index 0000000..e15b891 --- /dev/null +++ b/apps/web/src/content/posts/crm-synchronization-headless.mdx @@ -0,0 +1,26 @@ +--- +title: "B2B CRM-Integration: Wie automatisierte Datenflüsse 12% Ihres Umsatzes retten" +date: "2026-01-31T00:00:00.000Z" +description: "Vom Kontaktformular direkt in den Sales-Funnel: Wie Sie manuelle Daten-Silos auflösen, die Sales-Produktivität um 14,5% steigern und menschliche Fehler eliminieren." +tags: ["crm", "architecture", "automation"] +--- + + + + diff --git a/apps/web/src/content/posts/digital-longevity-architecture.mdx b/apps/web/src/content/posts/digital-longevity-architecture.mdx new file mode 100644 index 0000000..302c13a --- /dev/null +++ b/apps/web/src/content/posts/digital-longevity-architecture.mdx @@ -0,0 +1,9 @@ +--- +title: "Digital Longevity: B2B-Software-Architektur für das nächste Jahrzehnt" +date: "2026-02-02T00:00:00.000Z" +description: "Software ohne Verfallsdatum: Erfahren Sie, wie nachhaltige Architektur technische Schulden minimiert und langfristige digitale Assets statt Liability schafft." +tags: ["architecture", "longevity", "strategy"] +--- + +**TL;DR:** +Die durchschnittliche App überlebt kaum 14-24 Monate. Durch modulare Headless-Architekturen, den Verzicht auf kurzlebige Frameworks und [Clean Code](/blog/clean-code-for-business-value) verwandeln wir IT von einem Kostenfaktor in ein langlebiges digitales Asset mit einer Lebensdauer von 10+ Jahren. diff --git a/apps/web/src/content/posts/fixed-price-digital-projects.mdx b/apps/web/src/content/posts/fixed-price-digital-projects.mdx new file mode 100644 index 0000000..949d134 --- /dev/null +++ b/apps/web/src/content/posts/fixed-price-digital-projects.mdx @@ -0,0 +1,6 @@ +--- +title: "Der strategische Festpreis: Warum Budgetsicherheit die Software-Qualität maximiert" +date: "2026-02-04T00:00:00.000Z" +description: "Keine Angst vor uferlosen Stundenabrechnungen. Erfahren Sie, warum ein Festpreis-Modell mit Risiko-Buffern der fairste Weg zu High-End Software-Lösungen ist." +tags: ["management", "business"] +--- diff --git a/apps/web/src/content/posts/gdpr-conformity-system-approach.mdx b/apps/web/src/content/posts/gdpr-conformity-system-approach.mdx new file mode 100644 index 0000000..90fadec --- /dev/null +++ b/apps/web/src/content/posts/gdpr-conformity-system-approach.mdx @@ -0,0 +1,21 @@ +--- +title: "DSGVO-Konformität: Warum Privacy by Design der ultimative B2B-Wettbewerbsvorteil ist" +date: "2026-02-10T00:00:00.000Z" +description: "Vergessen Sie Cookie-Banner. Echte DSGVO-Konformität entsteht durch Privacy by Design und saubere Systemarchitektur. Ein Leitfaden für Digital Architects." +tags: ["legal", "gdpr", "architecture"] +--- + + diff --git a/apps/web/src/content/posts/google-pagespeed-guide-warum-ladezeit-ihr-wichtigster-b2b-umsatzhebel-ist.mdx b/apps/web/src/content/posts/google-pagespeed-guide-warum-ladezeit-ihr-wichtigster-b2b-umsatzhebel-ist.mdx new file mode 100644 index 0000000..876c4f8 --- /dev/null +++ b/apps/web/src/content/posts/google-pagespeed-guide-warum-ladezeit-ihr-wichtigster-b2b-umsatzhebel-ist.mdx @@ -0,0 +1,25 @@ +--- +title: "Google PageSpeed Guide: Warum Ladezeit Ihr wichtigster B2B-Umsatzhebel ist" +date: "2026-02-15T00:00:00.000Z" +description: "Millisekunden entscheiden im B2B über Erfolg oder Absprung. Erfahren Sie, wie Core Web Vitals Ihre Conversion-Rate und SEO-Rankings massiv beeinflussen." +tags: ["performance", "seo", "conversion-optimization"] +--- + + + +**TL;DR:** Website-Geschwindigkeit ist ein kritischer Ranking-Faktor und der stärkste Hebel für Conversions. Während Page-Load-Zeiten von 1s auf 3s die Bounce-Rate um 32 % erhöhen, steigert jede 0,1s Verbesserung die Conversion um bis zu 8,4 %. Moderne Architekturen wie Static Site Generation sind der Schlüssel zur Performance-Exzellenz. + + diff --git a/apps/web/src/content/posts/green-it-sustainable-web.mdx b/apps/web/src/content/posts/green-it-sustainable-web.mdx new file mode 100644 index 0000000..c202f2f --- /dev/null +++ b/apps/web/src/content/posts/green-it-sustainable-web.mdx @@ -0,0 +1,10 @@ +--- +title: "Green IT & Digitale Effizienz: Warum nachhaltiger Code profitabler ist" +date: "2026-02-03T00:00:00.000Z" +description: "Nachhaltigkeit als Rendite-Hebel im B2B: Erfahren Sie, wie schlanke Software-Architekturen CO2 senken, Serverlast reduzieren und Ihre Conversion-Rate maximieren." +tags: ["sustainability", "performance", "digital-architecture"] +--- + + + +**TL;DR:** Nachhaltige IT-Architektur reduziert durch Minimierung von Datenübertragungen und CPU-Zyklen sowohl den ökologischen Fußabdruck als auch die Betriebskosten. Studien belegen, dass schnellere Ladezeiten direkt mit höheren Conversions korrelieren. Wer heute in effizienten Code investiert, baut ein wertstabiles digitales Asset auf. diff --git a/apps/web/src/content/posts/hidden-costs-of-wordpress-plugins.mdx b/apps/web/src/content/posts/hidden-costs-of-wordpress-plugins.mdx new file mode 100644 index 0000000..159a133 --- /dev/null +++ b/apps/web/src/content/posts/hidden-costs-of-wordpress-plugins.mdx @@ -0,0 +1,6 @@ +--- +title: "Die versteckten Kosten von WordPress-Plugins: Performance-Killer & Sicherheitsrisiko" +date: "2026-02-12T00:00:00.000Z" +description: "Warum Plugin-Bloat Ihre B2B-Website verlangsamt und gefährdet. Erfahren Sie, wie eine saubere Architektur die Wartungskosten senkt und den ROI steigert." +tags: ["wordpress", "performance", "security", "digital-architecture"] +--- diff --git a/apps/web/src/content/posts/maintenance-for-headless-systems.mdx b/apps/web/src/content/posts/maintenance-for-headless-systems.mdx new file mode 100644 index 0000000..f7c5835 --- /dev/null +++ b/apps/web/src/content/posts/maintenance-for-headless-systems.mdx @@ -0,0 +1,8 @@ +--- +title: "Wartungsfrei durch Verzicht: Warum " +date: "2026-02-01T00:00:00.000Z" +description: "Sicherheit und Geschwindigkeit durch architektonische Reduktion: Warum Git-basierte Workflows klassische CMS-Backends in Performance und ROI schlagen." +tags: ["maintenance", "architecture"] +--- + + diff --git a/apps/web/src/content/posts/no-us-cloud-platforms.mdx b/apps/web/src/content/posts/no-us-cloud-platforms.mdx new file mode 100644 index 0000000..a99b667 --- /dev/null +++ b/apps/web/src/content/posts/no-us-cloud-platforms.mdx @@ -0,0 +1,6 @@ +--- +title: "US-Cloud-Exit & Souveränität: Warum lokale Infrastruktur der wahre B2B-Standard ist" +date: "2026-02-07T00:00:00.000Z" +description: "Erfahren Sie, wie der US CLOUD Act Ihre Daten bedroht und warum europäische Infrastruktur nicht nur sicherer, sondern durch Latenzvorteile auch profitabler ist." +tags: ["cloud", "privacy", "infrastructure", "compliance"] +--- diff --git a/apps/web/src/content/posts/professional-hosting-operations.mdx b/apps/web/src/content/posts/professional-hosting-operations.mdx new file mode 100644 index 0000000..16e4bc1 --- /dev/null +++ b/apps/web/src/content/posts/professional-hosting-operations.mdx @@ -0,0 +1,15 @@ +--- +title: "Hosting & Infrastructure Overhaul: Das Fundament digitaler Exzellenz" +date: "2026-01-29T00:00:00.000Z" +description: "Vermeiden Sie teure Downtimes und Shared-Hosting-Risiken. Erfahren Sie, wie Industrial-Grade Infrastructure als Code (IaC) Ihre B2B-Plattform unverwüstlich macht." +tags: ["hosting", "operations", "infrastructure"] +--- + + diff --git a/apps/web/src/content/posts/responsive-design-high-fidelity.mdx b/apps/web/src/content/posts/responsive-design-high-fidelity.mdx new file mode 100644 index 0000000..9774afa --- /dev/null +++ b/apps/web/src/content/posts/responsive-design-high-fidelity.mdx @@ -0,0 +1,8 @@ +--- +title: "Responsive Design: Warum mobile Exzellenz über Ihren B2B-Umsatz entscheidet" +date: "2026-01-27T00:00:00.000Z" +description: "Mehr als nur Boxen rücken: Erfahren Sie, wie architektonische Präzision, Core Web Vitals und plattformübergreifende Ergonomie Ihre globale Conversion-Rate massiv steigern." +tags: ["design", "ux", "performance"] +--- + + diff --git a/apps/web/src/content/posts/slow-loading-costs-customers.mdx b/apps/web/src/content/posts/slow-loading-costs-customers.mdx new file mode 100644 index 0000000..9f0be31 --- /dev/null +++ b/apps/web/src/content/posts/slow-loading-costs-customers.mdx @@ -0,0 +1,6 @@ +--- +title: "Der Preis der Trägheit: Wie technische Altlasten Ihren B2B-Umsatz vernichten" +date: "2026-02-14T00:00:00.000Z" +description: "53% der Nutzer springen nach 3 Sekunden ab. Erfahren Sie, warum Web-Performance kein IT-Gadget, sondern Ihr wichtigster betriebswirtschaftlicher Hebel ist." +tags: ["performance", "business-strategy", "conversion-optimization"] +--- diff --git a/apps/web/src/content/posts/website-without-cookie-banners.mdx b/apps/web/src/content/posts/website-without-cookie-banners.mdx new file mode 100644 index 0000000..b14037b --- /dev/null +++ b/apps/web/src/content/posts/website-without-cookie-banners.mdx @@ -0,0 +1,13 @@ +--- +title: "Websites ohne Cookie-Banner: Warum Privacy by Design der neue B2B-Standard ist" +date: "2026-02-06T00:00:00.000Z" +description: "Cookie-Banner sind ein Zeichen für schlechtes Engineering. Erfahren Sie, wie Sie durch eine Cookie-freie Architektur UX, Performance und DSGVO-Konformität brillant vereinen." +tags: ["privacy", "ux", "engineering"] +--- + +A --> G["Standard CMS"] + G --> H["US-Cloud Scripts"] + H --> I["Cookie Banner Pflicht"] + I --> J["Nutzer-Abbruch"] + + diff --git a/apps/web/src/content/posts/why-agencies-are-slow.mdx b/apps/web/src/content/posts/why-agencies-are-slow.mdx new file mode 100644 index 0000000..6c7527b --- /dev/null +++ b/apps/web/src/content/posts/why-agencies-are-slow.mdx @@ -0,0 +1,16 @@ +--- +title: "Warum B2B-Agenturen für kleine Änderungen Wochen brauchen" +date: "2026-02-13T00:00:00.000Z" +description: "Analysieren Sie die versteckten Kosten bürokratischer Agenturprozesse. Erfahren Sie, wie moderne Architektur und radikale Direktheit Ihren Output vervierfachen." +tags: ["architecture", "engineering", "business-strategy"] +--- + +
+ Inhaltsverzeichnis + - [Die "stille Post" der Agentur-Hierarchien](#die-stille-post-der-agentur-hierarchien) + - [Der systemische Interessenkonflikt](#der-systemische-interessenkonflikt) + - [Handwerk statt Fließband: Mein Boutique-Ansatz](#handwerk-statt-fließband-mein-boutique-ansatz) + - [Der Haken an der Sache (Ehrliche Analyse)](#der-haken-an-der-sache) + - [Hebel für doppeltes Tempo](#hebel-für-doppeltes-tempo) + - [FAQ](#faq) +
diff --git a/apps/web/src/content/posts/why-no-templates-matter.mdx b/apps/web/src/content/posts/why-no-templates-matter.mdx new file mode 100644 index 0000000..168ef65 --- /dev/null +++ b/apps/web/src/content/posts/why-no-templates-matter.mdx @@ -0,0 +1,6 @@ +--- +title: "Maßwerk statt Massenware: Warum Templates Ihre B2B-Markenidentität verwässern" +date: "2026-01-28T00:00:00.000Z" +description: "Erfahren Sie, warum Standard-Templates die Silent Killer Ihrer Conversion sind und wie Bespoke-Architektur digitale Distinktion und messbaren ROI schafft." +tags: ["design", "strategy", "performance"] +--- diff --git a/apps/web/src/content/posts/why-websites-break-after-updates.mdx b/apps/web/src/content/posts/why-websites-break-after-updates.mdx new file mode 100644 index 0000000..f524e6b --- /dev/null +++ b/apps/web/src/content/posts/why-websites-break-after-updates.mdx @@ -0,0 +1,8 @@ +--- +title: "Warum Ihre Website nach Updates nicht mehr funktioniert: Strategien gegen den Software-Zerfall" +date: "2026-02-11T00:00:00.000Z" +description: "Fehlerhafte Layouts und kaputte Formulare nach Updates kosten B2B-Vertrauen. Erfahren Sie, wie automatisierte Regressionstests und Headless-Architektur Ihre Website stabilisieren." +tags: ["maintenance", "reliability", "software-engineering"] +--- + + diff --git a/apps/web/src/lib/posts.ts b/apps/web/src/lib/posts.ts index f05e6ed..8d40781 100644 --- a/apps/web/src/lib/posts.ts +++ b/apps/web/src/lib/posts.ts @@ -1,58 +1,37 @@ -import { getPayload } from "payload"; -import configPromise from "@payload-config"; +import fs from "fs"; +import path from "path"; +import matter from "gray-matter"; + +const POSTS_DIR = path.join(process.cwd(), "src/content/posts"); export async function getAllPosts() { - if (!process.env.DATABASE_URI && !process.env.POSTGRES_URI) { - console.warn( - "⚠️ Bypassing Payload fetch during Next.js build: DATABASE_URI is missing.", - ); - return []; - } - try { - const payload = await getPayload({ config: configPromise }); - const { docs } = await payload.find({ - collection: "posts", - limit: 1000, - sort: "-date", - where: { - and: [ - { - _status: { - equals: "published", - }, - }, - { - date: { - less_than_equal: new Date(), - }, - }, - ], - }, - }); + if (!fs.existsSync(POSTS_DIR)) return []; + + const files = fs.readdirSync(POSTS_DIR); + const posts = files + .filter((filename) => filename.endsWith(".mdx")) + .map((filename) => { + const filePath = path.join(POSTS_DIR, filename); + const fileContent = fs.readFileSync(filePath, "utf-8"); + const { data, content } = matter(fileContent); - return docs.map((doc) => ({ - title: doc.title as string, - description: doc.description as string, - date: doc.date as string, - tags: (doc.tags || []).map((t) => - typeof t === "object" && t !== null ? t.tag : t, - ) as string[], - slug: doc.slug as string, - thumbnail: - (doc.featuredImage && - typeof doc.featuredImage === "object" && - doc.featuredImage.url - ? doc.featuredImage.url - : "") || "", - body: { code: "" as string }, - lexicalContent: doc.content || null, - })); + return { + title: data.title || "", + description: data.description || "", + date: data.date || new Date().toISOString(), + tags: data.tags || [], + slug: filename.replace(/\.mdx$/, ""), + thumbnail: data.thumbnail || "", + body: { code: "" }, + lexicalContent: null, + mdxContent: content, + }; + }); + + return posts.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); } catch (error) { - console.warn( - "⚠️ Bypassing Payload fetch during build: Database connection refused.", - error, - ); + console.error("Error reading MDX posts:", error); return []; } } diff --git a/apps/web/src/migrations/20260227_171023_crm_collections.json b/apps/web/src/migrations/20260227_171023_crm_collections.json deleted file mode 100644 index 8bf778e..0000000 --- a/apps/web/src/migrations/20260227_171023_crm_collections.json +++ /dev/null @@ -1,2868 +0,0 @@ -{ - "version": "7", - "dialect": "postgresql", - "tables": { - "public.users_sessions": { - "name": "users_sessions", - "schema": "", - "columns": { - "_order": { - "name": "_order", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "_parent_id": { - "name": "_parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "varchar", - "primaryKey": true, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "users_sessions_order_idx": { - "name": "users_sessions_order_idx", - "columns": [ - { - "expression": "_order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "users_sessions_parent_id_idx": { - "name": "users_sessions_parent_id_idx", - "columns": [ - { - "expression": "_parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "users_sessions_parent_id_fk": { - "name": "users_sessions_parent_id_fk", - "tableFrom": "users_sessions", - "tableTo": "users", - "columnsFrom": ["_parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.users": { - "name": "users", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "email": { - "name": "email", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "reset_password_token": { - "name": "reset_password_token", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "reset_password_expiration": { - "name": "reset_password_expiration", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "salt": { - "name": "salt", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "hash": { - "name": "hash", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "login_attempts": { - "name": "login_attempts", - "type": "numeric", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "lock_until": { - "name": "lock_until", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "users_updated_at_idx": { - "name": "users_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "users_created_at_idx": { - "name": "users_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "users_email_idx": { - "name": "users_email_idx", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.media": { - "name": "media", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "alt": { - "name": "alt", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "prefix": { - "name": "prefix", - "type": "varchar", - "primaryKey": false, - "notNull": false, - "default": "'mintel-me/media'" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "url": { - "name": "url", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "thumbnail_u_r_l": { - "name": "thumbnail_u_r_l", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "filename": { - "name": "filename", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "mime_type": { - "name": "mime_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "filesize": { - "name": "filesize", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "width": { - "name": "width", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "height": { - "name": "height", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "focal_x": { - "name": "focal_x", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "focal_y": { - "name": "focal_y", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_url": { - "name": "sizes_thumbnail_url", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_width": { - "name": "sizes_thumbnail_width", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_height": { - "name": "sizes_thumbnail_height", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_mime_type": { - "name": "sizes_thumbnail_mime_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_filesize": { - "name": "sizes_thumbnail_filesize", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_filename": { - "name": "sizes_thumbnail_filename", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_card_url": { - "name": "sizes_card_url", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_card_width": { - "name": "sizes_card_width", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_card_height": { - "name": "sizes_card_height", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_card_mime_type": { - "name": "sizes_card_mime_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_card_filesize": { - "name": "sizes_card_filesize", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_card_filename": { - "name": "sizes_card_filename", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_url": { - "name": "sizes_tablet_url", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_width": { - "name": "sizes_tablet_width", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_height": { - "name": "sizes_tablet_height", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_mime_type": { - "name": "sizes_tablet_mime_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_filesize": { - "name": "sizes_tablet_filesize", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_filename": { - "name": "sizes_tablet_filename", - "type": "varchar", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "media_updated_at_idx": { - "name": "media_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_created_at_idx": { - "name": "media_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_filename_idx": { - "name": "media_filename_idx", - "columns": [ - { - "expression": "filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_sizes_thumbnail_sizes_thumbnail_filename_idx": { - "name": "media_sizes_thumbnail_sizes_thumbnail_filename_idx", - "columns": [ - { - "expression": "sizes_thumbnail_filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_sizes_card_sizes_card_filename_idx": { - "name": "media_sizes_card_sizes_card_filename_idx", - "columns": [ - { - "expression": "sizes_card_filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_sizes_tablet_sizes_tablet_filename_idx": { - "name": "media_sizes_tablet_sizes_tablet_filename_idx", - "columns": [ - { - "expression": "sizes_tablet_filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.posts_tags": { - "name": "posts_tags", - "schema": "", - "columns": { - "_order": { - "name": "_order", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "_parent_id": { - "name": "_parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "varchar", - "primaryKey": true, - "notNull": true - }, - "tag": { - "name": "tag", - "type": "varchar", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "posts_tags_order_idx": { - "name": "posts_tags_order_idx", - "columns": [ - { - "expression": "_order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts_tags_parent_id_idx": { - "name": "posts_tags_parent_id_idx", - "columns": [ - { - "expression": "_parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "posts_tags_parent_id_fk": { - "name": "posts_tags_parent_id_fk", - "tableFrom": "posts_tags", - "tableTo": "posts", - "columnsFrom": ["_parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.posts": { - "name": "posts", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "slug": { - "name": "slug", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "date": { - "name": "date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "featured_image_id": { - "name": "featured_image_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "content": { - "name": "content", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "_status": { - "name": "_status", - "type": "enum_posts_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": false, - "default": "'draft'" - } - }, - "indexes": { - "posts_slug_idx": { - "name": "posts_slug_idx", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts_featured_image_idx": { - "name": "posts_featured_image_idx", - "columns": [ - { - "expression": "featured_image_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts_updated_at_idx": { - "name": "posts_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts_created_at_idx": { - "name": "posts_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts__status_idx": { - "name": "posts__status_idx", - "columns": [ - { - "expression": "_status", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "posts_featured_image_id_media_id_fk": { - "name": "posts_featured_image_id_media_id_fk", - "tableFrom": "posts", - "tableTo": "media", - "columnsFrom": ["featured_image_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public._posts_v_version_tags": { - "name": "_posts_v_version_tags", - "schema": "", - "columns": { - "_order": { - "name": "_order", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "_parent_id": { - "name": "_parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "tag": { - "name": "tag", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "_uuid": { - "name": "_uuid", - "type": "varchar", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "_posts_v_version_tags_order_idx": { - "name": "_posts_v_version_tags_order_idx", - "columns": [ - { - "expression": "_order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_tags_parent_id_idx": { - "name": "_posts_v_version_tags_parent_id_idx", - "columns": [ - { - "expression": "_parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "_posts_v_version_tags_parent_id_fk": { - "name": "_posts_v_version_tags_parent_id_fk", - "tableFrom": "_posts_v_version_tags", - "tableTo": "_posts_v", - "columnsFrom": ["_parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public._posts_v": { - "name": "_posts_v", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "version_title": { - "name": "version_title", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "version_slug": { - "name": "version_slug", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "version_description": { - "name": "version_description", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "version_date": { - "name": "version_date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "version_featured_image_id": { - "name": "version_featured_image_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "version_content": { - "name": "version_content", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "version_updated_at": { - "name": "version_updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "version_created_at": { - "name": "version_created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "version__status": { - "name": "version__status", - "type": "enum__posts_v_version_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": false, - "default": "'draft'" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "latest": { - "name": "latest", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "_posts_v_parent_idx": { - "name": "_posts_v_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version_slug_idx": { - "name": "_posts_v_version_version_slug_idx", - "columns": [ - { - "expression": "version_slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version_featured_image_idx": { - "name": "_posts_v_version_version_featured_image_idx", - "columns": [ - { - "expression": "version_featured_image_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version_updated_at_idx": { - "name": "_posts_v_version_version_updated_at_idx", - "columns": [ - { - "expression": "version_updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version_created_at_idx": { - "name": "_posts_v_version_version_created_at_idx", - "columns": [ - { - "expression": "version_created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version__status_idx": { - "name": "_posts_v_version_version__status_idx", - "columns": [ - { - "expression": "version__status", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_created_at_idx": { - "name": "_posts_v_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_updated_at_idx": { - "name": "_posts_v_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_latest_idx": { - "name": "_posts_v_latest_idx", - "columns": [ - { - "expression": "latest", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "_posts_v_parent_id_posts_id_fk": { - "name": "_posts_v_parent_id_posts_id_fk", - "tableFrom": "_posts_v", - "tableTo": "posts", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - }, - "_posts_v_version_featured_image_id_media_id_fk": { - "name": "_posts_v_version_featured_image_id_media_id_fk", - "tableFrom": "_posts_v", - "tableTo": "media", - "columnsFrom": ["version_featured_image_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.inquiries": { - "name": "inquiries", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "company_name": { - "name": "company_name", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "project_type": { - "name": "project_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "message": { - "name": "message", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "is_free_text": { - "name": "is_free_text", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "config": { - "name": "config", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "inquiries_updated_at_idx": { - "name": "inquiries_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "inquiries_created_at_idx": { - "name": "inquiries_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.redirects": { - "name": "redirects", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "from": { - "name": "from", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "to": { - "name": "to", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "redirects_from_idx": { - "name": "redirects_from_idx", - "columns": [ - { - "expression": "from", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "redirects_updated_at_idx": { - "name": "redirects_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "redirects_created_at_idx": { - "name": "redirects_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.context_files": { - "name": "context_files", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "filename": { - "name": "filename", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "content": { - "name": "content", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "context_files_filename_idx": { - "name": "context_files_filename_idx", - "columns": [ - { - "expression": "filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "context_files_updated_at_idx": { - "name": "context_files_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "context_files_created_at_idx": { - "name": "context_files_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_accounts": { - "name": "crm_accounts", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "website": { - "name": "website", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "enum_crm_accounts_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": false, - "default": "'lead'" - }, - "lead_temperature": { - "name": "lead_temperature", - "type": "enum_crm_accounts_lead_temperature", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "assigned_to_id": { - "name": "assigned_to_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "crm_accounts_assigned_to_idx": { - "name": "crm_accounts_assigned_to_idx", - "columns": [ - { - "expression": "assigned_to_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_updated_at_idx": { - "name": "crm_accounts_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_created_at_idx": { - "name": "crm_accounts_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_accounts_assigned_to_id_users_id_fk": { - "name": "crm_accounts_assigned_to_id_users_id_fk", - "tableFrom": "crm_accounts", - "tableTo": "users", - "columnsFrom": ["assigned_to_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_accounts_rels": { - "name": "crm_accounts_rels", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "media_id": { - "name": "media_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "crm_accounts_rels_order_idx": { - "name": "crm_accounts_rels_order_idx", - "columns": [ - { - "expression": "order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_rels_parent_idx": { - "name": "crm_accounts_rels_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_rels_path_idx": { - "name": "crm_accounts_rels_path_idx", - "columns": [ - { - "expression": "path", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_rels_media_id_idx": { - "name": "crm_accounts_rels_media_id_idx", - "columns": [ - { - "expression": "media_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_accounts_rels_parent_fk": { - "name": "crm_accounts_rels_parent_fk", - "tableFrom": "crm_accounts_rels", - "tableTo": "crm_accounts", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "crm_accounts_rels_media_fk": { - "name": "crm_accounts_rels_media_fk", - "tableFrom": "crm_accounts_rels", - "tableTo": "media", - "columnsFrom": ["media_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_contacts": { - "name": "crm_contacts", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "first_name": { - "name": "first_name", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "last_name": { - "name": "last_name", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "phone": { - "name": "phone", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "linked_in": { - "name": "linked_in", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "role": { - "name": "role", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "account_id": { - "name": "account_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "crm_contacts_email_idx": { - "name": "crm_contacts_email_idx", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_contacts_account_idx": { - "name": "crm_contacts_account_idx", - "columns": [ - { - "expression": "account_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_contacts_updated_at_idx": { - "name": "crm_contacts_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_contacts_created_at_idx": { - "name": "crm_contacts_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_contacts_account_id_crm_accounts_id_fk": { - "name": "crm_contacts_account_id_crm_accounts_id_fk", - "tableFrom": "crm_contacts", - "tableTo": "crm_accounts", - "columnsFrom": ["account_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_interactions": { - "name": "crm_interactions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "type": { - "name": "type", - "type": "enum_crm_interactions_type", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'email'" - }, - "direction": { - "name": "direction", - "type": "enum_crm_interactions_direction", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "date": { - "name": "date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true - }, - "contact_id": { - "name": "contact_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "account_id": { - "name": "account_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "subject": { - "name": "subject", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "content": { - "name": "content", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "crm_interactions_contact_idx": { - "name": "crm_interactions_contact_idx", - "columns": [ - { - "expression": "contact_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_account_idx": { - "name": "crm_interactions_account_idx", - "columns": [ - { - "expression": "account_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_updated_at_idx": { - "name": "crm_interactions_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_created_at_idx": { - "name": "crm_interactions_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_interactions_contact_id_crm_contacts_id_fk": { - "name": "crm_interactions_contact_id_crm_contacts_id_fk", - "tableFrom": "crm_interactions", - "tableTo": "crm_contacts", - "columnsFrom": ["contact_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - }, - "crm_interactions_account_id_crm_accounts_id_fk": { - "name": "crm_interactions_account_id_crm_accounts_id_fk", - "tableFrom": "crm_interactions", - "tableTo": "crm_accounts", - "columnsFrom": ["account_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_kv": { - "name": "payload_kv", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "key": { - "name": "key", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "payload_kv_key_idx": { - "name": "payload_kv_key_idx", - "columns": [ - { - "expression": "key", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_locked_documents": { - "name": "payload_locked_documents", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "global_slug": { - "name": "global_slug", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "payload_locked_documents_global_slug_idx": { - "name": "payload_locked_documents_global_slug_idx", - "columns": [ - { - "expression": "global_slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_updated_at_idx": { - "name": "payload_locked_documents_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_created_at_idx": { - "name": "payload_locked_documents_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_locked_documents_rels": { - "name": "payload_locked_documents_rels", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "users_id": { - "name": "users_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "media_id": { - "name": "media_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "posts_id": { - "name": "posts_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "inquiries_id": { - "name": "inquiries_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "redirects_id": { - "name": "redirects_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "context_files_id": { - "name": "context_files_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "crm_accounts_id": { - "name": "crm_accounts_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "crm_contacts_id": { - "name": "crm_contacts_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "crm_interactions_id": { - "name": "crm_interactions_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "payload_locked_documents_rels_order_idx": { - "name": "payload_locked_documents_rels_order_idx", - "columns": [ - { - "expression": "order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_parent_idx": { - "name": "payload_locked_documents_rels_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_path_idx": { - "name": "payload_locked_documents_rels_path_idx", - "columns": [ - { - "expression": "path", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_users_id_idx": { - "name": "payload_locked_documents_rels_users_id_idx", - "columns": [ - { - "expression": "users_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_media_id_idx": { - "name": "payload_locked_documents_rels_media_id_idx", - "columns": [ - { - "expression": "media_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_posts_id_idx": { - "name": "payload_locked_documents_rels_posts_id_idx", - "columns": [ - { - "expression": "posts_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_inquiries_id_idx": { - "name": "payload_locked_documents_rels_inquiries_id_idx", - "columns": [ - { - "expression": "inquiries_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_redirects_id_idx": { - "name": "payload_locked_documents_rels_redirects_id_idx", - "columns": [ - { - "expression": "redirects_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_context_files_id_idx": { - "name": "payload_locked_documents_rels_context_files_id_idx", - "columns": [ - { - "expression": "context_files_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_crm_accounts_id_idx": { - "name": "payload_locked_documents_rels_crm_accounts_id_idx", - "columns": [ - { - "expression": "crm_accounts_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_crm_contacts_id_idx": { - "name": "payload_locked_documents_rels_crm_contacts_id_idx", - "columns": [ - { - "expression": "crm_contacts_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_crm_interactions_id_idx": { - "name": "payload_locked_documents_rels_crm_interactions_id_idx", - "columns": [ - { - "expression": "crm_interactions_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "payload_locked_documents_rels_parent_fk": { - "name": "payload_locked_documents_rels_parent_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "payload_locked_documents", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_users_fk": { - "name": "payload_locked_documents_rels_users_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "users", - "columnsFrom": ["users_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_media_fk": { - "name": "payload_locked_documents_rels_media_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "media", - "columnsFrom": ["media_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_posts_fk": { - "name": "payload_locked_documents_rels_posts_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "posts", - "columnsFrom": ["posts_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_inquiries_fk": { - "name": "payload_locked_documents_rels_inquiries_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "inquiries", - "columnsFrom": ["inquiries_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_redirects_fk": { - "name": "payload_locked_documents_rels_redirects_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "redirects", - "columnsFrom": ["redirects_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_context_files_fk": { - "name": "payload_locked_documents_rels_context_files_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "context_files", - "columnsFrom": ["context_files_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_crm_accounts_fk": { - "name": "payload_locked_documents_rels_crm_accounts_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "crm_accounts", - "columnsFrom": ["crm_accounts_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_crm_contacts_fk": { - "name": "payload_locked_documents_rels_crm_contacts_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "crm_contacts", - "columnsFrom": ["crm_contacts_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_crm_interactions_fk": { - "name": "payload_locked_documents_rels_crm_interactions_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "crm_interactions", - "columnsFrom": ["crm_interactions_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_preferences": { - "name": "payload_preferences", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "key": { - "name": "key", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "value": { - "name": "value", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "payload_preferences_key_idx": { - "name": "payload_preferences_key_idx", - "columns": [ - { - "expression": "key", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_updated_at_idx": { - "name": "payload_preferences_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_created_at_idx": { - "name": "payload_preferences_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_preferences_rels": { - "name": "payload_preferences_rels", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "users_id": { - "name": "users_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "payload_preferences_rels_order_idx": { - "name": "payload_preferences_rels_order_idx", - "columns": [ - { - "expression": "order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_rels_parent_idx": { - "name": "payload_preferences_rels_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_rels_path_idx": { - "name": "payload_preferences_rels_path_idx", - "columns": [ - { - "expression": "path", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_rels_users_id_idx": { - "name": "payload_preferences_rels_users_id_idx", - "columns": [ - { - "expression": "users_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "payload_preferences_rels_parent_fk": { - "name": "payload_preferences_rels_parent_fk", - "tableFrom": "payload_preferences_rels", - "tableTo": "payload_preferences", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_preferences_rels_users_fk": { - "name": "payload_preferences_rels_users_fk", - "tableFrom": "payload_preferences_rels", - "tableTo": "users", - "columnsFrom": ["users_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_migrations": { - "name": "payload_migrations", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "batch": { - "name": "batch", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "payload_migrations_updated_at_idx": { - "name": "payload_migrations_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_migrations_created_at_idx": { - "name": "payload_migrations_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.ai_settings_custom_sources": { - "name": "ai_settings_custom_sources", - "schema": "", - "columns": { - "_order": { - "name": "_order", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "_parent_id": { - "name": "_parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "varchar", - "primaryKey": true, - "notNull": true - }, - "source_name": { - "name": "source_name", - "type": "varchar", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "ai_settings_custom_sources_order_idx": { - "name": "ai_settings_custom_sources_order_idx", - "columns": [ - { - "expression": "_order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "ai_settings_custom_sources_parent_id_idx": { - "name": "ai_settings_custom_sources_parent_id_idx", - "columns": [ - { - "expression": "_parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "ai_settings_custom_sources_parent_id_fk": { - "name": "ai_settings_custom_sources_parent_id_fk", - "tableFrom": "ai_settings_custom_sources", - "tableTo": "ai_settings", - "columnsFrom": ["_parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.ai_settings": { - "name": "ai_settings", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": { - "public.enum_posts_status": { - "name": "enum_posts_status", - "schema": "public", - "values": ["draft", "published"] - }, - "public.enum__posts_v_version_status": { - "name": "enum__posts_v_version_status", - "schema": "public", - "values": ["draft", "published"] - }, - "public.enum_crm_accounts_status": { - "name": "enum_crm_accounts_status", - "schema": "public", - "values": ["lead", "client", "lost"] - }, - "public.enum_crm_accounts_lead_temperature": { - "name": "enum_crm_accounts_lead_temperature", - "schema": "public", - "values": ["cold", "warm", "hot"] - }, - "public.enum_crm_interactions_type": { - "name": "enum_crm_interactions_type", - "schema": "public", - "values": ["email", "call", "meeting", "note"] - }, - "public.enum_crm_interactions_direction": { - "name": "enum_crm_interactions_direction", - "schema": "public", - "values": ["inbound", "outbound"] - } - }, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "id": "d9155237-d4aa-4d52-8925-98fc9fd2ea5d", - "prevId": "00000000-0000-0000-0000-000000000000" -} diff --git a/apps/web/src/migrations/20260227_171023_crm_collections.ts b/apps/web/src/migrations/20260227_171023_crm_collections.ts deleted file mode 100644 index 256c0f0..0000000 --- a/apps/web/src/migrations/20260227_171023_crm_collections.ts +++ /dev/null @@ -1,392 +0,0 @@ -import { MigrateUpArgs, MigrateDownArgs, sql } from "@payloadcms/db-postgres"; - -export async function up({ db, payload, req }: MigrateUpArgs): Promise { - await db.execute(sql` - CREATE TYPE "public"."enum_posts_status" AS ENUM('draft', 'published'); - CREATE TYPE "public"."enum__posts_v_version_status" AS ENUM('draft', 'published'); - CREATE TYPE "public"."enum_crm_accounts_status" AS ENUM('lead', 'client', 'lost'); - CREATE TYPE "public"."enum_crm_accounts_lead_temperature" AS ENUM('cold', 'warm', 'hot'); - CREATE TYPE "public"."enum_crm_interactions_type" AS ENUM('email', 'call', 'meeting', 'note'); - CREATE TYPE "public"."enum_crm_interactions_direction" AS ENUM('inbound', 'outbound'); - CREATE TABLE "users_sessions" ( - "_order" integer NOT NULL, - "_parent_id" integer NOT NULL, - "id" varchar PRIMARY KEY NOT NULL, - "created_at" timestamp(3) with time zone, - "expires_at" timestamp(3) with time zone NOT NULL - ); - - CREATE TABLE "users" ( - "id" serial PRIMARY KEY NOT NULL, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "email" varchar NOT NULL, - "reset_password_token" varchar, - "reset_password_expiration" timestamp(3) with time zone, - "salt" varchar, - "hash" varchar, - "login_attempts" numeric DEFAULT 0, - "lock_until" timestamp(3) with time zone - ); - - CREATE TABLE "media" ( - "id" serial PRIMARY KEY NOT NULL, - "alt" varchar NOT NULL, - "prefix" varchar DEFAULT 'mintel-me/media', - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "url" varchar, - "thumbnail_u_r_l" varchar, - "filename" varchar, - "mime_type" varchar, - "filesize" numeric, - "width" numeric, - "height" numeric, - "focal_x" numeric, - "focal_y" numeric, - "sizes_thumbnail_url" varchar, - "sizes_thumbnail_width" numeric, - "sizes_thumbnail_height" numeric, - "sizes_thumbnail_mime_type" varchar, - "sizes_thumbnail_filesize" numeric, - "sizes_thumbnail_filename" varchar, - "sizes_card_url" varchar, - "sizes_card_width" numeric, - "sizes_card_height" numeric, - "sizes_card_mime_type" varchar, - "sizes_card_filesize" numeric, - "sizes_card_filename" varchar, - "sizes_tablet_url" varchar, - "sizes_tablet_width" numeric, - "sizes_tablet_height" numeric, - "sizes_tablet_mime_type" varchar, - "sizes_tablet_filesize" numeric, - "sizes_tablet_filename" varchar - ); - - CREATE TABLE "posts_tags" ( - "_order" integer NOT NULL, - "_parent_id" integer NOT NULL, - "id" varchar PRIMARY KEY NOT NULL, - "tag" varchar - ); - - CREATE TABLE "posts" ( - "id" serial PRIMARY KEY NOT NULL, - "title" varchar, - "slug" varchar, - "description" varchar, - "date" timestamp(3) with time zone, - "featured_image_id" integer, - "content" jsonb, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "_status" "enum_posts_status" DEFAULT 'draft' - ); - - CREATE TABLE "_posts_v_version_tags" ( - "_order" integer NOT NULL, - "_parent_id" integer NOT NULL, - "id" serial PRIMARY KEY NOT NULL, - "tag" varchar, - "_uuid" varchar - ); - - CREATE TABLE "_posts_v" ( - "id" serial PRIMARY KEY NOT NULL, - "parent_id" integer, - "version_title" varchar, - "version_slug" varchar, - "version_description" varchar, - "version_date" timestamp(3) with time zone, - "version_featured_image_id" integer, - "version_content" jsonb, - "version_updated_at" timestamp(3) with time zone, - "version_created_at" timestamp(3) with time zone, - "version__status" "enum__posts_v_version_status" DEFAULT 'draft', - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "latest" boolean - ); - - CREATE TABLE "inquiries" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar NOT NULL, - "email" varchar NOT NULL, - "company_name" varchar, - "project_type" varchar, - "message" varchar, - "is_free_text" boolean DEFAULT false, - "config" jsonb, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "redirects" ( - "id" serial PRIMARY KEY NOT NULL, - "from" varchar NOT NULL, - "to" varchar NOT NULL, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "context_files" ( - "id" serial PRIMARY KEY NOT NULL, - "filename" varchar NOT NULL, - "content" varchar NOT NULL, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "crm_accounts" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar NOT NULL, - "website" varchar, - "status" "enum_crm_accounts_status" DEFAULT 'lead', - "lead_temperature" "enum_crm_accounts_lead_temperature", - "assigned_to_id" integer, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "crm_accounts_rels" ( - "id" serial PRIMARY KEY NOT NULL, - "order" integer, - "parent_id" integer NOT NULL, - "path" varchar NOT NULL, - "media_id" integer - ); - - CREATE TABLE "crm_contacts" ( - "id" serial PRIMARY KEY NOT NULL, - "first_name" varchar NOT NULL, - "last_name" varchar NOT NULL, - "email" varchar NOT NULL, - "phone" varchar, - "linked_in" varchar, - "role" varchar, - "account_id" integer, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "crm_interactions" ( - "id" serial PRIMARY KEY NOT NULL, - "type" "enum_crm_interactions_type" DEFAULT 'email' NOT NULL, - "direction" "enum_crm_interactions_direction", - "date" timestamp(3) with time zone NOT NULL, - "contact_id" integer, - "account_id" integer, - "subject" varchar NOT NULL, - "content" jsonb, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "payload_kv" ( - "id" serial PRIMARY KEY NOT NULL, - "key" varchar NOT NULL, - "data" jsonb NOT NULL - ); - - CREATE TABLE "payload_locked_documents" ( - "id" serial PRIMARY KEY NOT NULL, - "global_slug" varchar, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "payload_locked_documents_rels" ( - "id" serial PRIMARY KEY NOT NULL, - "order" integer, - "parent_id" integer NOT NULL, - "path" varchar NOT NULL, - "users_id" integer, - "media_id" integer, - "posts_id" integer, - "inquiries_id" integer, - "redirects_id" integer, - "context_files_id" integer, - "crm_accounts_id" integer, - "crm_contacts_id" integer, - "crm_interactions_id" integer - ); - - CREATE TABLE "payload_preferences" ( - "id" serial PRIMARY KEY NOT NULL, - "key" varchar, - "value" jsonb, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "payload_preferences_rels" ( - "id" serial PRIMARY KEY NOT NULL, - "order" integer, - "parent_id" integer NOT NULL, - "path" varchar NOT NULL, - "users_id" integer - ); - - CREATE TABLE "payload_migrations" ( - "id" serial PRIMARY KEY NOT NULL, - "name" varchar, - "batch" numeric, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "ai_settings_custom_sources" ( - "_order" integer NOT NULL, - "_parent_id" integer NOT NULL, - "id" varchar PRIMARY KEY NOT NULL, - "source_name" varchar NOT NULL - ); - - CREATE TABLE "ai_settings" ( - "id" serial PRIMARY KEY NOT NULL, - "updated_at" timestamp(3) with time zone, - "created_at" timestamp(3) with time zone - ); - - ALTER TABLE "users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "posts_tags" ADD CONSTRAINT "posts_tags_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."posts"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "posts" ADD CONSTRAINT "posts_featured_image_id_media_id_fk" FOREIGN KEY ("featured_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "_posts_v_version_tags" ADD CONSTRAINT "_posts_v_version_tags_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_posts_v"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "_posts_v" ADD CONSTRAINT "_posts_v_parent_id_posts_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."posts"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "_posts_v" ADD CONSTRAINT "_posts_v_version_featured_image_id_media_id_fk" FOREIGN KEY ("version_featured_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "crm_accounts" ADD CONSTRAINT "crm_accounts_assigned_to_id_users_id_fk" FOREIGN KEY ("assigned_to_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "crm_accounts_rels" ADD CONSTRAINT "crm_accounts_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."crm_accounts"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "crm_accounts_rels" ADD CONSTRAINT "crm_accounts_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "crm_contacts" ADD CONSTRAINT "crm_contacts_account_id_crm_accounts_id_fk" FOREIGN KEY ("account_id") REFERENCES "public"."crm_accounts"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "crm_interactions" ADD CONSTRAINT "crm_interactions_contact_id_crm_contacts_id_fk" FOREIGN KEY ("contact_id") REFERENCES "public"."crm_contacts"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "crm_interactions" ADD CONSTRAINT "crm_interactions_account_id_crm_accounts_id_fk" FOREIGN KEY ("account_id") REFERENCES "public"."crm_accounts"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_posts_fk" FOREIGN KEY ("posts_id") REFERENCES "public"."posts"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_inquiries_fk" FOREIGN KEY ("inquiries_id") REFERENCES "public"."inquiries"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_redirects_fk" FOREIGN KEY ("redirects_id") REFERENCES "public"."redirects"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_context_files_fk" FOREIGN KEY ("context_files_id") REFERENCES "public"."context_files"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_crm_accounts_fk" FOREIGN KEY ("crm_accounts_id") REFERENCES "public"."crm_accounts"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_crm_contacts_fk" FOREIGN KEY ("crm_contacts_id") REFERENCES "public"."crm_contacts"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_crm_interactions_fk" FOREIGN KEY ("crm_interactions_id") REFERENCES "public"."crm_interactions"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "ai_settings_custom_sources" ADD CONSTRAINT "ai_settings_custom_sources_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."ai_settings"("id") ON DELETE cascade ON UPDATE no action; - CREATE INDEX "users_sessions_order_idx" ON "users_sessions" USING btree ("_order"); - CREATE INDEX "users_sessions_parent_id_idx" ON "users_sessions" USING btree ("_parent_id"); - CREATE INDEX "users_updated_at_idx" ON "users" USING btree ("updated_at"); - CREATE INDEX "users_created_at_idx" ON "users" USING btree ("created_at"); - CREATE UNIQUE INDEX "users_email_idx" ON "users" USING btree ("email"); - CREATE INDEX "media_updated_at_idx" ON "media" USING btree ("updated_at"); - CREATE INDEX "media_created_at_idx" ON "media" USING btree ("created_at"); - CREATE UNIQUE INDEX "media_filename_idx" ON "media" USING btree ("filename"); - CREATE INDEX "media_sizes_thumbnail_sizes_thumbnail_filename_idx" ON "media" USING btree ("sizes_thumbnail_filename"); - CREATE INDEX "media_sizes_card_sizes_card_filename_idx" ON "media" USING btree ("sizes_card_filename"); - CREATE INDEX "media_sizes_tablet_sizes_tablet_filename_idx" ON "media" USING btree ("sizes_tablet_filename"); - CREATE INDEX "posts_tags_order_idx" ON "posts_tags" USING btree ("_order"); - CREATE INDEX "posts_tags_parent_id_idx" ON "posts_tags" USING btree ("_parent_id"); - CREATE UNIQUE INDEX "posts_slug_idx" ON "posts" USING btree ("slug"); - CREATE INDEX "posts_featured_image_idx" ON "posts" USING btree ("featured_image_id"); - CREATE INDEX "posts_updated_at_idx" ON "posts" USING btree ("updated_at"); - CREATE INDEX "posts_created_at_idx" ON "posts" USING btree ("created_at"); - CREATE INDEX "posts__status_idx" ON "posts" USING btree ("_status"); - CREATE INDEX "_posts_v_version_tags_order_idx" ON "_posts_v_version_tags" USING btree ("_order"); - CREATE INDEX "_posts_v_version_tags_parent_id_idx" ON "_posts_v_version_tags" USING btree ("_parent_id"); - CREATE INDEX "_posts_v_parent_idx" ON "_posts_v" USING btree ("parent_id"); - CREATE INDEX "_posts_v_version_version_slug_idx" ON "_posts_v" USING btree ("version_slug"); - CREATE INDEX "_posts_v_version_version_featured_image_idx" ON "_posts_v" USING btree ("version_featured_image_id"); - CREATE INDEX "_posts_v_version_version_updated_at_idx" ON "_posts_v" USING btree ("version_updated_at"); - CREATE INDEX "_posts_v_version_version_created_at_idx" ON "_posts_v" USING btree ("version_created_at"); - CREATE INDEX "_posts_v_version_version__status_idx" ON "_posts_v" USING btree ("version__status"); - CREATE INDEX "_posts_v_created_at_idx" ON "_posts_v" USING btree ("created_at"); - CREATE INDEX "_posts_v_updated_at_idx" ON "_posts_v" USING btree ("updated_at"); - CREATE INDEX "_posts_v_latest_idx" ON "_posts_v" USING btree ("latest"); - CREATE INDEX "inquiries_updated_at_idx" ON "inquiries" USING btree ("updated_at"); - CREATE INDEX "inquiries_created_at_idx" ON "inquiries" USING btree ("created_at"); - CREATE UNIQUE INDEX "redirects_from_idx" ON "redirects" USING btree ("from"); - CREATE INDEX "redirects_updated_at_idx" ON "redirects" USING btree ("updated_at"); - CREATE INDEX "redirects_created_at_idx" ON "redirects" USING btree ("created_at"); - CREATE UNIQUE INDEX "context_files_filename_idx" ON "context_files" USING btree ("filename"); - CREATE INDEX "context_files_updated_at_idx" ON "context_files" USING btree ("updated_at"); - CREATE INDEX "context_files_created_at_idx" ON "context_files" USING btree ("created_at"); - CREATE INDEX "crm_accounts_assigned_to_idx" ON "crm_accounts" USING btree ("assigned_to_id"); - CREATE INDEX "crm_accounts_updated_at_idx" ON "crm_accounts" USING btree ("updated_at"); - CREATE INDEX "crm_accounts_created_at_idx" ON "crm_accounts" USING btree ("created_at"); - CREATE INDEX "crm_accounts_rels_order_idx" ON "crm_accounts_rels" USING btree ("order"); - CREATE INDEX "crm_accounts_rels_parent_idx" ON "crm_accounts_rels" USING btree ("parent_id"); - CREATE INDEX "crm_accounts_rels_path_idx" ON "crm_accounts_rels" USING btree ("path"); - CREATE INDEX "crm_accounts_rels_media_id_idx" ON "crm_accounts_rels" USING btree ("media_id"); - CREATE UNIQUE INDEX "crm_contacts_email_idx" ON "crm_contacts" USING btree ("email"); - CREATE INDEX "crm_contacts_account_idx" ON "crm_contacts" USING btree ("account_id"); - CREATE INDEX "crm_contacts_updated_at_idx" ON "crm_contacts" USING btree ("updated_at"); - CREATE INDEX "crm_contacts_created_at_idx" ON "crm_contacts" USING btree ("created_at"); - CREATE INDEX "crm_interactions_contact_idx" ON "crm_interactions" USING btree ("contact_id"); - CREATE INDEX "crm_interactions_account_idx" ON "crm_interactions" USING btree ("account_id"); - CREATE INDEX "crm_interactions_updated_at_idx" ON "crm_interactions" USING btree ("updated_at"); - CREATE INDEX "crm_interactions_created_at_idx" ON "crm_interactions" USING btree ("created_at"); - CREATE UNIQUE INDEX "payload_kv_key_idx" ON "payload_kv" USING btree ("key"); - CREATE INDEX "payload_locked_documents_global_slug_idx" ON "payload_locked_documents" USING btree ("global_slug"); - CREATE INDEX "payload_locked_documents_updated_at_idx" ON "payload_locked_documents" USING btree ("updated_at"); - CREATE INDEX "payload_locked_documents_created_at_idx" ON "payload_locked_documents" USING btree ("created_at"); - CREATE INDEX "payload_locked_documents_rels_order_idx" ON "payload_locked_documents_rels" USING btree ("order"); - CREATE INDEX "payload_locked_documents_rels_parent_idx" ON "payload_locked_documents_rels" USING btree ("parent_id"); - CREATE INDEX "payload_locked_documents_rels_path_idx" ON "payload_locked_documents_rels" USING btree ("path"); - CREATE INDEX "payload_locked_documents_rels_users_id_idx" ON "payload_locked_documents_rels" USING btree ("users_id"); - CREATE INDEX "payload_locked_documents_rels_media_id_idx" ON "payload_locked_documents_rels" USING btree ("media_id"); - CREATE INDEX "payload_locked_documents_rels_posts_id_idx" ON "payload_locked_documents_rels" USING btree ("posts_id"); - CREATE INDEX "payload_locked_documents_rels_inquiries_id_idx" ON "payload_locked_documents_rels" USING btree ("inquiries_id"); - CREATE INDEX "payload_locked_documents_rels_redirects_id_idx" ON "payload_locked_documents_rels" USING btree ("redirects_id"); - CREATE INDEX "payload_locked_documents_rels_context_files_id_idx" ON "payload_locked_documents_rels" USING btree ("context_files_id"); - CREATE INDEX "payload_locked_documents_rels_crm_accounts_id_idx" ON "payload_locked_documents_rels" USING btree ("crm_accounts_id"); - CREATE INDEX "payload_locked_documents_rels_crm_contacts_id_idx" ON "payload_locked_documents_rels" USING btree ("crm_contacts_id"); - CREATE INDEX "payload_locked_documents_rels_crm_interactions_id_idx" ON "payload_locked_documents_rels" USING btree ("crm_interactions_id"); - CREATE INDEX "payload_preferences_key_idx" ON "payload_preferences" USING btree ("key"); - CREATE INDEX "payload_preferences_updated_at_idx" ON "payload_preferences" USING btree ("updated_at"); - CREATE INDEX "payload_preferences_created_at_idx" ON "payload_preferences" USING btree ("created_at"); - CREATE INDEX "payload_preferences_rels_order_idx" ON "payload_preferences_rels" USING btree ("order"); - CREATE INDEX "payload_preferences_rels_parent_idx" ON "payload_preferences_rels" USING btree ("parent_id"); - CREATE INDEX "payload_preferences_rels_path_idx" ON "payload_preferences_rels" USING btree ("path"); - CREATE INDEX "payload_preferences_rels_users_id_idx" ON "payload_preferences_rels" USING btree ("users_id"); - CREATE INDEX "payload_migrations_updated_at_idx" ON "payload_migrations" USING btree ("updated_at"); - CREATE INDEX "payload_migrations_created_at_idx" ON "payload_migrations" USING btree ("created_at"); - CREATE INDEX "ai_settings_custom_sources_order_idx" ON "ai_settings_custom_sources" USING btree ("_order"); - CREATE INDEX "ai_settings_custom_sources_parent_id_idx" ON "ai_settings_custom_sources" USING btree ("_parent_id");`); -} - -export async function down({ - db, - payload, - req, -}: MigrateDownArgs): Promise { - await db.execute(sql` - DROP TABLE "users_sessions" CASCADE; - DROP TABLE "users" CASCADE; - DROP TABLE "media" CASCADE; - DROP TABLE "posts_tags" CASCADE; - DROP TABLE "posts" CASCADE; - DROP TABLE "_posts_v_version_tags" CASCADE; - DROP TABLE "_posts_v" CASCADE; - DROP TABLE "inquiries" CASCADE; - DROP TABLE "redirects" CASCADE; - DROP TABLE "context_files" CASCADE; - DROP TABLE "crm_accounts" CASCADE; - DROP TABLE "crm_accounts_rels" CASCADE; - DROP TABLE "crm_contacts" CASCADE; - DROP TABLE "crm_interactions" CASCADE; - DROP TABLE "payload_kv" CASCADE; - DROP TABLE "payload_locked_documents" CASCADE; - DROP TABLE "payload_locked_documents_rels" CASCADE; - DROP TABLE "payload_preferences" CASCADE; - DROP TABLE "payload_preferences_rels" CASCADE; - DROP TABLE "payload_migrations" CASCADE; - DROP TABLE "ai_settings_custom_sources" CASCADE; - DROP TABLE "ai_settings" CASCADE; - DROP TYPE "public"."enum_posts_status"; - DROP TYPE "public"."enum__posts_v_version_status"; - DROP TYPE "public"."enum_crm_accounts_status"; - DROP TYPE "public"."enum_crm_accounts_lead_temperature"; - DROP TYPE "public"."enum_crm_interactions_type"; - DROP TYPE "public"."enum_crm_interactions_direction";`); -} diff --git a/apps/web/src/migrations/20260301_151838.json b/apps/web/src/migrations/20260301_151838.json deleted file mode 100644 index 6e97b69..0000000 --- a/apps/web/src/migrations/20260301_151838.json +++ /dev/null @@ -1,3671 +0,0 @@ -{ - "version": "7", - "dialect": "postgresql", - "tables": { - "public.users_sessions": { - "name": "users_sessions", - "schema": "", - "columns": { - "_order": { - "name": "_order", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "_parent_id": { - "name": "_parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "varchar", - "primaryKey": true, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "users_sessions_order_idx": { - "name": "users_sessions_order_idx", - "columns": [ - { - "expression": "_order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "users_sessions_parent_id_idx": { - "name": "users_sessions_parent_id_idx", - "columns": [ - { - "expression": "_parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "users_sessions_parent_id_fk": { - "name": "users_sessions_parent_id_fk", - "tableFrom": "users_sessions", - "tableTo": "users", - "columnsFrom": ["_parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.users": { - "name": "users", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "email": { - "name": "email", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "reset_password_token": { - "name": "reset_password_token", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "reset_password_expiration": { - "name": "reset_password_expiration", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "salt": { - "name": "salt", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "hash": { - "name": "hash", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "login_attempts": { - "name": "login_attempts", - "type": "numeric", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "lock_until": { - "name": "lock_until", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "users_updated_at_idx": { - "name": "users_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "users_created_at_idx": { - "name": "users_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "users_email_idx": { - "name": "users_email_idx", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.media": { - "name": "media", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "alt": { - "name": "alt", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "prefix": { - "name": "prefix", - "type": "varchar", - "primaryKey": false, - "notNull": false, - "default": "'mintel-me/media'" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "url": { - "name": "url", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "thumbnail_u_r_l": { - "name": "thumbnail_u_r_l", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "filename": { - "name": "filename", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "mime_type": { - "name": "mime_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "filesize": { - "name": "filesize", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "width": { - "name": "width", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "height": { - "name": "height", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "focal_x": { - "name": "focal_x", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "focal_y": { - "name": "focal_y", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_url": { - "name": "sizes_thumbnail_url", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_width": { - "name": "sizes_thumbnail_width", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_height": { - "name": "sizes_thumbnail_height", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_mime_type": { - "name": "sizes_thumbnail_mime_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_filesize": { - "name": "sizes_thumbnail_filesize", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_thumbnail_filename": { - "name": "sizes_thumbnail_filename", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_card_url": { - "name": "sizes_card_url", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_card_width": { - "name": "sizes_card_width", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_card_height": { - "name": "sizes_card_height", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_card_mime_type": { - "name": "sizes_card_mime_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_card_filesize": { - "name": "sizes_card_filesize", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_card_filename": { - "name": "sizes_card_filename", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_url": { - "name": "sizes_tablet_url", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_width": { - "name": "sizes_tablet_width", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_height": { - "name": "sizes_tablet_height", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_mime_type": { - "name": "sizes_tablet_mime_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_filesize": { - "name": "sizes_tablet_filesize", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "sizes_tablet_filename": { - "name": "sizes_tablet_filename", - "type": "varchar", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "media_updated_at_idx": { - "name": "media_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_created_at_idx": { - "name": "media_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_filename_idx": { - "name": "media_filename_idx", - "columns": [ - { - "expression": "filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_sizes_thumbnail_sizes_thumbnail_filename_idx": { - "name": "media_sizes_thumbnail_sizes_thumbnail_filename_idx", - "columns": [ - { - "expression": "sizes_thumbnail_filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_sizes_card_sizes_card_filename_idx": { - "name": "media_sizes_card_sizes_card_filename_idx", - "columns": [ - { - "expression": "sizes_card_filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "media_sizes_tablet_sizes_tablet_filename_idx": { - "name": "media_sizes_tablet_sizes_tablet_filename_idx", - "columns": [ - { - "expression": "sizes_tablet_filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.posts_tags": { - "name": "posts_tags", - "schema": "", - "columns": { - "_order": { - "name": "_order", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "_parent_id": { - "name": "_parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "varchar", - "primaryKey": true, - "notNull": true - }, - "tag": { - "name": "tag", - "type": "varchar", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "posts_tags_order_idx": { - "name": "posts_tags_order_idx", - "columns": [ - { - "expression": "_order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts_tags_parent_id_idx": { - "name": "posts_tags_parent_id_idx", - "columns": [ - { - "expression": "_parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "posts_tags_parent_id_fk": { - "name": "posts_tags_parent_id_fk", - "tableFrom": "posts_tags", - "tableTo": "posts", - "columnsFrom": ["_parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.posts": { - "name": "posts", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "slug": { - "name": "slug", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "date": { - "name": "date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "featured_image_id": { - "name": "featured_image_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "content": { - "name": "content", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "_status": { - "name": "_status", - "type": "enum_posts_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": false, - "default": "'draft'" - } - }, - "indexes": { - "posts_slug_idx": { - "name": "posts_slug_idx", - "columns": [ - { - "expression": "slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts_featured_image_idx": { - "name": "posts_featured_image_idx", - "columns": [ - { - "expression": "featured_image_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts_updated_at_idx": { - "name": "posts_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts_created_at_idx": { - "name": "posts_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "posts__status_idx": { - "name": "posts__status_idx", - "columns": [ - { - "expression": "_status", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "posts_featured_image_id_media_id_fk": { - "name": "posts_featured_image_id_media_id_fk", - "tableFrom": "posts", - "tableTo": "media", - "columnsFrom": ["featured_image_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public._posts_v_version_tags": { - "name": "_posts_v_version_tags", - "schema": "", - "columns": { - "_order": { - "name": "_order", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "_parent_id": { - "name": "_parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "tag": { - "name": "tag", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "_uuid": { - "name": "_uuid", - "type": "varchar", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "_posts_v_version_tags_order_idx": { - "name": "_posts_v_version_tags_order_idx", - "columns": [ - { - "expression": "_order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_tags_parent_id_idx": { - "name": "_posts_v_version_tags_parent_id_idx", - "columns": [ - { - "expression": "_parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "_posts_v_version_tags_parent_id_fk": { - "name": "_posts_v_version_tags_parent_id_fk", - "tableFrom": "_posts_v_version_tags", - "tableTo": "_posts_v", - "columnsFrom": ["_parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public._posts_v": { - "name": "_posts_v", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "version_title": { - "name": "version_title", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "version_slug": { - "name": "version_slug", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "version_description": { - "name": "version_description", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "version_date": { - "name": "version_date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "version_featured_image_id": { - "name": "version_featured_image_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "version_content": { - "name": "version_content", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "version_updated_at": { - "name": "version_updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "version_created_at": { - "name": "version_created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "version__status": { - "name": "version__status", - "type": "enum__posts_v_version_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": false, - "default": "'draft'" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "latest": { - "name": "latest", - "type": "boolean", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "_posts_v_parent_idx": { - "name": "_posts_v_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version_slug_idx": { - "name": "_posts_v_version_version_slug_idx", - "columns": [ - { - "expression": "version_slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version_featured_image_idx": { - "name": "_posts_v_version_version_featured_image_idx", - "columns": [ - { - "expression": "version_featured_image_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version_updated_at_idx": { - "name": "_posts_v_version_version_updated_at_idx", - "columns": [ - { - "expression": "version_updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version_created_at_idx": { - "name": "_posts_v_version_version_created_at_idx", - "columns": [ - { - "expression": "version_created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_version_version__status_idx": { - "name": "_posts_v_version_version__status_idx", - "columns": [ - { - "expression": "version__status", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_created_at_idx": { - "name": "_posts_v_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_updated_at_idx": { - "name": "_posts_v_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "_posts_v_latest_idx": { - "name": "_posts_v_latest_idx", - "columns": [ - { - "expression": "latest", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "_posts_v_parent_id_posts_id_fk": { - "name": "_posts_v_parent_id_posts_id_fk", - "tableFrom": "_posts_v", - "tableTo": "posts", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - }, - "_posts_v_version_featured_image_id_media_id_fk": { - "name": "_posts_v_version_featured_image_id_media_id_fk", - "tableFrom": "_posts_v", - "tableTo": "media", - "columnsFrom": ["version_featured_image_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.inquiries": { - "name": "inquiries", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "processed": { - "name": "processed", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "name": { - "name": "name", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "company_name": { - "name": "company_name", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "project_type": { - "name": "project_type", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "message": { - "name": "message", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "is_free_text": { - "name": "is_free_text", - "type": "boolean", - "primaryKey": false, - "notNull": false, - "default": false - }, - "config": { - "name": "config", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "inquiries_updated_at_idx": { - "name": "inquiries_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "inquiries_created_at_idx": { - "name": "inquiries_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.redirects": { - "name": "redirects", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "from": { - "name": "from", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "to": { - "name": "to", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "redirects_from_idx": { - "name": "redirects_from_idx", - "columns": [ - { - "expression": "from", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "redirects_updated_at_idx": { - "name": "redirects_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "redirects_created_at_idx": { - "name": "redirects_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.context_files": { - "name": "context_files", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "filename": { - "name": "filename", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "content": { - "name": "content", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "context_files_filename_idx": { - "name": "context_files_filename_idx", - "columns": [ - { - "expression": "filename", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "context_files_updated_at_idx": { - "name": "context_files_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "context_files_created_at_idx": { - "name": "context_files_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_accounts": { - "name": "crm_accounts", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "website": { - "name": "website", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "enum_crm_accounts_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": false, - "default": "'lead'" - }, - "lead_temperature": { - "name": "lead_temperature", - "type": "enum_crm_accounts_lead_temperature", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "assigned_to_id": { - "name": "assigned_to_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "crm_accounts_assigned_to_idx": { - "name": "crm_accounts_assigned_to_idx", - "columns": [ - { - "expression": "assigned_to_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_updated_at_idx": { - "name": "crm_accounts_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_created_at_idx": { - "name": "crm_accounts_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_accounts_assigned_to_id_users_id_fk": { - "name": "crm_accounts_assigned_to_id_users_id_fk", - "tableFrom": "crm_accounts", - "tableTo": "users", - "columnsFrom": ["assigned_to_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_accounts_rels": { - "name": "crm_accounts_rels", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "media_id": { - "name": "media_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "crm_accounts_rels_order_idx": { - "name": "crm_accounts_rels_order_idx", - "columns": [ - { - "expression": "order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_rels_parent_idx": { - "name": "crm_accounts_rels_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_rels_path_idx": { - "name": "crm_accounts_rels_path_idx", - "columns": [ - { - "expression": "path", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_accounts_rels_media_id_idx": { - "name": "crm_accounts_rels_media_id_idx", - "columns": [ - { - "expression": "media_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_accounts_rels_parent_fk": { - "name": "crm_accounts_rels_parent_fk", - "tableFrom": "crm_accounts_rels", - "tableTo": "crm_accounts", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "crm_accounts_rels_media_fk": { - "name": "crm_accounts_rels_media_fk", - "tableFrom": "crm_accounts_rels", - "tableTo": "media", - "columnsFrom": ["media_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_contacts": { - "name": "crm_contacts", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "full_name": { - "name": "full_name", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "first_name": { - "name": "first_name", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "last_name": { - "name": "last_name", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "phone": { - "name": "phone", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "linked_in": { - "name": "linked_in", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "role": { - "name": "role", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "account_id": { - "name": "account_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "crm_contacts_email_idx": { - "name": "crm_contacts_email_idx", - "columns": [ - { - "expression": "email", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_contacts_account_idx": { - "name": "crm_contacts_account_idx", - "columns": [ - { - "expression": "account_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_contacts_updated_at_idx": { - "name": "crm_contacts_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_contacts_created_at_idx": { - "name": "crm_contacts_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_contacts_account_id_crm_accounts_id_fk": { - "name": "crm_contacts_account_id_crm_accounts_id_fk", - "tableFrom": "crm_contacts", - "tableTo": "crm_accounts", - "columnsFrom": ["account_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_topics": { - "name": "crm_topics", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "account_id": { - "name": "account_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "status": { - "name": "status", - "type": "enum_crm_topics_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'active'" - }, - "stage": { - "name": "stage", - "type": "enum_crm_topics_stage", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "crm_topics_account_idx": { - "name": "crm_topics_account_idx", - "columns": [ - { - "expression": "account_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_topics_updated_at_idx": { - "name": "crm_topics_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_topics_created_at_idx": { - "name": "crm_topics_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_topics_account_id_crm_accounts_id_fk": { - "name": "crm_topics_account_id_crm_accounts_id_fk", - "tableFrom": "crm_topics", - "tableTo": "crm_accounts", - "columnsFrom": ["account_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_interactions": { - "name": "crm_interactions", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "type": { - "name": "type", - "type": "enum_crm_interactions_type", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'note'" - }, - "direction": { - "name": "direction", - "type": "enum_crm_interactions_direction", - "typeSchema": "public", - "primaryKey": false, - "notNull": false - }, - "date": { - "name": "date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true - }, - "subject": { - "name": "subject", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "contact_id": { - "name": "contact_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "account_id": { - "name": "account_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "topic_id": { - "name": "topic_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "content": { - "name": "content", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "crm_interactions_contact_idx": { - "name": "crm_interactions_contact_idx", - "columns": [ - { - "expression": "contact_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_account_idx": { - "name": "crm_interactions_account_idx", - "columns": [ - { - "expression": "account_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_topic_idx": { - "name": "crm_interactions_topic_idx", - "columns": [ - { - "expression": "topic_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_updated_at_idx": { - "name": "crm_interactions_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_created_at_idx": { - "name": "crm_interactions_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_interactions_contact_id_crm_contacts_id_fk": { - "name": "crm_interactions_contact_id_crm_contacts_id_fk", - "tableFrom": "crm_interactions", - "tableTo": "crm_contacts", - "columnsFrom": ["contact_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - }, - "crm_interactions_account_id_crm_accounts_id_fk": { - "name": "crm_interactions_account_id_crm_accounts_id_fk", - "tableFrom": "crm_interactions", - "tableTo": "crm_accounts", - "columnsFrom": ["account_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - }, - "crm_interactions_topic_id_crm_topics_id_fk": { - "name": "crm_interactions_topic_id_crm_topics_id_fk", - "tableFrom": "crm_interactions", - "tableTo": "crm_topics", - "columnsFrom": ["topic_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.crm_interactions_rels": { - "name": "crm_interactions_rels", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "media_id": { - "name": "media_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "crm_interactions_rels_order_idx": { - "name": "crm_interactions_rels_order_idx", - "columns": [ - { - "expression": "order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_rels_parent_idx": { - "name": "crm_interactions_rels_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_rels_path_idx": { - "name": "crm_interactions_rels_path_idx", - "columns": [ - { - "expression": "path", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "crm_interactions_rels_media_id_idx": { - "name": "crm_interactions_rels_media_id_idx", - "columns": [ - { - "expression": "media_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "crm_interactions_rels_parent_fk": { - "name": "crm_interactions_rels_parent_fk", - "tableFrom": "crm_interactions_rels", - "tableTo": "crm_interactions", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "crm_interactions_rels_media_fk": { - "name": "crm_interactions_rels_media_fk", - "tableFrom": "crm_interactions_rels", - "tableTo": "media", - "columnsFrom": ["media_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.projects_milestones": { - "name": "projects_milestones", - "schema": "", - "columns": { - "_order": { - "name": "_order", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "_parent_id": { - "name": "_parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "varchar", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "status": { - "name": "status", - "type": "enum_projects_milestones_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'todo'" - }, - "priority": { - "name": "priority", - "type": "enum_projects_milestones_priority", - "typeSchema": "public", - "primaryKey": false, - "notNull": false, - "default": "'medium'" - }, - "start_date": { - "name": "start_date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "target_date": { - "name": "target_date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "assignee_id": { - "name": "assignee_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "projects_milestones_order_idx": { - "name": "projects_milestones_order_idx", - "columns": [ - { - "expression": "_order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "projects_milestones_parent_id_idx": { - "name": "projects_milestones_parent_id_idx", - "columns": [ - { - "expression": "_parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "projects_milestones_assignee_idx": { - "name": "projects_milestones_assignee_idx", - "columns": [ - { - "expression": "assignee_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "projects_milestones_assignee_id_users_id_fk": { - "name": "projects_milestones_assignee_id_users_id_fk", - "tableFrom": "projects_milestones", - "tableTo": "users", - "columnsFrom": ["assignee_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - }, - "projects_milestones_parent_id_fk": { - "name": "projects_milestones_parent_id_fk", - "tableFrom": "projects_milestones", - "tableTo": "projects", - "columnsFrom": ["_parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.projects": { - "name": "projects", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "account_id": { - "name": "account_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "status": { - "name": "status", - "type": "enum_projects_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'draft'" - }, - "start_date": { - "name": "start_date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "target_date": { - "name": "target_date", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "value_min": { - "name": "value_min", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "value_max": { - "name": "value_max", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "briefing": { - "name": "briefing", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "projects_account_idx": { - "name": "projects_account_idx", - "columns": [ - { - "expression": "account_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "projects_updated_at_idx": { - "name": "projects_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "projects_created_at_idx": { - "name": "projects_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "projects_account_id_crm_accounts_id_fk": { - "name": "projects_account_id_crm_accounts_id_fk", - "tableFrom": "projects", - "tableTo": "crm_accounts", - "columnsFrom": ["account_id"], - "columnsTo": ["id"], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.projects_rels": { - "name": "projects_rels", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "crm_contacts_id": { - "name": "crm_contacts_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "media_id": { - "name": "media_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "projects_rels_order_idx": { - "name": "projects_rels_order_idx", - "columns": [ - { - "expression": "order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "projects_rels_parent_idx": { - "name": "projects_rels_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "projects_rels_path_idx": { - "name": "projects_rels_path_idx", - "columns": [ - { - "expression": "path", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "projects_rels_crm_contacts_id_idx": { - "name": "projects_rels_crm_contacts_id_idx", - "columns": [ - { - "expression": "crm_contacts_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "projects_rels_media_id_idx": { - "name": "projects_rels_media_id_idx", - "columns": [ - { - "expression": "media_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "projects_rels_parent_fk": { - "name": "projects_rels_parent_fk", - "tableFrom": "projects_rels", - "tableTo": "projects", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "projects_rels_crm_contacts_fk": { - "name": "projects_rels_crm_contacts_fk", - "tableFrom": "projects_rels", - "tableTo": "crm_contacts", - "columnsFrom": ["crm_contacts_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "projects_rels_media_fk": { - "name": "projects_rels_media_fk", - "tableFrom": "projects_rels", - "tableTo": "media", - "columnsFrom": ["media_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_kv": { - "name": "payload_kv", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "key": { - "name": "key", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "payload_kv_key_idx": { - "name": "payload_kv_key_idx", - "columns": [ - { - "expression": "key", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": true, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_locked_documents": { - "name": "payload_locked_documents", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "global_slug": { - "name": "global_slug", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "payload_locked_documents_global_slug_idx": { - "name": "payload_locked_documents_global_slug_idx", - "columns": [ - { - "expression": "global_slug", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_updated_at_idx": { - "name": "payload_locked_documents_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_created_at_idx": { - "name": "payload_locked_documents_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_locked_documents_rels": { - "name": "payload_locked_documents_rels", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "users_id": { - "name": "users_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "media_id": { - "name": "media_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "posts_id": { - "name": "posts_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "inquiries_id": { - "name": "inquiries_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "redirects_id": { - "name": "redirects_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "context_files_id": { - "name": "context_files_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "crm_accounts_id": { - "name": "crm_accounts_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "crm_contacts_id": { - "name": "crm_contacts_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "crm_topics_id": { - "name": "crm_topics_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "crm_interactions_id": { - "name": "crm_interactions_id", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "projects_id": { - "name": "projects_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "payload_locked_documents_rels_order_idx": { - "name": "payload_locked_documents_rels_order_idx", - "columns": [ - { - "expression": "order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_parent_idx": { - "name": "payload_locked_documents_rels_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_path_idx": { - "name": "payload_locked_documents_rels_path_idx", - "columns": [ - { - "expression": "path", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_users_id_idx": { - "name": "payload_locked_documents_rels_users_id_idx", - "columns": [ - { - "expression": "users_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_media_id_idx": { - "name": "payload_locked_documents_rels_media_id_idx", - "columns": [ - { - "expression": "media_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_posts_id_idx": { - "name": "payload_locked_documents_rels_posts_id_idx", - "columns": [ - { - "expression": "posts_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_inquiries_id_idx": { - "name": "payload_locked_documents_rels_inquiries_id_idx", - "columns": [ - { - "expression": "inquiries_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_redirects_id_idx": { - "name": "payload_locked_documents_rels_redirects_id_idx", - "columns": [ - { - "expression": "redirects_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_context_files_id_idx": { - "name": "payload_locked_documents_rels_context_files_id_idx", - "columns": [ - { - "expression": "context_files_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_crm_accounts_id_idx": { - "name": "payload_locked_documents_rels_crm_accounts_id_idx", - "columns": [ - { - "expression": "crm_accounts_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_crm_contacts_id_idx": { - "name": "payload_locked_documents_rels_crm_contacts_id_idx", - "columns": [ - { - "expression": "crm_contacts_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_crm_topics_id_idx": { - "name": "payload_locked_documents_rels_crm_topics_id_idx", - "columns": [ - { - "expression": "crm_topics_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_crm_interactions_id_idx": { - "name": "payload_locked_documents_rels_crm_interactions_id_idx", - "columns": [ - { - "expression": "crm_interactions_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_locked_documents_rels_projects_id_idx": { - "name": "payload_locked_documents_rels_projects_id_idx", - "columns": [ - { - "expression": "projects_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "payload_locked_documents_rels_parent_fk": { - "name": "payload_locked_documents_rels_parent_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "payload_locked_documents", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_users_fk": { - "name": "payload_locked_documents_rels_users_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "users", - "columnsFrom": ["users_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_media_fk": { - "name": "payload_locked_documents_rels_media_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "media", - "columnsFrom": ["media_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_posts_fk": { - "name": "payload_locked_documents_rels_posts_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "posts", - "columnsFrom": ["posts_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_inquiries_fk": { - "name": "payload_locked_documents_rels_inquiries_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "inquiries", - "columnsFrom": ["inquiries_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_redirects_fk": { - "name": "payload_locked_documents_rels_redirects_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "redirects", - "columnsFrom": ["redirects_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_context_files_fk": { - "name": "payload_locked_documents_rels_context_files_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "context_files", - "columnsFrom": ["context_files_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_crm_accounts_fk": { - "name": "payload_locked_documents_rels_crm_accounts_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "crm_accounts", - "columnsFrom": ["crm_accounts_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_crm_contacts_fk": { - "name": "payload_locked_documents_rels_crm_contacts_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "crm_contacts", - "columnsFrom": ["crm_contacts_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_crm_topics_fk": { - "name": "payload_locked_documents_rels_crm_topics_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "crm_topics", - "columnsFrom": ["crm_topics_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_crm_interactions_fk": { - "name": "payload_locked_documents_rels_crm_interactions_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "crm_interactions", - "columnsFrom": ["crm_interactions_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_projects_fk": { - "name": "payload_locked_documents_rels_projects_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "projects", - "columnsFrom": ["projects_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_preferences": { - "name": "payload_preferences", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "key": { - "name": "key", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "value": { - "name": "value", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "payload_preferences_key_idx": { - "name": "payload_preferences_key_idx", - "columns": [ - { - "expression": "key", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_updated_at_idx": { - "name": "payload_preferences_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_created_at_idx": { - "name": "payload_preferences_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_preferences_rels": { - "name": "payload_preferences_rels", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "varchar", - "primaryKey": false, - "notNull": true - }, - "users_id": { - "name": "users_id", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": { - "payload_preferences_rels_order_idx": { - "name": "payload_preferences_rels_order_idx", - "columns": [ - { - "expression": "order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_rels_parent_idx": { - "name": "payload_preferences_rels_parent_idx", - "columns": [ - { - "expression": "parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_rels_path_idx": { - "name": "payload_preferences_rels_path_idx", - "columns": [ - { - "expression": "path", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_preferences_rels_users_id_idx": { - "name": "payload_preferences_rels_users_id_idx", - "columns": [ - { - "expression": "users_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "payload_preferences_rels_parent_fk": { - "name": "payload_preferences_rels_parent_fk", - "tableFrom": "payload_preferences_rels", - "tableTo": "payload_preferences", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_preferences_rels_users_fk": { - "name": "payload_preferences_rels_users_fk", - "tableFrom": "payload_preferences_rels", - "tableTo": "users", - "columnsFrom": ["users_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.payload_migrations": { - "name": "payload_migrations", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "varchar", - "primaryKey": false, - "notNull": false - }, - "batch": { - "name": "batch", - "type": "numeric", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": { - "payload_migrations_updated_at_idx": { - "name": "payload_migrations_updated_at_idx", - "columns": [ - { - "expression": "updated_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "payload_migrations_created_at_idx": { - "name": "payload_migrations_created_at_idx", - "columns": [ - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.ai_settings_custom_sources": { - "name": "ai_settings_custom_sources", - "schema": "", - "columns": { - "_order": { - "name": "_order", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "_parent_id": { - "name": "_parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "varchar", - "primaryKey": true, - "notNull": true - }, - "source_name": { - "name": "source_name", - "type": "varchar", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "ai_settings_custom_sources_order_idx": { - "name": "ai_settings_custom_sources_order_idx", - "columns": [ - { - "expression": "_order", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - }, - "ai_settings_custom_sources_parent_id_idx": { - "name": "ai_settings_custom_sources_parent_id_idx", - "columns": [ - { - "expression": "_parent_id", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "ai_settings_custom_sources_parent_id_fk": { - "name": "ai_settings_custom_sources_parent_id_fk", - "tableFrom": "ai_settings_custom_sources", - "tableTo": "ai_settings", - "columnsFrom": ["_parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.ai_settings": { - "name": "ai_settings", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "serial", - "primaryKey": true, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp(3) with time zone", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": { - "public.enum_posts_status": { - "name": "enum_posts_status", - "schema": "public", - "values": ["draft", "published"] - }, - "public.enum__posts_v_version_status": { - "name": "enum__posts_v_version_status", - "schema": "public", - "values": ["draft", "published"] - }, - "public.enum_crm_accounts_status": { - "name": "enum_crm_accounts_status", - "schema": "public", - "values": ["lead", "client", "partner", "lost"] - }, - "public.enum_crm_accounts_lead_temperature": { - "name": "enum_crm_accounts_lead_temperature", - "schema": "public", - "values": ["cold", "warm", "hot"] - }, - "public.enum_crm_topics_status": { - "name": "enum_crm_topics_status", - "schema": "public", - "values": ["active", "paused", "won", "lost"] - }, - "public.enum_crm_topics_stage": { - "name": "enum_crm_topics_stage", - "schema": "public", - "values": ["discovery", "proposal", "negotiation", "implementation"] - }, - "public.enum_crm_interactions_type": { - "name": "enum_crm_interactions_type", - "schema": "public", - "values": [ - "email", - "call", - "meeting", - "whatsapp", - "social", - "document", - "note" - ] - }, - "public.enum_crm_interactions_direction": { - "name": "enum_crm_interactions_direction", - "schema": "public", - "values": ["inbound", "outbound"] - }, - "public.enum_projects_milestones_status": { - "name": "enum_projects_milestones_status", - "schema": "public", - "values": ["todo", "in_progress", "done"] - }, - "public.enum_projects_milestones_priority": { - "name": "enum_projects_milestones_priority", - "schema": "public", - "values": ["low", "medium", "high"] - }, - "public.enum_projects_status": { - "name": "enum_projects_status", - "schema": "public", - "values": ["draft", "in_progress", "review", "completed"] - } - }, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "id": "766409a0-4873-48a0-93e9-c6252b2b97c7", - "prevId": "00000000-0000-0000-0000-000000000000" -} diff --git a/apps/web/src/migrations/20260301_151838.ts b/apps/web/src/migrations/20260301_151838.ts deleted file mode 100644 index 75553e1..0000000 --- a/apps/web/src/migrations/20260301_151838.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { MigrateUpArgs, MigrateDownArgs, sql } from "@payloadcms/db-postgres"; - -export async function up({ db, payload, req }: MigrateUpArgs): Promise { - await db.execute(sql` - CREATE TYPE "public"."enum_crm_topics_status" AS ENUM('active', 'paused', 'won', 'lost'); - CREATE TYPE "public"."enum_crm_topics_stage" AS ENUM('discovery', 'proposal', 'negotiation', 'implementation'); - CREATE TYPE "public"."enum_projects_milestones_status" AS ENUM('todo', 'in_progress', 'done'); - CREATE TYPE "public"."enum_projects_milestones_priority" AS ENUM('low', 'medium', 'high'); - CREATE TYPE "public"."enum_projects_status" AS ENUM('draft', 'in_progress', 'review', 'completed'); - ALTER TYPE "public"."enum_crm_accounts_status" ADD VALUE 'partner' BEFORE 'lost'; - ALTER TYPE "public"."enum_crm_interactions_type" ADD VALUE 'whatsapp' BEFORE 'note'; - ALTER TYPE "public"."enum_crm_interactions_type" ADD VALUE 'social' BEFORE 'note'; - ALTER TYPE "public"."enum_crm_interactions_type" ADD VALUE 'document' BEFORE 'note'; - CREATE TABLE "crm_topics" ( - "id" serial PRIMARY KEY NOT NULL, - "title" varchar NOT NULL, - "account_id" integer NOT NULL, - "status" "enum_crm_topics_status" DEFAULT 'active' NOT NULL, - "stage" "enum_crm_topics_stage", - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "crm_interactions_rels" ( - "id" serial PRIMARY KEY NOT NULL, - "order" integer, - "parent_id" integer NOT NULL, - "path" varchar NOT NULL, - "media_id" integer - ); - - CREATE TABLE "projects_milestones" ( - "_order" integer NOT NULL, - "_parent_id" integer NOT NULL, - "id" varchar PRIMARY KEY NOT NULL, - "name" varchar NOT NULL, - "status" "enum_projects_milestones_status" DEFAULT 'todo' NOT NULL, - "priority" "enum_projects_milestones_priority" DEFAULT 'medium', - "start_date" timestamp(3) with time zone, - "target_date" timestamp(3) with time zone, - "assignee_id" integer - ); - - CREATE TABLE "projects" ( - "id" serial PRIMARY KEY NOT NULL, - "title" varchar NOT NULL, - "account_id" integer NOT NULL, - "status" "enum_projects_status" DEFAULT 'draft' NOT NULL, - "start_date" timestamp(3) with time zone, - "target_date" timestamp(3) with time zone, - "value_min" numeric, - "value_max" numeric, - "briefing" jsonb, - "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL, - "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL - ); - - CREATE TABLE "projects_rels" ( - "id" serial PRIMARY KEY NOT NULL, - "order" integer, - "parent_id" integer NOT NULL, - "path" varchar NOT NULL, - "crm_contacts_id" integer, - "media_id" integer - ); - - ALTER TABLE "crm_interactions" ALTER COLUMN "type" SET DEFAULT 'note'; - ALTER TABLE "inquiries" ADD COLUMN "processed" boolean DEFAULT false; - ALTER TABLE "crm_contacts" ADD COLUMN "full_name" varchar; - ALTER TABLE "crm_interactions" ADD COLUMN "topic_id" integer; - ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "crm_topics_id" integer; - ALTER TABLE "payload_locked_documents_rels" ADD COLUMN "projects_id" integer; - ALTER TABLE "crm_topics" ADD CONSTRAINT "crm_topics_account_id_crm_accounts_id_fk" FOREIGN KEY ("account_id") REFERENCES "public"."crm_accounts"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "crm_interactions_rels" ADD CONSTRAINT "crm_interactions_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."crm_interactions"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "crm_interactions_rels" ADD CONSTRAINT "crm_interactions_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "projects_milestones" ADD CONSTRAINT "projects_milestones_assignee_id_users_id_fk" FOREIGN KEY ("assignee_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "projects_milestones" ADD CONSTRAINT "projects_milestones_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "projects" ADD CONSTRAINT "projects_account_id_crm_accounts_id_fk" FOREIGN KEY ("account_id") REFERENCES "public"."crm_accounts"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "projects_rels" ADD CONSTRAINT "projects_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "projects_rels" ADD CONSTRAINT "projects_rels_crm_contacts_fk" FOREIGN KEY ("crm_contacts_id") REFERENCES "public"."crm_contacts"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "projects_rels" ADD CONSTRAINT "projects_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action; - CREATE INDEX "crm_topics_account_idx" ON "crm_topics" USING btree ("account_id"); - CREATE INDEX "crm_topics_updated_at_idx" ON "crm_topics" USING btree ("updated_at"); - CREATE INDEX "crm_topics_created_at_idx" ON "crm_topics" USING btree ("created_at"); - CREATE INDEX "crm_interactions_rels_order_idx" ON "crm_interactions_rels" USING btree ("order"); - CREATE INDEX "crm_interactions_rels_parent_idx" ON "crm_interactions_rels" USING btree ("parent_id"); - CREATE INDEX "crm_interactions_rels_path_idx" ON "crm_interactions_rels" USING btree ("path"); - CREATE INDEX "crm_interactions_rels_media_id_idx" ON "crm_interactions_rels" USING btree ("media_id"); - CREATE INDEX "projects_milestones_order_idx" ON "projects_milestones" USING btree ("_order"); - CREATE INDEX "projects_milestones_parent_id_idx" ON "projects_milestones" USING btree ("_parent_id"); - CREATE INDEX "projects_milestones_assignee_idx" ON "projects_milestones" USING btree ("assignee_id"); - CREATE INDEX "projects_account_idx" ON "projects" USING btree ("account_id"); - CREATE INDEX "projects_updated_at_idx" ON "projects" USING btree ("updated_at"); - CREATE INDEX "projects_created_at_idx" ON "projects" USING btree ("created_at"); - CREATE INDEX "projects_rels_order_idx" ON "projects_rels" USING btree ("order"); - CREATE INDEX "projects_rels_parent_idx" ON "projects_rels" USING btree ("parent_id"); - CREATE INDEX "projects_rels_path_idx" ON "projects_rels" USING btree ("path"); - CREATE INDEX "projects_rels_crm_contacts_id_idx" ON "projects_rels" USING btree ("crm_contacts_id"); - CREATE INDEX "projects_rels_media_id_idx" ON "projects_rels" USING btree ("media_id"); - ALTER TABLE "crm_interactions" ADD CONSTRAINT "crm_interactions_topic_id_crm_topics_id_fk" FOREIGN KEY ("topic_id") REFERENCES "public"."crm_topics"("id") ON DELETE set null ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_crm_topics_fk" FOREIGN KEY ("crm_topics_id") REFERENCES "public"."crm_topics"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_projects_fk" FOREIGN KEY ("projects_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action; - CREATE INDEX "crm_interactions_topic_idx" ON "crm_interactions" USING btree ("topic_id"); - CREATE INDEX "payload_locked_documents_rels_crm_topics_id_idx" ON "payload_locked_documents_rels" USING btree ("crm_topics_id"); - CREATE INDEX "payload_locked_documents_rels_projects_id_idx" ON "payload_locked_documents_rels" USING btree ("projects_id");`); -} - -export async function down({ - db, - payload, - req, -}: MigrateDownArgs): Promise { - await db.execute(sql` - ALTER TABLE "crm_topics" DISABLE ROW LEVEL SECURITY; - ALTER TABLE "crm_interactions_rels" DISABLE ROW LEVEL SECURITY; - ALTER TABLE "projects_milestones" DISABLE ROW LEVEL SECURITY; - ALTER TABLE "projects" DISABLE ROW LEVEL SECURITY; - ALTER TABLE "projects_rels" DISABLE ROW LEVEL SECURITY; - DROP TABLE "crm_topics" CASCADE; - DROP TABLE "crm_interactions_rels" CASCADE; - DROP TABLE "projects_milestones" CASCADE; - DROP TABLE "projects" CASCADE; - DROP TABLE "projects_rels" CASCADE; - ALTER TABLE "crm_interactions" DROP CONSTRAINT "crm_interactions_topic_id_crm_topics_id_fk"; - - ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_crm_topics_fk"; - - ALTER TABLE "payload_locked_documents_rels" DROP CONSTRAINT "payload_locked_documents_rels_projects_fk"; - - ALTER TABLE "crm_accounts" ALTER COLUMN "status" SET DATA TYPE text; - ALTER TABLE "crm_accounts" ALTER COLUMN "status" SET DEFAULT 'lead'::text; - DROP TYPE "public"."enum_crm_accounts_status"; - CREATE TYPE "public"."enum_crm_accounts_status" AS ENUM('lead', 'client', 'lost'); - ALTER TABLE "crm_accounts" ALTER COLUMN "status" SET DEFAULT 'lead'::"public"."enum_crm_accounts_status"; - ALTER TABLE "crm_accounts" ALTER COLUMN "status" SET DATA TYPE "public"."enum_crm_accounts_status" USING "status"::"public"."enum_crm_accounts_status"; - ALTER TABLE "crm_interactions" ALTER COLUMN "type" SET DATA TYPE text; - ALTER TABLE "crm_interactions" ALTER COLUMN "type" SET DEFAULT 'email'::text; - DROP TYPE "public"."enum_crm_interactions_type"; - CREATE TYPE "public"."enum_crm_interactions_type" AS ENUM('email', 'call', 'meeting', 'note'); - ALTER TABLE "crm_interactions" ALTER COLUMN "type" SET DEFAULT 'email'::"public"."enum_crm_interactions_type"; - ALTER TABLE "crm_interactions" ALTER COLUMN "type" SET DATA TYPE "public"."enum_crm_interactions_type" USING "type"::"public"."enum_crm_interactions_type"; - DROP INDEX "crm_interactions_topic_idx"; - DROP INDEX "payload_locked_documents_rels_crm_topics_id_idx"; - DROP INDEX "payload_locked_documents_rels_projects_id_idx"; - ALTER TABLE "inquiries" DROP COLUMN "processed"; - ALTER TABLE "crm_contacts" DROP COLUMN "full_name"; - ALTER TABLE "crm_interactions" DROP COLUMN "topic_id"; - ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "crm_topics_id"; - ALTER TABLE "payload_locked_documents_rels" DROP COLUMN "projects_id"; - DROP TYPE "public"."enum_crm_topics_status"; - DROP TYPE "public"."enum_crm_topics_stage"; - DROP TYPE "public"."enum_projects_milestones_status"; - DROP TYPE "public"."enum_projects_milestones_priority"; - DROP TYPE "public"."enum_projects_status";`); -} diff --git a/apps/web/src/migrations/index.ts b/apps/web/src/migrations/index.ts deleted file mode 100644 index ffe055d..0000000 --- a/apps/web/src/migrations/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as migration_20260227_171023_crm_collections from "./20260227_171023_crm_collections"; -import * as migration_20260301_151838 from "./20260301_151838"; - -export const migrations = [ - { - up: migration_20260227_171023_crm_collections.up, - down: migration_20260227_171023_crm_collections.down, - name: "20260227_171023_crm_collections", - }, - { - up: migration_20260301_151838.up, - down: migration_20260301_151838.down, - name: "20260301_151838", - }, -]; diff --git a/apps/web/src/payload/blocks/ArchitectureBuilderBlock.ts b/apps/web/src/payload/blocks/ArchitectureBuilderBlock.ts deleted file mode 100644 index 77626be..0000000 --- a/apps/web/src/payload/blocks/ArchitectureBuilderBlock.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const ArchitectureBuilderBlock: MintelBlock = { - slug: "architectureBuilder", - labels: { - singular: "Architecture Builder", - plural: "Architecture Builders", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "preset", - type: "text", - defaultValue: "standard", - admin: { description: "Geben Sie den Text für preset ein." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/ArticleBlockquoteBlock.ts b/apps/web/src/payload/blocks/ArticleBlockquoteBlock.ts deleted file mode 100644 index 0402a84..0000000 --- a/apps/web/src/payload/blocks/ArticleBlockquoteBlock.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const ArticleBlockquoteBlock: MintelBlock = { - slug: "articleBlockquote", - labels: { - singular: "Article Blockquote", - plural: "Article Blockquotes", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "quote", - type: "textarea", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den mehrzeiligen Text für quote ein.", - }, - }, - { - name: "author", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für author ein.", - }, - }, - { - name: "role", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für role ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/ArticleMemeBlock.ts b/apps/web/src/payload/blocks/ArticleMemeBlock.ts deleted file mode 100644 index 860c5c0..0000000 --- a/apps/web/src/payload/blocks/ArticleMemeBlock.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { MintelBlock } from "./types"; -import type { Block } from "payload"; - -export const ArticleMemeBlock: MintelBlock = { - slug: "articleMeme", - labels: { - singular: "Article Meme", - plural: "Article Memes", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "image", - type: "upload", - relationTo: "media", - required: true, - admin: { description: "Laden Sie die Datei für image hoch." }, - }, - { - name: "alt", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für alt ein.", - }, - }, - { - name: "caption", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für caption ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/ArticleQuoteBlock.ts b/apps/web/src/payload/blocks/ArticleQuoteBlock.ts deleted file mode 100644 index 2f84dd3..0000000 --- a/apps/web/src/payload/blocks/ArticleQuoteBlock.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const ArticleQuoteBlock: MintelBlock = { - slug: "articleQuote", - labels: { - singular: "Article Quote", - plural: "Article Quotes", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "ArticleQuote", - description: - "Dark-themed quote card. Use for expert quotes or statements. Use isCompany={true} for brands/orgs to show an entity icon instead of personal initials. MANDATORY: always include source and sourceUrl for verifiability. Props: quote, author, role (optional), source (REQUIRED), sourceUrl (REQUIRED), isCompany (optional), translated (optional boolean).", - usageExample: - '\'\'', - }, - fields: [ - { - name: "value", - type: "text", - required: true, - admin: { - description: "e.g. 53% or 2.5M€", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - }, - }, - { - name: "label", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für label ein.", - }, - }, - { - name: "source", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für source ein.", - }, - }, - { - name: "sourceUrl", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für sourceUrl ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/ButtonBlock.ts b/apps/web/src/payload/blocks/ButtonBlock.ts deleted file mode 100644 index 5e801e2..0000000 --- a/apps/web/src/payload/blocks/ButtonBlock.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const ButtonBlock: MintelBlock = { - slug: "buttonBlock", - labels: { - singular: "Button Block", - plural: "Button Blocks", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "label", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für label ein.", - }, - }, - { - name: "href", - type: "text", - required: true, - admin: { description: "Geben Sie den Text für href ein." }, - }, - { - name: "variant", - type: "select", - options: [ - { label: "Primary", value: "primary" }, - { label: "Outline", value: "outline" }, - { label: "Ghost", value: "ghost" }, - ], - defaultValue: "primary", - admin: { description: "Wählen Sie eine Option für variant aus." }, - }, - { - name: "size", - type: "select", - options: [ - { label: "Normal", value: "normal" }, - { label: "Large", value: "large" }, - ], - defaultValue: "normal", - admin: { description: "Wählen Sie eine Option für size aus." }, - }, - { - name: "showArrow", - type: "checkbox", - defaultValue: true, - admin: { description: "Wert für showArrow eingeben." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/CarouselBlock.ts b/apps/web/src/payload/blocks/CarouselBlock.ts deleted file mode 100644 index fe8ff83..0000000 --- a/apps/web/src/payload/blocks/CarouselBlock.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const CarouselBlock: MintelBlock = { - slug: "carousel", - labels: { - singular: "Carousel", - plural: "Carousels", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "slides", - type: "array", - fields: [ - { - name: "title", - type: "text", - admin: { description: "Titel der Slide-Karte." }, - }, - { - name: "content", - type: "textarea", - admin: { description: "Beschreibungstext der Slide-Karte." }, - }, - { - name: "image", - type: "upload", - relationTo: "media", - admin: { description: "Laden Sie die Datei für image hoch." }, - }, - { - name: "caption", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für caption ein.", - }, - }, - ], - admin: { description: "Fügen Sie Elemente zur Liste slides hinzu." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/ComparisonRowBlock.ts b/apps/web/src/payload/blocks/ComparisonRowBlock.ts deleted file mode 100644 index 4315ebf..0000000 --- a/apps/web/src/payload/blocks/ComparisonRowBlock.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const ComparisonRowBlock: MintelBlock = { - slug: "comparisonRow", - labels: { - singular: "Comparison Row", - plural: "Comparison Rows", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "ComparisonRow", - description: - 'Side-by-side comparison: negative "Standard" approach vs positive "Mintel" approach. Props include showShare boolean.', - usageExample: `Google Core Web Vitals'", - }, - fields: [ - { - name: "href", - type: "text", - required: true, - admin: { description: "Geben Sie den Text für href ein." }, - }, - { - name: "label", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für label ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/FAQSectionBlock.ts b/apps/web/src/payload/blocks/FAQSectionBlock.ts deleted file mode 100644 index 0e8342f..0000000 --- a/apps/web/src/payload/blocks/FAQSectionBlock.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; -import { lexicalEditor, BlocksFeature } from "@payloadcms/richtext-lexical"; -import { HeadingBlock } from "./HeadingBlock"; -import { ParagraphBlock } from "./ParagraphBlock"; -import { ExternalLinkBlock } from "./ExternalLinkBlock"; -import { TrackedLinkBlock } from "./TrackedLinkBlock"; - -export const FAQSectionBlock: MintelBlock = { - slug: "faqSection", - labels: { - singular: "Faq Section", - plural: "Faq Sections", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "content", - type: "richText", - editor: lexicalEditor({ - features: ({ defaultFeatures }) => [ - ...defaultFeatures, - BlocksFeature({ - blocks: [ - HeadingBlock, - ParagraphBlock, - ExternalLinkBlock, - TrackedLinkBlock, - ].map(({ ai, render, ...b }) => b), - }), - ], - }), - required: true, - admin: { description: "Formatierter Textbereich für content." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/H2Block.ts b/apps/web/src/payload/blocks/H2Block.ts deleted file mode 100644 index 8219240..0000000 --- a/apps/web/src/payload/blocks/H2Block.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { MintelBlock } from "./types"; - -export const H2Block: MintelBlock = { - slug: "mintelH2", - labels: { - singular: "Heading 2", - plural: "Headings 2", - }, - fields: [ - { - name: "text", - type: "text", - required: true, - admin: { - description: "Geben Sie den Text für die H2-Überschrift ein.", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/H3Block.ts b/apps/web/src/payload/blocks/H3Block.ts deleted file mode 100644 index 2dc96fa..0000000 --- a/apps/web/src/payload/blocks/H3Block.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { MintelBlock } from "./types"; - -export const H3Block: MintelBlock = { - slug: "mintelH3", - labels: { - singular: "Heading 3", - plural: "Headings 3", - }, - fields: [ - { - name: "text", - type: "text", - required: true, - admin: { - description: "Geben Sie den Text für die H3-Überschrift ein.", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/HeadingBlock.ts b/apps/web/src/payload/blocks/HeadingBlock.ts deleted file mode 100644 index c2b3800..0000000 --- a/apps/web/src/payload/blocks/HeadingBlock.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { MintelBlock } from "./types"; - -export const HeadingBlock: MintelBlock = { - slug: "mintelHeading", - labels: { - singular: "Heading", - plural: "Headings", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "Heading", - description: - "Flexible heading component with separated SEO and visual display levels.", - usageExample: - '\'Titel\'', - }, - fields: [ - { - name: "text", - type: "text", - required: true, - admin: { - description: "Der Text der Überschrift.", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - }, - }, - { - name: "seoLevel", - type: "select", - options: ["h1", "h2", "h3", "h4", "h5", "h6"], - defaultValue: "h2", - admin: { description: "Das semantische HTML-Tag für SEO." }, - }, - { - name: "displayLevel", - type: "select", - options: ["h1", "h2", "h3", "h4", "h5", "h6"], - defaultValue: "h2", - admin: { - description: "Die visuelle Größe der Überschrift (unabhängig von SEO).", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/IconListBlock.ts b/apps/web/src/payload/blocks/IconListBlock.ts deleted file mode 100644 index 617c1bd..0000000 --- a/apps/web/src/payload/blocks/IconListBlock.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const IconListBlock: MintelBlock = { - slug: "iconList", - labels: { - singular: "Icon List", - plural: "Icon Lists", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "IconList", - description: - "Checklist with check/cross icons. Wrap IconListItem children inside.", - usageExample: ` - - Zero-Computation: Statische Seiten, kein Serverwarten. - - - Legacy CMS: Datenbankabfragen bei jedem Request. - -`, - }, - fields: [ - { - name: "items", - type: "array", - fields: [ - { - name: "icon", - type: "text", - admin: { - description: "Lucide icon", - components: { Field: "@/src/payload/components/IconSelector" }, - }, - }, - { - name: "title", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für title ein.", - }, - }, - { - name: "description", - type: "textarea", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den mehrzeiligen Text für description ein.", - }, - }, - ], - admin: { description: "Fügen Sie Elemente zur Liste items hinzu." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/ImageTextBlock.ts b/apps/web/src/payload/blocks/ImageTextBlock.ts deleted file mode 100644 index e70c6fb..0000000 --- a/apps/web/src/payload/blocks/ImageTextBlock.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const ImageTextBlock: MintelBlock = { - slug: "imageText", - labels: { - singular: "Image Text", - plural: "Image Texts", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "image", - type: "upload", - relationTo: "media", - required: true, - admin: { description: "Laden Sie die Datei für image hoch." }, - }, - { - name: "text", - type: "textarea", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den mehrzeiligen Text für text ein.", - }, - }, - { - name: "alignment", - type: "select", - options: [ - { label: "Left", value: "left" }, - { label: "Right", value: "right" }, - ], - defaultValue: "left", - admin: { description: "Wählen Sie eine Option für alignment aus." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/LeadMagnetBlock.ts b/apps/web/src/payload/blocks/LeadMagnetBlock.ts deleted file mode 100644 index c269ac8..0000000 --- a/apps/web/src/payload/blocks/LeadMagnetBlock.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const LeadMagnetBlock: MintelBlock = { - slug: "leadMagnet", - labels: { - singular: "Lead Magnet CTA", - plural: "Lead Magnet CTAs", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "LeadMagnet", - description: - "Premium B2B conversion card. Use 1-2 per article as main high-impact CTAs. Props: title (strong headline), description (value prop), buttonText (action), href (link), variant (performance|security|standard).", - usageExample: - '\'\'', - }, - fields: [ - { - name: "title", - type: "text", - required: true, - admin: { - description: "The strong headline for the Call-to-Action", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - }, - }, - { - name: "description", - type: "text", - required: true, - admin: { - description: "The value proposition text.", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - }, - }, - { - name: "buttonText", - type: "text", - required: true, - defaultValue: "Jetzt anfragen", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für buttonText ein.", - }, - }, - { - name: "href", - type: "text", - required: true, - defaultValue: "/contact", - admin: { description: "Geben Sie den Text für href ein." }, - }, - { - name: "variant", - type: "select", - options: [ - { label: "Performance", value: "performance" }, - { label: "Security", value: "security" }, - { label: "Standard", value: "standard" }, - ], - defaultValue: "standard", - admin: { description: "Wählen Sie eine Option für variant aus." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/LeadParagraphBlock.ts b/apps/web/src/payload/blocks/LeadParagraphBlock.ts deleted file mode 100644 index 02b7e45..0000000 --- a/apps/web/src/payload/blocks/LeadParagraphBlock.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const LeadParagraphBlock: MintelBlock = { - slug: "leadParagraph", - labels: { - singular: "Lead Paragraph", - plural: "Lead Paragraphs", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "LeadParagraph", - description: - "Larger, emphasized paragraph for the article introduction. Use 1-3 at the start.", - usageExample: - "'\n Unternehmen investieren oft Unsummen in glänzende Oberflächen, während das technische Fundament bröckelt.\n'", - }, - fields: [ - { - name: "text", - type: "textarea", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den mehrzeiligen Text für text ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/LinkedInEmbedBlock.ts b/apps/web/src/payload/blocks/LinkedInEmbedBlock.ts deleted file mode 100644 index dd5fce5..0000000 --- a/apps/web/src/payload/blocks/LinkedInEmbedBlock.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const LinkedInEmbedBlock: MintelBlock = { - slug: "linkedInEmbed", - labels: { - singular: "Linked In Embed", - plural: "Linked In Embeds", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "url", - type: "text", - required: true, - admin: { description: "Geben Sie den Text für url ein." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/LoadTimeSimulatorBlock.ts b/apps/web/src/payload/blocks/LoadTimeSimulatorBlock.ts deleted file mode 100644 index 0d1b7b8..0000000 --- a/apps/web/src/payload/blocks/LoadTimeSimulatorBlock.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const LoadTimeSimulatorBlock: MintelBlock = { - slug: "loadTimeSimulator", - labels: { - singular: "Load Time Simulator", - plural: "Load Time Simulators", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "initialLoadTime", - type: "number", - defaultValue: 3.5, - admin: { - description: - "Tragen Sie einen numerischen Wert für initialLoadTime ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/MarkerBlock.ts b/apps/web/src/payload/blocks/MarkerBlock.ts deleted file mode 100644 index 2cde05a..0000000 --- a/apps/web/src/payload/blocks/MarkerBlock.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const MarkerBlock: MintelBlock = { - slug: "marker", - labels: { - singular: "Marker", - plural: "Markers", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "text", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für text ein.", - }, - }, - { - name: "color", - type: "text", - admin: { - description: "Hex or rgba color", - components: { Field: "@/src/payload/components/ColorPicker" }, - }, - }, - { - name: "delay", - type: "number", - defaultValue: 0, - admin: { - description: "Tragen Sie einen numerischen Wert für delay ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/MemeCardBlock.ts b/apps/web/src/payload/blocks/MemeCardBlock.ts deleted file mode 100644 index 30a2bf6..0000000 --- a/apps/web/src/payload/blocks/MemeCardBlock.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { MintelBlock } from "./types"; -import type { Block } from "payload"; - -export const MemeCardBlock: MintelBlock = { - slug: "memeCard", - labels: { - singular: "Meme Card", - plural: "Meme Cards", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "MemeCard", - description: - "Real meme from memegen.link. ONLY use these templates: drake, distracted-bf, change-my-mind, uno-draw-25, always-has-been. Captions MUST be in German, extremely sarcastic, max 6 words per line. Use pipe | to separate caption lines. Use sparingly: MAX 1 meme per article.", - usageExample: `
- -
`, - }, - fields: [ - { - name: "template", - type: "text", - required: true, - admin: { - description: - "The template ID from memegen.link (e.g. 'drake', 'disastergirl')", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - }, - }, - { - name: "captions", - type: "textarea", - required: true, - admin: { - description: - "Pipe-separated captions for the meme (e.g. 'Legacy Code|Mintel Stack'). Maximum 6 words per line.", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/MermaidBlock.ts b/apps/web/src/payload/blocks/MermaidBlock.ts deleted file mode 100644 index 29518c3..0000000 --- a/apps/web/src/payload/blocks/MermaidBlock.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const MermaidBlock: MintelBlock = { - slug: "mermaid", - labels: { - singular: "Mermaid", - plural: "Mermaids", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "Mermaid", - description: - 'Renders a Mermaid.js diagram (flowchart, sequence, pie, etc.). Diagram code goes as children. Keep it tiny (max 3-4 nodes). Wrap in div with className="my-8".', - usageExample: `
- \n Mein System ist kein Kostenfaktor, sondern ein ROI-Beschleuniger.\n'", - }, - fields: [ - { - name: "text", - type: "textarea", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den mehrzeiligen Text für text ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/PerformanceChartBlock.ts b/apps/web/src/payload/blocks/PerformanceChartBlock.ts deleted file mode 100644 index c1e809c..0000000 --- a/apps/web/src/payload/blocks/PerformanceChartBlock.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const PerformanceChartBlock: MintelBlock = { - slug: "performanceChart", - labels: { - singular: "Performance Chart", - plural: "Performance Charts", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "title", - type: "text", - defaultValue: "Website Performance", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für title ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/PerformanceROICalculatorBlock.ts b/apps/web/src/payload/blocks/PerformanceROICalculatorBlock.ts deleted file mode 100644 index 8473688..0000000 --- a/apps/web/src/payload/blocks/PerformanceROICalculatorBlock.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const PerformanceROICalculatorBlock: MintelBlock = { - slug: "performanceROICalculator", - labels: { - singular: "Performance R O I Calculator", - plural: "Performance R O I Calculators", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "baseConversionRate", - type: "number", - defaultValue: 2.5, - admin: { - description: - "Tragen Sie einen numerischen Wert für baseConversionRate ein.", - }, - }, - { - name: "monthlyVisitors", - type: "number", - defaultValue: 50000, - admin: { - description: - "Tragen Sie einen numerischen Wert für monthlyVisitors ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/PremiumComparisonChartBlock.ts b/apps/web/src/payload/blocks/PremiumComparisonChartBlock.ts deleted file mode 100644 index 5a65ce1..0000000 --- a/apps/web/src/payload/blocks/PremiumComparisonChartBlock.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const PremiumComparisonChartBlock: MintelBlock = { - slug: "premiumComparisonChart", - labels: { - singular: "Premium Comparison Chart", - plural: "Premium Comparison Charts", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "title", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für title ein.", - }, - }, - { - name: "subtitle", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für subtitle ein.", - }, - }, - { - name: "datasets", - type: "array", - fields: [ - { - name: "label", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für label ein.", - }, - }, - { - name: "value", - type: "number", - required: true, - admin: { - description: "Tragen Sie einen numerischen Wert für value ein.", - }, - }, - { - name: "max", - type: "number", - defaultValue: 100, - admin: { - description: "Tragen Sie einen numerischen Wert für max ein.", - }, - }, - { - name: "unit", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für unit ein.", - }, - }, - { - name: "color", - type: "text", - admin: { - components: { Field: "@/src/payload/components/ColorPicker" }, - description: "Geben Sie den Text für color ein.", - }, - }, - { - name: "description", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für description ein.", - }, - }, - ], - admin: { description: "Fügen Sie Elemente zur Liste datasets hinzu." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/RevealBlock.ts b/apps/web/src/payload/blocks/RevealBlock.ts deleted file mode 100644 index 31f4dae..0000000 --- a/apps/web/src/payload/blocks/RevealBlock.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; -import { lexicalEditor } from "@payloadcms/richtext-lexical"; - -export const RevealBlock: MintelBlock = { - slug: "mintelReveal", - labels: { - singular: "Reveal Wrap", - plural: "Reveal Wraps", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "direction", - type: "select", - options: [ - { label: "Up", value: "up" }, - { label: "Down", value: "down" }, - { label: "Left", value: "left" }, - { label: "Right", value: "right" }, - ], - defaultValue: "up", - admin: { description: "Wählen Sie eine Option für direction aus." }, - }, - { - name: "delay", - type: "number", - defaultValue: 0.1, - admin: { - description: "Tragen Sie einen numerischen Wert für delay ein.", - }, - }, - { - name: "content", - type: "richText", - editor: lexicalEditor({}), - required: true, - admin: { description: "Formatierter Textbereich für content." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/RevenueLossCalculatorBlock.ts b/apps/web/src/payload/blocks/RevenueLossCalculatorBlock.ts deleted file mode 100644 index 7da9419..0000000 --- a/apps/web/src/payload/blocks/RevenueLossCalculatorBlock.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const RevenueLossCalculatorBlock: MintelBlock = { - slug: "revenueLossCalculator", - labels: { - singular: "Revenue Loss Calculator", - plural: "Revenue Loss Calculators", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "title", - type: "text", - defaultValue: "Performance Revenue Simulator", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für title ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/SectionBlock.ts b/apps/web/src/payload/blocks/SectionBlock.ts deleted file mode 100644 index aba5876..0000000 --- a/apps/web/src/payload/blocks/SectionBlock.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; -import { lexicalEditor } from "@payloadcms/richtext-lexical"; - -export const SectionBlock: MintelBlock = { - slug: "mintelSection", - labels: { - singular: "Section Wrap", - plural: "Section Wraps", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "title", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für title ein.", - }, - }, - { - name: "content", - type: "richText", - editor: lexicalEditor({}), - required: true, - admin: { description: "Formatierter Textbereich für content." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/StatsDisplayBlock.ts b/apps/web/src/payload/blocks/StatsDisplayBlock.ts deleted file mode 100644 index bee81c0..0000000 --- a/apps/web/src/payload/blocks/StatsDisplayBlock.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const StatsDisplayBlock: MintelBlock = { - slug: "statsDisplay", - labels: { - singular: "Stats Display", - plural: "Stats Displays", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "label", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für label ein.", - }, - }, - { - name: "value", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für value ein.", - }, - }, - { - name: "subtext", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für subtext ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/StatsGridBlock.ts b/apps/web/src/payload/blocks/StatsGridBlock.ts deleted file mode 100644 index 5e962a8..0000000 --- a/apps/web/src/payload/blocks/StatsGridBlock.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const StatsGridBlock: MintelBlock = { - slug: "statsGrid", - labels: { - singular: "Stats Grid", - plural: "Stats Grids", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "stats", - type: "array", - fields: [ - { - name: "label", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für label ein.", - }, - }, - { - name: "value", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für value ein.", - }, - }, - ], - admin: { description: "Fügen Sie Elemente zur Liste stats hinzu." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/TLDRBlock.ts b/apps/web/src/payload/blocks/TLDRBlock.ts deleted file mode 100644 index b48cb41..0000000 --- a/apps/web/src/payload/blocks/TLDRBlock.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { MintelBlock } from "./types"; -import type { Block } from "payload"; - -export const TLDRBlock: MintelBlock = { - slug: "mintelTldr", - labels: { - singular: "TL;DR Block", - plural: "TL;DR Blocks", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "TLDR", - description: - "Presents a bite-sized summary of the article in a premium dark card. Use exactly once at the very beginning.", - usageExample: - "'\n Stabilität ist kein Zufall, sondern das Ergebnis einer Clean Code Strategie.\n'", - }, - fields: [ - { - name: "content", - type: "textarea", - required: true, - admin: { - description: "The summary content for the TLDR box.", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/TrackedLinkBlock.ts b/apps/web/src/payload/blocks/TrackedLinkBlock.ts deleted file mode 100644 index 3dea0dc..0000000 --- a/apps/web/src/payload/blocks/TrackedLinkBlock.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const TrackedLinkBlock: MintelBlock = { - slug: "trackedLink", - labels: { - singular: "Tracked Link", - plural: "Tracked Links", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "href", - type: "text", - required: true, - admin: { description: "Geben Sie den Text für href ein." }, - }, - { - name: "label", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für label ein.", - }, - }, - { - name: "eventName", - type: "text", - required: true, - admin: { description: "Geben Sie den Text für eventName ein." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/TwitterEmbedBlock.ts b/apps/web/src/payload/blocks/TwitterEmbedBlock.ts deleted file mode 100644 index 80840e8..0000000 --- a/apps/web/src/payload/blocks/TwitterEmbedBlock.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const TwitterEmbedBlock: MintelBlock = { - slug: "twitterEmbed", - labels: { - singular: "Twitter (X) Embed", - plural: "Twitter (X) Embeds", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "url", - type: "text", - required: true, - admin: { description: "Geben Sie den Text für url ein." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/WaterfallChartBlock.ts b/apps/web/src/payload/blocks/WaterfallChartBlock.ts deleted file mode 100644 index 20c119b..0000000 --- a/apps/web/src/payload/blocks/WaterfallChartBlock.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const WaterfallChartBlock: MintelBlock = { - slug: "waterfallChart", - labels: { - singular: "Waterfall Chart", - plural: "Waterfall Charts", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "title", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für title ein.", - }, - }, - { - name: "metrics", - type: "array", - fields: [ - { - name: "label", - type: "text", - required: true, - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für label ein.", - }, - }, - { - name: "duration", - type: "number", - required: true, - admin: { - description: "Tragen Sie einen numerischen Wert für duration ein.", - }, - }, - { - name: "color", - type: "text", - admin: { - components: { Field: "@/src/payload/components/ColorPicker" }, - description: "Geben Sie den Text für color ein.", - }, - }, - ], - admin: { description: "Fügen Sie Elemente zur Liste metrics hinzu." }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/WebVitalsScoreBlock.ts b/apps/web/src/payload/blocks/WebVitalsScoreBlock.ts deleted file mode 100644 index 078a244..0000000 --- a/apps/web/src/payload/blocks/WebVitalsScoreBlock.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const WebVitalsScoreBlock: MintelBlock = { - slug: "webVitalsScore", - labels: { - singular: "Web Vitals Score", - plural: "Web Vitals Scores", - }, - admin: { - group: "MDX Components", - }, - fields: [ - { - name: "lcp", - type: "number", - required: true, - admin: { description: "Largest Contentful Paint (s)" }, - }, - { - name: "inp", - type: "number", - required: true, - admin: { description: "Interaction to Next Paint (ms)" }, - }, - { - name: "cls", - type: "number", - required: true, - admin: { description: "Cumulative Layout Shift" }, - }, - { - name: "description", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für description ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/YouTubeEmbedBlock.ts b/apps/web/src/payload/blocks/YouTubeEmbedBlock.ts deleted file mode 100644 index 7bdefe3..0000000 --- a/apps/web/src/payload/blocks/YouTubeEmbedBlock.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { MintelBlock } from "./types"; - -import type { Block } from "payload"; - -export const YouTubeEmbedBlock: MintelBlock = { - slug: "youTubeEmbed", - labels: { - singular: "You Tube Embed", - plural: "You Tube Embeds", - }, - admin: { - group: "MDX Components", - }, - ai: { - name: "YouTubeEmbed", - description: - "Embeds a YouTube video to visualize concepts or provide deep dives. Use the 11-character videoId.", - usageExample: - '\'\'', - }, - fields: [ - { - name: "videoId", - type: "text", - required: true, - admin: { description: "Geben Sie den Text für videoId ein." }, - }, - { - name: "title", - type: "text", - admin: { - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/AiFieldButton#AiFieldButton", - ], - }, - description: "Geben Sie den Text für title ein.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/blocks/allBlocks.ts b/apps/web/src/payload/blocks/allBlocks.ts deleted file mode 100644 index a35e82f..0000000 --- a/apps/web/src/payload/blocks/allBlocks.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { MintelBlock } from "./types"; -import { MemeCardBlock } from "./MemeCardBlock"; -import { MermaidBlock } from "./MermaidBlock"; -import { LeadMagnetBlock } from "./LeadMagnetBlock"; -import { ComparisonRowBlock } from "./ComparisonRowBlock"; -import { LeadParagraphBlock } from "./LeadParagraphBlock"; -import { ArticleBlockquoteBlock } from "./ArticleBlockquoteBlock"; -import { FAQSectionBlock } from "./FAQSectionBlock"; -import { StatsDisplayBlock } from "./StatsDisplayBlock"; -import { DiagramStateBlock } from "./DiagramStateBlock"; -import { DiagramTimelineBlock } from "./DiagramTimelineBlock"; -import { DiagramGanttBlock } from "./DiagramGanttBlock"; -import { DiagramPieBlock } from "./DiagramPieBlock"; -import { DiagramSequenceBlock } from "./DiagramSequenceBlock"; -import { DiagramFlowBlock } from "./DiagramFlowBlock"; -import { WaterfallChartBlock } from "./WaterfallChartBlock"; -import { PremiumComparisonChartBlock } from "./PremiumComparisonChartBlock"; -import { IconListBlock } from "./IconListBlock"; -import { StatsGridBlock } from "./StatsGridBlock"; -import { MetricBarBlock } from "./MetricBarBlock"; -import { CarouselBlock } from "./CarouselBlock"; -import { ImageTextBlock } from "./ImageTextBlock"; -import { RevenueLossCalculatorBlock } from "./RevenueLossCalculatorBlock"; -import { PerformanceChartBlock } from "./PerformanceChartBlock"; -import { PerformanceROICalculatorBlock } from "./PerformanceROICalculatorBlock"; -import { LoadTimeSimulatorBlock } from "./LoadTimeSimulatorBlock"; -import { ArchitectureBuilderBlock } from "./ArchitectureBuilderBlock"; -import { DigitalAssetVisualizerBlock } from "./DigitalAssetVisualizerBlock"; -import { TwitterEmbedBlock } from "./TwitterEmbedBlock"; -import { YouTubeEmbedBlock } from "./YouTubeEmbedBlock"; -import { LinkedInEmbedBlock } from "./LinkedInEmbedBlock"; -import { ExternalLinkBlock } from "./ExternalLinkBlock"; -import { TrackedLinkBlock } from "./TrackedLinkBlock"; -import { ArticleMemeBlock } from "./ArticleMemeBlock"; -import { MarkerBlock } from "./MarkerBlock"; -import { BoldNumberBlock } from "./BoldNumberBlock"; -import { WebVitalsScoreBlock } from "./WebVitalsScoreBlock"; -import { ButtonBlock } from "./ButtonBlock"; -import { ArticleQuoteBlock } from "./ArticleQuoteBlock"; -import { RevealBlock } from "./RevealBlock"; -import { SectionBlock } from "./SectionBlock"; -import { TLDRBlock } from "./TLDRBlock"; -import { HeadingBlock } from "./HeadingBlock"; -import { ParagraphBlock } from "./ParagraphBlock"; -import { H2Block } from "./H2Block"; -import { H3Block } from "./H3Block"; - -export const allBlocks: MintelBlock[] = [ - TLDRBlock, - HeadingBlock, - H2Block, - H3Block, - ParagraphBlock, - MemeCardBlock, - MermaidBlock, - LeadMagnetBlock, - ComparisonRowBlock, - LeadParagraphBlock, - ArticleBlockquoteBlock, - FAQSectionBlock, - StatsDisplayBlock, - DiagramStateBlock, - DiagramTimelineBlock, - DiagramGanttBlock, - DiagramPieBlock, - DiagramSequenceBlock, - DiagramFlowBlock, - WaterfallChartBlock, - PremiumComparisonChartBlock, - IconListBlock, - StatsGridBlock, - MetricBarBlock, - CarouselBlock, - ImageTextBlock, - RevenueLossCalculatorBlock, - PerformanceChartBlock, - PerformanceROICalculatorBlock, - LoadTimeSimulatorBlock, - ArchitectureBuilderBlock, - DigitalAssetVisualizerBlock, - TwitterEmbedBlock, - YouTubeEmbedBlock, - LinkedInEmbedBlock, - ExternalLinkBlock, - TrackedLinkBlock, - ArticleMemeBlock, - MarkerBlock, - BoldNumberBlock, - WebVitalsScoreBlock, - ButtonBlock, - ArticleQuoteBlock, - RevealBlock, - SectionBlock, -]; - -/** - * Payload 3.x silently drops blocks containing unknown properties. - * We strip `ai` and `render` so Payload gets clean Block objects. - */ -export const payloadBlocks = allBlocks.map(({ ai, render, ...block }) => block); - -export const allComponentDefinitions = allBlocks - .filter((block) => !!block.ai) - .map((block) => block.ai!); diff --git a/apps/web/src/payload/blocks/index.ts b/apps/web/src/payload/blocks/index.ts deleted file mode 100644 index 5148e53..0000000 --- a/apps/web/src/payload/blocks/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -export * from "./ArchitectureBuilderBlock"; -export * from "./ArticleBlockquoteBlock"; -export * from "./ArticleMemeBlock"; -export * from "./ArticleQuoteBlock"; -export * from "./BoldNumberBlock"; -export * from "./ButtonBlock"; -export * from "./CarouselBlock"; -export * from "./ComparisonRowBlock"; -export * from "./DiagramFlowBlock"; -export * from "./DiagramGanttBlock"; -export * from "./DiagramPieBlock"; -export * from "./DiagramSequenceBlock"; -export * from "./DiagramStateBlock"; -export * from "./DiagramTimelineBlock"; -export * from "./DigitalAssetVisualizerBlock"; -export * from "./ExternalLinkBlock"; -export * from "./FAQSectionBlock"; -export * from "./IconListBlock"; -export * from "./ImageTextBlock"; -export * from "./LeadMagnetBlock"; -export * from "./LeadParagraphBlock"; -export * from "./LinkedInEmbedBlock"; -export * from "./LoadTimeSimulatorBlock"; -export * from "./MarkerBlock"; -export * from "./MemeCardBlock"; -export * from "./MermaidBlock"; -export * from "./MetricBarBlock"; -export * from "./PerformanceChartBlock"; -export * from "./PerformanceROICalculatorBlock"; -export * from "./PremiumComparisonChartBlock"; -export * from "./RevealBlock"; -export * from "./RevenueLossCalculatorBlock"; -export * from "./SectionBlock"; -export * from "./StatsDisplayBlock"; -export * from "./StatsGridBlock"; -export * from "./TrackedLinkBlock"; -export * from "./TwitterEmbedBlock"; -export * from "./WaterfallChartBlock"; -export * from "./WebVitalsScoreBlock"; -export * from "./YouTubeEmbedBlock"; -export * from "./HeadingBlock"; -export * from "./H2Block"; -export * from "./H3Block"; -export * from "./ParagraphBlock"; -export * from "./TLDRBlock"; diff --git a/apps/web/src/payload/blocks/types.ts b/apps/web/src/payload/blocks/types.ts deleted file mode 100644 index 858986a..0000000 --- a/apps/web/src/payload/blocks/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { Block } from "payload"; -import type { ComponentDefinition } from "@mintel/content-engine"; -import type { ComponentType } from "react"; - -export type MintelBlock = Block & { - ai?: ComponentDefinition; - render?: ComponentType; -}; diff --git a/apps/web/src/payload/collections/ContextFiles.ts b/apps/web/src/payload/collections/ContextFiles.ts deleted file mode 100644 index 42b588a..0000000 --- a/apps/web/src/payload/collections/ContextFiles.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { CollectionConfig } from "payload"; -import fs from "fs"; -import path from "path"; -import { fileURLToPath } from "url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -export const ContextFiles: CollectionConfig = { - slug: "context-files", - labels: { - singular: "Context File", - plural: "Context Files", - }, - admin: { - useAsTitle: "filename", - defaultColumns: ["filename", "updatedAt"], - }, - access: { - read: () => true, // Needed for server actions to fetch context - create: () => true, - update: () => true, - delete: () => true, - }, - hooks: { - afterChange: [ - ({ doc, operation }) => { - // Potential future: sync back to disk? - // For now, let's keep it simple as a CMS-first feature. - }, - ], - }, - fields: [ - { - name: "filename", - type: "text", - required: true, - unique: true, - admin: { - description: - "Exact filename (e.g. 'strategy.md'). The system uses this to identify the document during prompt generation.", - }, - }, - { - name: "content", - type: "textarea", - required: true, - admin: { - rows: 25, - description: "The raw markdown/text content of the document.", - style: { fontFamily: "monospace" }, - }, - }, - ], -}; diff --git a/apps/web/src/payload/collections/ContextFiles/seed/ABOUT.md b/apps/web/src/payload/collections/ContextFiles/seed/ABOUT.md deleted file mode 100644 index 2d4ead9..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/ABOUT.md +++ /dev/null @@ -1,123 +0,0 @@ -Über mich - -Ich baue Websites und Systeme seit über 15 Jahren. -Nicht weil ich Websites so liebe – sondern weil ich es hasse, wenn Dinge nicht funktionieren. - -In diesen 15 Jahren habe ich: -• Agenturen von innen gesehen -• Konzerne erlebt -• Startups aufgebaut -• Marketingversprechen zerlegt -• Systeme repariert, die „fertig“ waren -• und gelernt, wie man Dinge baut, die einfach laufen - -Heute mache ich das ohne Agentur-Zwischenschichten. -Direkt. Sauber. Verantwortlich. - -⸻ - -Ich habe fast alle Fehler schon für Sie gemacht - -(damit Sie sie nicht machen müssen) - -Ich habe als Designer angefangen, -bin dann Entwickler geworden, -und habe irgendwann gemerkt: - -Das Problem ist selten Technik. -Es ist immer Zuständigkeit. - -Wenn keiner verantwortlich ist, passiert nichts. -Also habe ich mir angewöhnt, Verantwortung zu übernehmen. - -⸻ - -Warum ich Websites wie Systeme baue - -Ich war viele Jahre Senior Developer in Firmen, in denen: -• Millionenumsätze dranhingen -• Fehler teuer waren -• Performance nicht optional war -• Sicherheit kein Nice-to-Have war -• „kurz mal ändern“ trotzdem passieren musste - -Das prägt. - -Deshalb sind meine Websites: -• schnell -• stabil -• boring (im besten Sinne) -• erweiterbar -• wartungsarm -• und nicht abhängig von Plugins oder Agenturen - -⸻ - -Ich habe beide Seiten gesehen - -Ich war: -• Webdesigner -• Entwickler -• Marketing -• Vertrieb -• Agentur -• Inhouse -• Dienstleister -• Unternehmer - -Das heißt: - -Ich weiß, was Unternehmen brauchen – -und was sie nicht brauchen. - -(Meetings, Tickets, Workshops, PowerPoint.) - -⸻ - -Was Kunden davon haben - -Sie bekommen: -• keinen Projektmanager -• keinen Prozess -• kein Team -• kein Ticket -• kein CMS-Drama - -Sie bekommen: -• eine Person -• eine Verantwortung -• ein Ergebnis - -⸻ - -Ein kurzer Überblick (ohne Lebenslauf-Gefühl) - -Ich habe u. a. gearbeitet bei: -• Agenturen -• E-Commerce-Plattformen -• SaaS-Firmen -• Marketing-Teams -• internationalen Unternehmen -• Mittelständlern -• und Konzernen - -Als: -• Web Designer -• Frontend Developer -• Software Developer -• Senior Developer -• und später Gründer - -Das Ergebnis daraus ist nicht ein Titel. -Sondern eine Arbeitsweise. - -⸻ - -Heute - -Heute baue ich Websites und Systeme für Unternehmen, -die keine Lust mehr auf Agenturen haben -und keine Zeit für Chaos. - -Ich übernehme das Thema komplett – -damit es für Sie kein Thema mehr ist. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/AGBS.md b/apps/web/src/payload/collections/ContextFiles/seed/AGBS.md deleted file mode 100644 index 690ae5f..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/AGBS.md +++ /dev/null @@ -1,154 +0,0 @@ -Allgemeine Geschäftsbedingungen (AGB) - -1. Geltungsbereich - -Diese Allgemeinen Geschäftsbedingungen gelten für alle Verträge zwischen -Marc Mintel (nachfolgend „Auftragnehmer“) -und dem jeweiligen Kunden (nachfolgend „Auftraggeber“). - -Abweichende oder ergänzende Bedingungen des Auftraggebers werden nicht Vertragsbestandteil, auch wenn ihrer Geltung nicht ausdrücklich widersprochen wird. - -⸻ - -2. Vertragsgegenstand - -Der Auftragnehmer erbringt Dienstleistungen im Bereich: -• Webentwicklung -• technische Umsetzung digitaler Systeme -• Funktionen, Schnittstellen und Automatisierungen -• Hosting, Betrieb und Wartung, sofern ausdrücklich vereinbart - -Der Auftragnehmer schuldet ausschließlich die vereinbarte technische Leistung, nicht jedoch: -• einen wirtschaftlichen Erfolg -• bestimmte Umsätze, Conversions oder Reichweiten -• Suchmaschinen-Rankings -• rechtliche oder geschäftliche Ergebnisse - -⸻ - -3. Mitwirkungspflichten des Auftraggebers - -Der Auftraggeber verpflichtet sich, alle zur Leistungserbringung erforderlichen Inhalte, Informationen, Zugänge und Entscheidungen rechtzeitig, vollständig und korrekt bereitzustellen. - -Hierzu zählen insbesondere: -• Texte, Bilder, Videos, Produktdaten -• Freigaben und Feedback -• Zugangsdaten -• rechtlich erforderliche Inhalte (z. B. Impressum, Datenschutzerklärung) - -Verzögerungen oder Unterlassungen der Mitwirkung führen zu einer entsprechenden Verschiebung aller Termine. -Hieraus entstehen keine Schadensersatz- oder Minderungsansprüche. - -⸻ - -4. Ausführungs- und Bearbeitungszeiten - -Angegebene Bearbeitungszeiten sind unverbindliche Schätzungen, keine garantierten Fristen. - -Fixe Termine oder Deadlines gelten nur, wenn sie ausdrücklich schriftlich als verbindlich vereinbart wurden. - -⸻ - -5. Abnahme - -Die Leistung gilt als abgenommen, wenn: -• der Auftraggeber sie produktiv nutzt oder -• innerhalb von 7 Tagen nach Bereitstellung keine wesentlichen Mängel angezeigt werden. - -Optische Abweichungen, Geschmacksfragen oder subjektive Einschätzungen stellen keine Mängel dar. - -⸻ - -6. Haftung - -Der Auftragnehmer haftet nur für Schäden, die auf vorsätzlicher oder grob fahrlässiger Pflichtverletzung beruhen. - -Eine Haftung für: -• entgangenen Gewinn -• Umsatzausfälle -• Datenverlust -• Betriebsunterbrechungen -• mittelbare oder Folgeschäden - -ist ausgeschlossen, soweit gesetzlich zulässig. - -⸻ - -7. Verfügbarkeit & Betrieb - -Bei vereinbartem Hosting oder Betrieb schuldet der Auftragnehmer keine permanente Verfügbarkeit. - -Wartungsarbeiten, Updates, Sicherheitsmaßnahmen oder externe Störungen (z. B. Hoster, Netze, Drittanbieter) können zu zeitweisen Einschränkungen führen und begründen keine Haftungsansprüche. - -7a. Betriebs- und Pflegeleistung - -Die Betriebs- und Pflegeleistung ist fester Bestandteil der laufenden Leistungen des Auftragnehmers. - -Sie umfasst ausschließlich: -• Sicherstellung des technischen Betriebs der Website -• Wartung, Updates und Fehlerbehebung der bestehenden Systeme -• Austausch, Korrektur oder Aktualisierung bereits vorhandener Inhalte -• Pflege bestehender Datensätze ohne Änderung oder Erweiterung der Datenstruktur - -Nicht Bestandteil der Betriebs- und Pflegeleistung sind insbesondere: -• regelmäßige oder fortlaufende Erstellung neuer Inhalte -(z. B. Blogartikel, News, Produkte, Seiten) -• redaktionelle Tätigkeiten oder Content-Produktion -• strategische Inhaltsplanung oder Marketingmaßnahmen -• Aufbau neuer Seiten, Features, Funktionen oder Datenmodelle -• Serien-, Massen- oder Dauerpflege -(z. B. tägliche oder wiederkehrende Inhaltserstellung) - -Die Betriebs- und Pflegeleistung dient ausschließlich der Instandhaltung, Sicherheit und Funktionsfähigkeit der bestehenden Website. - -Leistungen, die darüber hinausgehen, gelten als Neuentwicklung oder Inhaltserstellung und sind gesondert zu beauftragen und zu vergüten. - -⸻ - -8. Drittanbieter & externe Systeme - -Der Auftragnehmer übernimmt keine Verantwortung für: -• Leistungen, Ausfälle oder Änderungen externer Dienste -• APIs, Schnittstellen oder Plattformen Dritter -• rechtliche oder technische Änderungen fremder Systeme - -Eine Funktionsfähigkeit kann nur im Rahmen der jeweils aktuellen externen Schnittstellen gewährleistet werden. - -⸻ - -9. Inhalte & Rechtliches - -Der Auftraggeber ist allein verantwortlich für: -• Inhalte der Website -• rechtliche Konformität (DSGVO, Urheberrecht, Wettbewerbsrecht etc.) -• bereitgestellte Daten und Medien - -Der Auftragnehmer übernimmt keine rechtliche Prüfung. - -⸻ - -10. Vergütung & Zahlungsverzug - -Alle Preise verstehen sich netto zuzüglich gesetzlicher Umsatzsteuer. - -Rechnungen sind, sofern nicht anders vereinbart, innerhalb von 7 Tagen fällig. - -Bei Zahlungsverzug ist der Auftragnehmer berechtigt: -• Leistungen auszusetzen -• Systeme offline zu nehmen -• laufende Arbeiten zu stoppen - -⸻ - -11. Kündigung laufender Leistungen - -Laufende Leistungen (z. B. Hosting & Betrieb) können mit einer Frist von 4 Wochen zum Monatsende gekündigt werden, sofern nichts anderes vereinbart ist. - -⸻ - -12. Schlussbestimmungen - -Es gilt das Recht der Bundesrepublik Deutschland. -Gerichtsstand ist – soweit zulässig – der Sitz des Auftragnehmers. - -Sollte eine Bestimmung dieser AGB unwirksam sein, bleibt die Wirksamkeit der übrigen Regelungen unberührt. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/AUDIENCE.md b/apps/web/src/payload/collections/ContextFiles/seed/AUDIENCE.md deleted file mode 100644 index 2aa6672..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/AUDIENCE.md +++ /dev/null @@ -1,33 +0,0 @@ -# Zielgruppe - -## Primäre Zielgruppe: Der deutsche Mittelstand - -Unsere Blog-Inhalte richten sich an Entscheider in kleinen und mittelständischen Unternehmen – nicht an Entwickler. - -### Wer liest das? - -- **Geschäftsführer** von Handwerksbetrieben, Kanzleien, Arztpraxen -- **Marketing-Verantwortliche** in mittelständischen Unternehmen (10–250 Mitarbeiter) -- **Online-Shop-Betreiber** mit 20k–500k€ Jahresumsatz -- **Selbstständige** und Freiberufler mit eigener Website - -### Was sie NICHT sind - -- Keine Entwickler (kein Code-Jargon) -- Keine Enterprise-Konzerne (kein "Amazon-Scale", keine "Millionen User") -- Keine Marketing-Agenturen (kein Buzzword-Bingo) - -### Wie wir schreiben - -- **Know-how transportieren** ohne zu dozieren -- **Technische Fakten verständlich machen** — ELI5 aber nicht herablassend -- **Realistische Beispiele**: "Tischlerei Müller mit 30 Seitenbesuchern am Tag", nicht "globaler Marktführer mit 10M MAU" -- **Probleme benennen** die sie kennen: langsame Website, schlechtes Google-Ranking, verlorene Anfragen -- **Lösungen zeigen** die greifbar sind: konkrete Vorher/Nachher-Vergleiche, echte Zahlen - -### Tonalität gegenüber dem Leser - -- Auf Augenhöhe, nie von oben herab -- Wie ein kompetenter Bekannter der einem beim Thema Website hilft -- Ehrlich über Probleme, ohne Panik zu machen -- Kein Verkaufsdruck, keine künstliche Dringlichkeit diff --git a/apps/web/src/payload/collections/ContextFiles/seed/AUTOMATION.md b/apps/web/src/payload/collections/ContextFiles/seed/AUTOMATION.md deleted file mode 100644 index 6ad4ac8..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/AUTOMATION.md +++ /dev/null @@ -1,76 +0,0 @@ -# Routine Automation - -_Kleine Helfer, die den Alltag deutlich entlasten_ - -In vielen mittelständischen Unternehmen fressen wiederkehrende Aufgaben Monat für Monat unzählige Stunden: - -- Daten aus Dokumenten abtippen -- Formulare von Hand ausfüllen -- Angebote, Berichte oder Bestätigungen manuell anpassen -- Eingehende Anfragen immer wieder neu prüfen und bearbeiten - -Das ist keine wertschöpfende Arbeit. -Das ist Routine, die teuer ist, Fehler produziert und gute Mitarbeiter davon abhält, sich um das zu kümmern, was wirklich Umsatz bringt. - -Ich baue genau für diese Routine **einfache, maßgeschneiderte Helfer** – meist mit PDF- oder Excel-Ausgabe, Konfiguratoren oder KI-Dokumenten-Einlesen. -Einmal eingerichtet, laufen sie leise im Hintergrund. -Kein großes Projekt. Kein monatliches Tool-Abo. Kein „lernen Sie das neue System“. - -### Was das konkret bringen kann – Beispiele aus der Praxis - -- **Schnelle Dokumentenerstellung (PDF-Generatoren)** - Kurze Eingaben (Formular, Mail, Excel-Zeile) → fertiges PDF raus: Angebote, Berichte, Protokolle, Bestätigungen, Übersichten. Immer Ihr Corporate Design, immer aktuelle Daten/Bausteine. - → Von 30–120 Minuten runter auf 2–10 Minuten. - -- **Excel-Automatisierungen & smarte Tabellen** - Verkaufszahlen, Lagerbestände, Kundenlisten → automatische Berechnungen, Zusammenfassungen, Prognosen oder Exporte. Monatsberichte oder Preislisten aktualisieren sich von selbst. - → Kein ständiges Nachrechnen mehr, keine Versionskonflikte. - -- **Konfiguratoren für Anfragen & Schätzungen** - Kunde oder Mitarbeiter geht schrittweise durch ein Formular (auf Ihrer Website oder intern): „Welche Leistung? Welcher Umfang? Welcher Termin?“ → sofort realistische Schätzung, Preisspanne oder fertiges Angebot als PDF/Excel. - -- **KI-Einlesen von PDFs oder handschriftlichen Dokumenten** - Eingescannte Rechnungen, Lieferscheine, Formulare, Notizen oder handgeschriebene Protokolle → KI liest Text, Zahlen, Felder aus (auch Handschrift, wo lesbar) → Daten landen in übersichtlicher Tabelle/Excel oder vorausgefülltem Formular. - Mitarbeiter prüft nur noch kurz → kleine Korrektur → Prozess geht weiter. - → Kein stundenlanges Abtippen mehr, deutlich schnellerer Durchlauf. - -### Der echte Wert für Sie - -- 30–80 % weniger Zeit bei Routineaufgaben → Ihre Teams konzentrieren sich aufs Wesentliche -- Weniger Fehler & Rückfragen → einheitlicher, professioneller Output -- Schnellere Reaktion auf Kunden → Konfiguratoren & KI-Einlesen liefern sofort Infos -- Amortisation oft schon nach wenigen Wochen oder Dutzend Nutzungen -- Nutzt, was Sie bereits haben: Website, Excel, Mail, Scanner-App - -### Was ich **nicht** mache - -Ich ersetze **kein** ERP, CRM, Buchhaltungs- oder HR-System. -Kein automatisches Buchen, keine Finanzamtschnittstelle, keine GoBD-Archivierungspflichten. -Nur smarte Abkürzungen bei Routine – der Rest bleibt in Ihren bewährten Tools. - -### Ich kann Ihnen helfen, wenn Sie mit diesen typischen Problemen kämpfen - -- „Wir tippen immer noch Daten aus gescannten Dokumenten oder handschriftlichen Notizen ab.“ -- „Angebote, Berichte oder Protokolle dauern ewig, weil alles von Hand angepasst wird.“ -- „Kunden fragen ständig dasselbe – wir antworten jedes Mal manuell.“ -- „Excel-Tabellen und Berechnungen werden ständig neu gemacht und gehen kaputt.“ -- „Bis wir eine realistische Schätzung oder ein Angebot raus haben, vergeht zu viel Zeit.“ - -Schreiben Sie mir einfach einen kurzen Satz zu Ihrem größten Zeitfresser in diesem Bereich. -Ich antworte meist innerhalb von 1–2 Tagen: - -- Ist das machbar? Ja/Nein -- Ca. wie viel Aufwand (meist 3–15 Stunden) & Preisrahmen -- Was Sie realistisch sparen können (Zeit, Nerven, Fehler) - -Passt es → baue ich es. -Danach: Routine digitalisiert. Mehr Ruhe im Alltag. - -**Kurz gesagt** -Routine Automation: -Nicht die große Revolution. -Sondern gezielte Entlastung bei den Dingen, die jeden Tag Zeit und Nerven kosten. -Mehr Zeit. Weniger Frust. Besserer Output. -Und das Gefühl: „Das läuft jetzt einfach.“ - -Wenn bei Ihnen gerade etwas „von Hand gemacht wird“ oder „ewig dauert“ – Ich sage Ihnen, ob und wie schnell man das sinnvoll digitalisieren kann. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/CONTENT_RULES.md b/apps/web/src/payload/collections/ContextFiles/seed/CONTENT_RULES.md deleted file mode 100644 index 397a6f1..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/CONTENT_RULES.md +++ /dev/null @@ -1,65 +0,0 @@ -# Content-Regeln für Blog-Post-Generierung - -## 1. Visuelle Balance - -- **Max 1 visuelle Komponente pro 3–4 Textabsätze** -- Visualisierungen dürfen **niemals direkt hintereinander** stehen -- Zwischen zwei visuellen Elementen müssen mindestens 2 Textabsätze liegen -- Nicht mehr als 5–6 visuelle Komponenten pro Blog-Post insgesamt - -### Erlaubte visuelle Komponenten - -- `Mermaid` / `DiagramFlow` / `DiagramSequence` — für Prozesse und Architektur -- `ArticleMeme` — echte Meme-Bilder (memegen.link), kurze und knackige Texte -- `BoldNumber` — einzelne Hero-Statistik mit Quelle -- `PremiumComparisonChart` / `MetricBar` — für Vergleiche -- `WebVitalsScore` — für Performance-Audits (max 1x pro Post) -- `WaterfallChart` — für Ladezeiten-Visualisierung (max 1x pro Post) -- `StatsGrid` — für 2–4 zusammengehörige Statistiken -- `ComparisonRow` — für Vorher/Nachher-Vergleiche - -### Verboten - -- `MemeCard` (text-basierte Memes) — nur echte Bild-Memes verwenden -- AI-generierte Bilder im Content — nur Thumbnails erlaubt -- `DiagramPie` — vermeiden, zu generisch - -## 2. Zahlen und Statistiken - -- **Niemals nackte Zahlen** — jede Statistik braucht Kontext und Vergleich -- `BoldNumber` nur für DIE eine zentrale Statistik des Abschnitts -- Mehrere Zahlen → `StatsGrid` oder `PremiumComparisonChart` verwenden -- Jede Zahl braucht eine **Quelle** (`source` + `sourceUrl` Pflicht) -- Vergleiche sind immer besser als Einzelwerte: "33% vs. 92%", nicht nur "92%" - -## 3. Zitate und Quellen - -- Alle Zitate brauchen klare Attribution: `author`, `source`, `sourceUrl` -- Bei übersetzten Zitaten: "(übersetzt)" im Zitat oder als Hinweis -- `ExternalLink` für alle externen Referenzen im Fließtext -- Keine erfundenen Zitate — nur verifizierbare Quellen - -## 4. Mermaid-Diagramme - -- **Extrem kompakt halten**: Strikt max 3–4 Nodes pro Diagramm -- **Ausschließlich vertikale Layouts** (TD) — besser für Mobile -- Deutsche Labels verwenden -- Keine verschachtelten Subgraphs -- Jedes Diagramm braucht einen aussagekräftigen `title` - -## 5. Memes - -- Nur echte Bilder via `ArticleMeme` (memegen.link API) -- **Extreme Sarkasmus-Pflicht** — mach dich über schlechte Agentur-Arbeit oder Legacy-Tech lustig -- **Kurze, knackige Captions** — max 6 Wörter pro Zeile -- Deutsche Captions verwenden -- Bewährte Templates: `drake`, `disastergirl`, `fine`, `daily-struggle` -- Max 2–3 Memes pro Blog-Post - -## 6. Textstruktur - -- Jeder Abschnitt startet mit einer klaren H2/H3 -- `LeadParagraph` nur am Anfang (1–2 Stück) -- Normaler Text in `Paragraph`-Komponenten -- `Marker` sparsam einsetzen — max 2–3 pro Abschnitt -- `IconList` für Aufzählungen mit Pro/Contra diff --git a/apps/web/src/payload/collections/ContextFiles/seed/ESTIMATION_GUIDE.md b/apps/web/src/payload/collections/ContextFiles/seed/ESTIMATION_GUIDE.md deleted file mode 100644 index 6c6994e..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/ESTIMATION_GUIDE.md +++ /dev/null @@ -1,99 +0,0 @@ -# Service Estimation & AI Consultation Guide - -This guide explains how to use the automated estimation system to generate professional PDF quotes for clients using AI-driven context analysis. - -## 🛠 Basic Usage - -The primary entry point is the `ai-estimate` script. It orchestrates a 6-pass AI consultation: - -1. **Fact Extraction**: Identifying company data and project scope. -2. **Feature Deep-Dive**: Generating technical justifications for items. -3. **Strategic Content**: Creating the Briefing Analysis and Strategic Vision. -4. **Information Architecture**: Designing a hierarchical sitemap. -5. **Position Synthesis**: Mapping everything to a transparent pricing model. -6. **Industrial Critic**: Final quality gate for tone and accuracy. - -### Generating an Estimation from Scratch - -#### 1. With a Website URL (Recommended) - -Providing a URL allows the system to crawl the existing site to understand the "Company DNA" and services. - -```bash -npm run ai-estimate -- "Relaunch der Website mit Fokus auf B2B Leads" --url https://example.com -``` - -#### 2. From a Text File - -If you have a long briefing in a `.txt` file: - -```bash -npm run ai-estimate -- @briefing.txt --url https://example.com -``` - -#### 3. Text-Only (No URL) - -If no URL is provided, the system relies entirely on your briefing text. - -```bash -npm run ai-estimate -- "Neuentwicklung eines Portals für XYZ" -``` - ---- - -## 📄 Output Modes - -The system can generate two types of documents: - -### 1. Full Quote (Default) - -Includes everything: Front Page, Briefing Analysis, Vision, Sitemap, Technical Principles, Detailed Pricing, Roadmap, and Legal Terms (AGB). - -```bash -npm run ai-estimate -- "Project Briefing" -``` - -### 2. Estimation Only - -A condensed version excluding legal terms and deep technical principles. Focuses purely on the strategic fit and the price. - -```bash -npm run ai-estimate -- "Project Briefing" --estimation -``` - ---- - -## 📦 Cache & Cache Management - -To save costs and time, all AI responses and crawl results are cached in the `.cache` directory. - -### Regenerating with Cached Data - -If you run the same command again (identical briefing and URL), the system will use the cached results and won't call the AI APIs again. This is useful if you want to tweak the PDF layout without spending tokens. - -### Forcing a Refresh - -To ignore the cache and get a fresh AI consultation: - -```bash -npm run ai-estimate -- "Project Briefing" --clear-cache -``` - -### Manual Tweaking (JSON State) - -Every run saves a detailed state to `out/estimations/json/[Company]_[Timestamp].json`. -If you want to manually edit the AI's results (e.g., fix a typo in the sitemap or description), you can edit this JSON file and then regenerate the PDF from it: - -```bash -npm run ai-estimate -- --json out/estimations/json/Your_Project.json -``` - -_(Add `--estimation` if you want the condensed version)._ - ---- - -## 💡 Advanced Options - -- `--comments "..."`: Add manual notes that the AI should consider (e.g., "Customer prefers a minimalist blue theme"). -- `--clear-cache`: Purges all cached data for this project before starting. -- `--url [URL]`: Explicitly sets the crawl target (auto-discovered from briefing if omitted). diff --git a/apps/web/src/payload/collections/ContextFiles/seed/KEYWORDS.md b/apps/web/src/payload/collections/ContextFiles/seed/KEYWORDS.md deleted file mode 100644 index 8d14521..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/KEYWORDS.md +++ /dev/null @@ -1,68 +0,0 @@ -# High-Converting Keywords (Digital Architect / B2B) - -Diese 50 Keywords sind strategisch ausgewählt, um entscheidungsfreudige B2B-Kunden (Geschäftsführer, CMOs, CTOs) anzuziehen, die nach Premium-Lösungen, Performance-Architekturen und messbarem ROI suchen. Sie meiden den "Billig-Sektor" (wie "Wordpress Website günstig") und fokussieren sich auf High-End Tech und Business-Impact. - -## Kategorie 1: Enterprise Performance & Core Web Vitals (Pain Point: Sichtbarkeit & Speed) - -1. "Core Web Vitals Optimierung Agentur" -2. "PageSpeed Insights 100 erreichen B2B" -3. "Website Ladezeit verbessern Conversion Rate" -4. "Mobile First Indexing Strategie 2026" -5. "Headless Commerce Performance Optimierung" -6. "Time to First Byte reduzieren Architektur" -7. "Largest Contentful Paint optimieren Next.js" -8. "Website Performance Audit B2B" -9. "Static Site Generation vs Server Side Rendering SEO" -10. "Enterprise SEO Performance Tech Stack" - -## Kategorie 2: Modern Tech Stack & Headless (Pain Point: Skalierbarkeit & Legacy-Code) - -11. "Next.js Agentur Deutschland" -12. "Headless CMS Migration B2B" -13. "Vercel Hosting Enterprise Architektur" -14. "Directus CMS Agentur Setup" -15. "React Server Components Vorteile B2B" -16. "Decoupled Architecture E-Commerce" -17. "Legacy CMS ablösen Strategie" -18. "Wordpress headless machen Vor- und Nachteile" -19. "Jamstack Entwicklung Enterprise" -20. "Microservices Web Architektur" - -## Kategorie 3: B2B Conversion & Digital ROI (Pain Point: Umsatz & Leads) - -21. "B2B Website Relaunch Strategie" -22. "Digital Architect Consulting B2B" -23. "Conversion Rate Optimierung Tech Stack" -24. "Lead Generierung B2B Website Architektur" -25. "High-End Website Entwicklung Kosten" -26. "ROI von Website Performance" -27. "B2B Landingpage Architektur" -28. "Website als Vertriebsmitarbeiter B2B" -29. "Data Driven Design B2B" -30. "UX/UI Architektur für hohe Conversion" - -## Kategorie 4: Infrastruktur, Sicherheit & Skalierbarkeit (Pain Point: Ausfälle & Security) - -31. "Cloudflare Enterprise Setup Agentur" -32. "DDoS Schutz Web Architektur B2B" -33. "Serverless Architecture Vorteile" -34. "Hochverfügbare Website Architektur" -35. "Edge Computing für Websiten" -36. "Web Security Audit Enterprise" -37. "Zero Trust Web Architektur" -38. "Traefik Proxy Setup Next.js" -39. "Dockerized CMS Deployment" -40. "CI/CD Pipeline Webentwicklung B2B" - -## Kategorie 5: Spezifische Lösungen & "Digital Architect" Keywords (Nischen-Autorität) - -41. "Digital Architect Agentur Deutschland" -42. "Mittelstand Digitalisierung Web-Infrastruktur" -43. "Industrie 4.0 B2B Website" -44. "Premium Webentwicklung Geschäftsführer" -45. "Software Architektur Beratung B2B" -46. "Web Vitals als Rankingfaktor Strategie" -47. "Next.js Directus Integration" -48. "High Performance Corporate Website" -49. "Tech Stack Audit für Mittelstand" -50. "Sustainable Web Design Architektur" diff --git a/apps/web/src/payload/collections/ContextFiles/seed/LANDING_PAGE.md b/apps/web/src/payload/collections/ContextFiles/seed/LANDING_PAGE.md deleted file mode 100644 index efd6521..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/LANDING_PAGE.md +++ /dev/null @@ -1,238 +0,0 @@ -Digitale Systeme für Unternehmen, die keinen Overhead wollen - -Agenturen sind zu langsam. -CMS will keiner pflegen. -Digitale Themen bleiben liegen. - -Ich mache das anders. - -⸻ - -Was ich mache - -Ich setze digitale Systeme für Unternehmen um – direkt, sauber und ohne Agentur-Zirkus. - -Websites, Funktionen, Systeme, interne Tools. -Keine Workshops. Keine Tickets. Kein Tech-Blabla. - -Sie erklären mir, was Sie brauchen. -Ich sorge dafür, dass es funktioniert. - -⸻ - -Für wen das ist - -Für Unternehmen, die: -• regelmäßig Änderungen an Website oder Systemen brauchen -• keine Lust auf Agenturen haben -• kein CMS anfassen wollen -• keine Tickets schreiben möchten -• keinen Entwickler einstellen wollen -• und wollen, dass Dinge einfach erledigt werden - -Wenn bei Ihnen öfter der Satz fällt: - -„Das müsste man mal machen …“ - -… aber es passiert nie – dann sind Sie hier richtig. - -⸻ - -Das eigentliche Problem - -Digitale Arbeit scheitert nicht an Technik. -Sie scheitert an Zuständigkeit. - -Agenturen wollen Projekte. -Mitarbeiter haben Wichtigeres zu tun. -IT ist ausgelastet. -Und kleine Aufgaben sind zu klein für große Angebote. - -Also bleibt alles liegen. - -⸻ - -Warum keine Agentur - -Ich habe über 15 Jahre in Agenturen gearbeitet. -Ich kenne das Spiel. Und ich weiß, warum es nervt. - -⸻ - -Agenturen machen einfache Dinge kompliziert - -Ein Button ändern? - -→ Konzeptcall -→ Abstimmung -→ internes Meeting -→ Angebot -→ Warten -→ Rechnung - -Ich: -→ mache es -→ fertig - -⸻ - -Agenturen verkaufen Prozesse statt Ergebnisse - -Workshops, Slides, Roadmaps, Alignment, Stakeholder. -Klingt nach Fortschritt. -Ist oft nur Beschäftigungstherapie. - -Bei mir zählt nur Umsetzung. - -⸻ - -Agenturen rechnen nach Stunden - -(und liegen erstaunlich oft daneben) - -„Das dauert nur kurz“ -→ Überraschung auf der Rechnung - -Ich arbeite mit klaren Leistungen und Fixpreisen. -Sie wissen vorher, was es kostet. Immer. - -⸻ - -Agenturen geben Aufgaben weiter - -(und verlieren sie dann aus den Augen) - -Heute Projektmanager. -Morgen Entwickler. -Übermorgen niemand. - -Bei mir gilt: -Eine Person. Eine Verantwortung. - -⸻ - -Agenturen verschwinden nach dem Projekt - -Kleine Änderung? → neues Angebot -Dringend? → Warteschleife - -Ich bleibe. -Solange Sie Dinge brauchen. - -⸻ - -Wie ich arbeite (und warum das entspannter ist) - -Agenturen machen erst ein Konzept. -Dann wird umgesetzt. -Dann merkt man: „Passt doch nicht ganz.“ -Dann wird nachberechnet. - -Ich mache es anders. - -⸻ - -Ich baue zuerst. Dann reden wir drüber. - -Sie erklären mir Ihre Vorstellung. -Ich setze den ersten echten Stand um. - -Keine Slides. -Kein Konzept-PDF. -Kein Ratespiel. - -Dann arbeiten wir direkt am Ergebnis, bis es passt. -Ohne jedes Mal ein neues Angebot. -Ohne Scope-Diskussionen. -Ohne Theater. - -⸻ - -Was ich konkret umsetze - -Websites -• neue Websites (klarer Standard, kein Chaos) -• bestehende Websites übernehmen -• Seiten ändern oder ergänzen -• Performance & SEO -• Hosting & Betrieb (inklusive) - -⸻ - -Funktionen & Systeme -• Produktbereiche -• Blogs, News, Jobs -• Formulare (auch mehrstufig) -• Downloads -• Suche & Filter -• PDF-Generatoren -• API-Ausgaben & Daten-Sync -• Sonderlogik - -⸻ - -Interne Tools -• kleine Inhouse-Tools -• Excel ersetzen -• Importe & Exporte -• Automatisierung -• Dinge, die nerven → weg - -⸻ - -Was ich bewusst nicht mache -• keine CMS-Schulungen -• keine Agentur-Workshops -• keine Ticketsysteme -• keine Stundenabrechnung für Websites -• kein Overhead -• keine Prozessshows - -Das ist kein Mangel. -Das ist der Vorteil. - -⸻ - -Preise (klar & transparent) - -Ich arbeite mit festen Leistungen und Fixpreisen. -Keine Abos. Keine Überraschungen. - -Grundlage -• Website-Basis → 6.000 € -• Hosting & Betrieb → 120 € / Monat (inkl. 20 GB Medien) - -Entwicklung -• Seite → 800 € -• Feature (System) → 2.000 € -• Funktion (Logik) → 1.000 € - -Inhalte -• Neuer Datensatz → 400 € -• Datensatz anpassen → 200 € - -Optional -• CMS-Einrichtung → 1.500 € -• CMS-Anbindung pro Feature → 800 € -• Speichererweiterung → +10 € / 10 GB - -Sie wissen vorher, was es kostet. Immer. - -⸻ - -Warum Kunden bleiben -• Dinge passieren schnell -• Aufgaben verschwinden wirklich -• kein Erklären -• kein Nachfassen -• kein Projektstress -• kein Agentur-Zirkus - -Kurz: Ruhe. - -⸻ - -Interesse? - -Schreiben Sie mir einfach, was Sie brauchen. -Ich sage Ihnen ehrlich, ob ich es mache – und was es kostet. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/MAINTENANCE.md b/apps/web/src/payload/collections/ContextFiles/seed/MAINTENANCE.md deleted file mode 100644 index cbc2875..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/MAINTENANCE.md +++ /dev/null @@ -1,35 +0,0 @@ -# Sorglos-Betrieb – Damit Sie sich auf Ihr Geschäft konzentrieren können - -Eine Website ist ein lebendiger Teil Ihres Unternehmens. Sie soll funktionieren, sicher sein und gut aussehen – ohne dass Sie sich ständig darum kümmern müssen. - -Genau dafür gibt es meinen Sorglos-Betrieb. - -Das ist keine automatische Server-Überwachung und kein reiner Wartungsvertrag. Es ist meine persönliche Verantwortung, Ihre Website so stabil und aktuell wie möglich zu halten. Ich schaue regelmäßig vorbei, behebe Probleme frühzeitig und reagiere schnell, wenn doch einmal etwas nicht rund läuft. - -## Was Sie erwarten können: - -### Ich kümmere mich proaktiv - -Regelmäßige Checks, Updates von Systemen und Plugins, Sicherheitsüberprüfungen – alles, was typische Ausfälle und Schwachstellen verhindert oder minimiert. - -### Schnelle Reaktion bei Problemen - -Websites können mal down gehen – durch Hoster-Störungen, plötzliche Updates von Drittanbietern oder andere unvorhergesehene Dinge. In solchen Fällen bin ich für Sie da: Ich analysiere, behebe und informiere Sie transparent. Sie müssen nicht selbst recherchieren oder panisch Support-Tickets schreiben. - -### Sicherheit und Aktualität bleiben im Blick - -Ich halte die bestehende Technik auf dem neuesten Stand, korrigiere kleine Fehler und passe Inhalte an, wenn nötig – alles innerhalb des vereinbarten Rahmens. So bleibt Ihre Website vertrauenswürdig und nutzerfreundlich. - -### Klare Grenzen – faire Erwartungen - -Der Sorglos-Betrieb deckt die Instandhaltung und Pflege der bestehenden Website ab: Technischer Betrieb, Sicherheit, kleine Korrekturen und Aktualisierungen. -Neue Inhalte erstellen, große Umstrukturierungen, neue Features oder umfangreiche Redaktionsarbeit gehören nicht dazu – das besprechen und bepreisen wir separat und transparent. - -### Kurz gesagt: - -Ich nehme Ihnen so viel wie möglich vom technischen Alltag ab, damit Sie sich auf das konzentrieren können, was Sie am besten können – Ihr Geschäft führen. -Ich kann nicht jede Störung im Voraus verhindern (das kann niemand), aber ich sorge dafür, dass solche Momente selten bleiben und schnell wieder behoben sind. - -### Sorglos-Betrieb bedeutet für mich: - -Ich kümmere mich – verlässlich, ehrlich und mit dem gleichen Anspruch, mit dem ich Ihre Website gebaut habe. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/PRICING.md b/apps/web/src/payload/collections/ContextFiles/seed/PRICING.md deleted file mode 100644 index 1415e07..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/PRICING.md +++ /dev/null @@ -1,234 +0,0 @@ -Preise - -1. Website – Fixpreis - -Basis - -4.000 € einmalig - -Die Grundlage für jede Website: -• Projekt-Setup & Infrastruktur -• Hosting-Bereitstellung -• Grundstruktur & Design-Vorlage -• technisches SEO-Basics -• Analytics (mit automatischem Mail-Report) -• Testing, Staging, Production Umgebung -• Livegang - -Enthält keine Seiten, Inhalte oder Funktionen. - -⸻ - -2. Entwicklung (Produktion) - -Seite - -600 € / Seite - -Individuell gestaltete Seite – -mit Layout, Struktur, Textaufteilung, responsivem Design. - -⸻ - -Feature (System) - -1.500 € / Feature - -Ein in sich geschlossenes System mit Datenstruktur, Darstellung und Pflegefähigkeit. - -Typische Beispiele: -• Produktbereich -• Blog -• News -• Jobs -• Referenzen -• Events - -Ein Feature erzeugt ein Datenmodell, Übersichten & Detailseiten. - -⸻ - -Funktion (Logik) - -800 € / Funktion - -Funktionen liefern Logik und Interaktion, z. B.: -• Kontaktformular -• Mailversand -• Suche -• Filter -• Mehrsprachigkeit (System) -• PDF-Export von Daten -• API-Anbindungen (z. B. Produkt-Sync) -• Redirect-Logik -• Automatisierte Aufgaben - -Jede Funktion ist ein klar umrissener Logikbaustein. - -⸻ - -3. Visuelle Inszenierung & Interaktion - -(Hier geht es um Design/UX-Extras, nicht um „Standard-Design“.) - -Visuelle Inszenierung - -1.500 € / Abschnitt - -Erweiterte Gestaltung: -• Hero-Story -• visuelle Abläufe -• Scroll-Effekte -• speziell inszenierte Sektionen - -⸻ - -Komplexe Interaktion - -1.500 € / Interaktion - -Dargestellte, interaktive UI-Erlebnisse: -• Konfiguratoren -• Live-Previews -• mehrstufige Auswahlprozesse - -(Nutzt deine bestehenden Bausteine, gehört aber zur Entwicklung.) - -⸻ - -4. Inhalte & Medien - -Neuer Datensatz - -200 € / Stück - -Beispiele: -• Produkt -• Blogpost -• News -• Case -• Job - -Datensätze enthalten Inhalte mit Text, Medien, Metadaten. - -⸻ - -Datensatz anpassen - -200 € / Stück -• Textupdates -• Bildwechsel -• Feldänderungen (ohne Schemaänderung) - -⸻ - -5. Betrieb & Wartung (Pflicht) - -Hosting & Betrieb - -12 Monate = 3.000 € - -Sichert: -• Webhosting & Verfügbarkeit -• Sicherheitsupdates -• Backups & Monitoring -• Analytics inkl. Reports -• Medien-Speicher (Standard bis 20 GB) - -⸻ - -6. Speicher-Erweiterung (optional) - -Mehr Speicher - -+10 € / Monat → +10 GB (aber nur 20/100/200 GB) - -Wenn das inklusive Volumen überschritten wird, wird automatisch erweitert. - -(Keine Leistungsdiskussion – nur Infrastruktur.) - -⸻ - -7. Headless CMS (optional) - -CMS-Einrichtung - -1.500 € einmalig - -Einrichtung eines Headless CMS: -• Struktur -• Rollen -• Rechte -• API-Anbindung -• Deployment -• kurze Einführung - -⸻ - -CMS-Anbindung pro Feature - -800 € / Feature - -Erlaubt, dass Datensätze (z. B. Blog, News) im CMS gepflegt werden. -Seiten & Layout bleiben bei dir. - -⸻ - -8. App / interne Software - -Entwicklung nach Zeit - -120 € / Stunde - -Für: -• interne Tools -• Prozesslogik -• Workflows -• Automatisierungen -• alles, was Zustände und Abläufe beinhaltet - -(Kein Fixpreis, weil scope offen ist.) - -⸻ - -9. Integrationen (optional) - -API-Schnittstelle / Daten-Sync - -800 € / Zielsystem - -Synchronisation zu externem System (Push): -• Produkt-Sync -• CRM / ERP / Stripe / sonstige API - -Nicht enthalten: -• Betrieb fremder Systeme -• Echtzeit-Pull-Mechanismen -• Zustandsabhängige Syncs - -⸻ - -10. Wichtige Regeln - -Seiten = Entwicklung -Datensätze = Inhalte & Pflege -Features = Daten-Systeme -Funktionen = Logik -CMS-Anbindung = optionale Datenpflege über Schnittstelle -Betrieb = Hosting, Updates, Backups, Analytics -Apps = Stunden (Prozesse & Systeme außerhalb der Website) - -⸻ - -Leistungsausschlüsse (kurz und klar) -• Kein Betrieb von Mail-Servern -• Keine Logistik, kein Shop-Checkout -• Kein Drittanbieter-Betrieb -• Keine permanente Überwachung fremder Systeme - -⸻ - -Satz für Kundenkommunikation - -Ich baue digitale Systeme mit klaren Preisen und Ergebnissen – -keine Stunden, keine Überraschungen. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/PRINCIPLES.md b/apps/web/src/payload/collections/ContextFiles/seed/PRINCIPLES.md deleted file mode 100644 index 61a11c5..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/PRINCIPLES.md +++ /dev/null @@ -1,43 +0,0 @@ -Prinzipien - -Ich arbeite nach klaren Grundsätzen, die sicherstellen, dass meine Kunden fair, transparent und langfristig profitieren. - -⸻ - -1. Volle Preis-Transparenz - Alle Kosten sind offen und nachvollziehbar. - Es gibt keine versteckten Gebühren, keine Abos, keine Lock-ins. - Jeder Kunde sieht genau, wofür er bezahlt. - -⸻ - -2. Quellcode & Projektzugang - Auf Wunsch erhalten Kunden jederzeit den vollständigen Source Code und eine nachvollziehbare Struktur. - Damit kann jeder andere Entwickler problemlos weiterarbeiten. - Niemand kann später behaupten, der Code sei „Messy“ oder unbrauchbar. - -⸻ - -3. Best Practices & saubere Technik - Ich setze konsequent bewährte Standards und dokumentierte Abläufe ein. - Das sorgt dafür, dass Systeme wartbar, verständlich und erweiterbar bleiben – langfristig. - -⸻ - -4. Verantwortung & Fairness - Ich übernehme die technische Verantwortung für die Website. - Ich garantiere keine Umsätze, Rankings oder rechtliche Ergebnisse – nur saubere Umsetzung und stabile Systeme. - Wenn etwas nicht sinnvoll ist, sage ich es ehrlich. - -⸻ - -5. Langfristiger Wert - Eine Website ist ein Investment. - Ich baue sie so, dass Anpassungen, Erweiterungen und Übergaben an andere Entwickler problemlos möglich sind. - Das schützt Ihre Investition und vermeidet teure Neuaufbauten. - -⸻ - -6. Zusammenarbeit ohne Tricks - Keine künstlichen Deadlines, kein unnötiger Overhead. - Kommunikation ist klar, Entscheidungen nachvollziehbar, Übergaben sauber dokumentiert. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/STANDARDS.md b/apps/web/src/payload/collections/ContextFiles/seed/STANDARDS.md deleted file mode 100644 index 88fb4c6..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/STANDARDS.md +++ /dev/null @@ -1,36 +0,0 @@ -# Meine Standards - -Ich entwickle Websites nach Prinzipien, die über das reine Funktionieren hinausgehen. -Das Ziel ist eine Seite, die nicht nur heute überzeugt, sondern in den nächsten Jahren stabil, kosteneffizient, sicher und verantwortungsvoll bleibt – ohne dass Sie ständig nachbessern, abmahnen lassen oder sich für unnötigen Ressourcenverbrauch rechtfertigen müssen. - -## Was das für Sie konkret bedeutet: - -### Deutlich geringerer Energie- und CO₂-Verbrauch - -Durch konsequente Optimierung von Code, Bildern, Schriften und Ladeverhalten entsteht eine schlanke Website. -→ Ihre Besucher laden die Seite spürbar schneller, Ihre Hosting-Kosten bleiben niedrig, und der CO₂-Fußabdruck pro Aufruf liegt oft um 70–90 % unter dem Durchschnitt vergleichbarer Projekte. Das ist heute für viele Unternehmen ein echter Wettbewerbs- und Imagevorteil – ohne dass Sie Kompromisse bei Design oder Funktionalität eingehen müssen. - -### Technologische Souveränität & Unabhängigkeit - -Keine Abhängigkeit von Big Tech, geschlossenen Baukasten-Systemen oder undurchsichtigen Cloud-Plattformen. Wir setzen konsequent auf Self-Hosting und Open-Source-Kerntechnologien. -→ Alles, was für Ihre Website entwickelt wird, gehört Ihnen. Der Code ist custom-coded, die Infrastruktur ist unabhängig. Wenn ein großer Anbieter seine Preise erhöht, Bedingungen ändert oder Dienste einstellt, bleibt Ihre Website davon unberührt. Sie behalten die volle Kontrolle über Ihre digitale Identität – dauerhaft und ohne "Lock-in"-Effekte. - -### Vertrauen bei Ihren Besuchern - -Kein Cookie-Banner, kein heimliches Tracking, keine versteckten Datenabfragen. -→ Viele Menschen erkennen intuitiv, dass hier mitgedacht wurde. Das schafft ein deutlich besseres Gefühl – besonders bei Kunden, die selbst Wert auf Datenschutz legen, in regulierten Branchen tätig sind oder einfach ein seriöses Unternehmen erwarten. - -### Sicherheit von Grund auf eingebaut - -Sichere Formulare, Schutz vor typischen Angriffsvektoren, keine veralteten oder riskanten Bibliotheken, lokale Ressourcen wo immer möglich. -→ Die Website wird nicht schon nach wenigen Monaten zum Sicherheitsrisiko. Sie sparen sich spätere teure Sicherheits-Updates, Penetrationstests oder im Worst Case den Umgang mit einem Datenleck. Mehr Ruhe und weniger unvorhergesehene Kosten. - -### DSGVO-Konformität ohne Grauzonen oder Tricks - -Es wird nur verarbeitet, was technisch unbedingt erforderlich ist und ohne aktive Einwilligung erlaubt bleibt. -→ Sie können das Thema Datenschutz mit gutem Gewissen abhaken. Keine Abmahn-Risiken, keine nervösen Kundenanfragen, keine teuren Nachbesserungen. - -### Langfristig wartungsarm und zukunftssicher - -Weil Abhängigkeiten minimiert und bewährte, schlanke Techniken bevorzugt werden, altert die Website deutlich langsamer. -→ Sie zahlen weniger für regelmäßige Updates, haben seltener böse Überraschungen und können Ihr Budget gezielt in Inhalte, Marketing oder neue Funktionen investieren – statt in Notfall-Reparaturen. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/STYLEGUIDE.md b/apps/web/src/payload/collections/ContextFiles/seed/STYLEGUIDE.md deleted file mode 100644 index 7d5d3d6..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/STYLEGUIDE.md +++ /dev/null @@ -1,88 +0,0 @@ -# Style Guide: Digital Architect - -This document defines the visual language and design rules for the Mintel ecosystem. The goal is to maintain a "Digital Architect" aesthetic: technical, reductionist, and high-fidelity. - -## 1. Core Philosophy: Reduction to Essentials - -The design should feel "Websites ohne Overhead." Every element must serve a purpose. If it doesn't add value, remove it. - -- **Technical Precision**: Use grids, mono-spaced labels, and clear hierarchies to signal technical competence. -- **Tactile Digital Objects**: UI elements should feel like physical objects (buttons that depress, tags that pop in, glass that blurs). -- **High Contrast**: Bold black/slate on clean white backgrounds, with vibrant highlighter accents. - -## 2. Color Palette - -The project uses a monochrome base with curated highlighter accents. - -- **Primary Base**: - - **Backgrounds**: Pure White (`#ffffff`) for clarity. - - **Surfaces**: Slate-50 for subtle depth, White with 90% opacity + 10px blur for glassmorphism. -- **Grays (Slate)**: - - **Text**: Slate-800 for body, Slate-900 for headings. - - **UI Borders**: Slate-100 or Slate-200. - - **Muted text**: Slate-400 or Slate-500. -- **Highlighter Accents**: Used exclusively for tags, markers, and selective emphasis. - - **Yellow**: Warm, high-visibility (`rgba(255, 235, 59, 0.95)`). - - **Pink**: Vibrant, energetic (`rgba(255, 167, 209, 0.95)`). - - **Green**: Success, technical health (`rgba(129, 199, 132, 0.95)`). - - **Blue**: Neutral, structural (`rgba(226, 232, 240, 0.95)`). - -## 3. Typography - -A high-contrast mix of fonts that balances modern tech with editorial readability. - -- **Headings (Sans-serif)**: Use **Inter**. - - Tracking: `-0.025em` to `-0.05em` (tracking-tighter). - - Weight: Bold (`700`). - - Color: Slate-900. -- **Body (Serif)**: Use **Newsreader** or Georgia. - - Style: Defaults to serif for long-form content to provide a "notebook" feel. - - Line-height: Relaxed (`1.6` to `1.75`). -- **Technical (Monospace)**: Use **JetBrains Mono**. - - Usage: Small labels, tags, code snippets, and "Mono-Labels" (e.g., section numbers). - - Feature: Uppercase with wide tracking (`0.3em` to `0.4em`). - -## 4. Layout & Rhythm - -Standardized containers ensure consistency across different screen sizes. - -- **Standard Container**: Max-width 6xl (`72rem`). Used for most page sections. -- **Wide Container**: Max-width 7xl (`80rem`). Used for galleries or high-impact visuals. -- **Narrow Container**: Max-width 4xl (`56rem`). Used for focused reading and blog posts. -- **Section Rhythm**: Sections are separated by clear `border-top` lines and numbered (e.g., "01", "02"). - -## 5. UI Elements & Interactions - -### 5.1 Buttons - -- **Shape**: Always pill-shaped (rounded-full). -- **Style**: Thin borders (`1px`) with bold, uppercase mono-spaced text. -- **Hover**: Should feel "expensive." Smooth translate-up (`-0.5rem`) and deep, soft shadows. - -### 5.2 Cards & Containers - -- **Glassmorphism**: Use for search boxes and floating elements (`backdrop-filter: blur(10px)`). -- **Cards**: Minimalist. Use `Slate-50` or thin `Slate-100` borders. Avoid heavy shadows unless on hover. - -### 5.3 Highlighters & Tags - -- **Marker Effect**: Use a hand-drawn marker underline (diagonal skew, slightly erratic rotation) for key titles. -- **Tags**: Small, bold, uppercase. They should use `tagPopIn` animations when appearing. - -## 6. Motion & Atmosphere - -- **Reveals**: Content should never "just appear." Use slide-up and fade-in transitions (`0.5s` to `0.7s`) to create a sense of discovery. -- **Background Grid**: A subtle, low-opacity grid pattern provides a technical "blueprint" feel to the pages. -- **Micro-interactions**: Hovering over icons or tags should trigger subtle scales (`105%-110%`) and color shifts. - -## 7. Thumbnail & Illustration Style - -Blog post thumbnails are generated via AI image generation. They should follow these style rules: - -- **Style**: Technical blueprint / architectural illustration — clean lines, monochrome base with one highlighter accent color -- **No photos**: Abstract, geometric, or diagrammatic illustrations only -- **Color palette**: Slate grays + one accent from the highlighter palette (yellow, pink, or green) -- **Feel**: "Engineering notebook sketch" — precise, minimal, professional -- **No text in images**: Titles and labels are handled by the website layout -- **Aspect ratio**: 16:9 for blog headers, 1:1 for social media cards -- **No AI-generated photos of people, products, or realistic scenes** — only abstract/technical visualizations diff --git a/apps/web/src/payload/collections/ContextFiles/seed/TECH.md b/apps/web/src/payload/collections/ContextFiles/seed/TECH.md deleted file mode 100644 index c9f5c89..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/TECH.md +++ /dev/null @@ -1,98 +0,0 @@ -Wie ich Websites technisch umsetze - -Ich entwickle Websites als moderne, performante Websysteme – nicht als Baukasten-Seiten und nicht als schwer wartbare CMS-Konstrukte. -Der Fokus liegt auf Geschwindigkeit, Stabilität, Datenschutz und langfristiger Wartbarkeit. - -Die Technik dient dabei immer einem Zweck: -Ihre Website soll zuverlässig funktionieren, schnell laden und kein laufendes Risiko darstellen. - -⸻ - -Geschwindigkeit & Performance - -Meine Websites sind so aufgebaut, dass Inhalte extrem schnell ausgeliefert werden – unabhängig davon, ob ein Besucher am Desktop oder mobil unterwegs ist. - -Das bedeutet für Sie: -• kurze Ladezeiten -• bessere Nutzererfahrung -• messbar bessere Werte bei Google PageSpeed & Core Web Vitals -• geringere Absprungraten - -Die Seiten werden nicht „zusammengeklickt“, sondern technisch optimiert ausgeliefert. - -⸻ - -Responsives Design (ohne Kompromisse) - -Jede Website ist von Grund auf responsiv. -Layout, Inhalte und Funktionen passen sich automatisch an: -• Smartphones -• Tablets -• Laptops -• große Bildschirme - -Dabei wird nicht einfach skaliert, sondern gezielt für unterschiedliche Bildschirmgrößen optimiert. -Das Ergebnis ist eine saubere Darstellung und gute Bedienbarkeit auf allen Geräten. - -⸻ - -Stabilität & Betriebssicherheit - -Im Hintergrund laufen Überwachungs- und Kontrollmechanismen, die technische Probleme automatisch erkennen. - -Für Sie heißt das: -• Fehler werden bemerkt, auch wenn niemand sie meldet -• ich werde aktiv informiert, statt erst zu reagieren, wenn etwas kaputt ist -• Probleme können frühzeitig behoben werden - -Das reduziert Ausfälle und vermeidet unangenehme Überraschungen. - -⸻ - -Datenschutz & DSGVO - -Ich setze konsequent auf freie, selbst betriebene Software statt auf große externe Plattformen. - -Ihre Vorteile: -• keine Weitergabe von Nutzerdaten an Dritte -• keine versteckten Tracker -• keine Abhängigkeit von US-Anbietern -• datenschutzfreundliche Statistik ohne Cookies - -Die Website bleibt technisch schlank und rechtlich kontrollierbar. - -⸻ - -Unabhängigkeit & Kostenkontrolle - -Da ich keine proprietären Systeme oder Lizenzmodelle einsetze: -• entstehen keine laufenden Tool-Gebühren -• gibt es keine plötzlichen Preiserhöhungen -• bleibt die Website langfristig planbar betreibbar - -Sie zahlen für die Leistung – nicht für Lizenzen oder Marken. - -⸻ - -Wartbarkeit & Erweiterbarkeit - -Die technische Struktur ist so aufgebaut, dass: -• Inhalte erweitert werden können -• Funktionen sauber ergänzt werden können -• Anpassungen nicht das ganze System gefährden - -Das schützt Ihre Investition und verhindert teure Neuaufbauten nach kurzer Zeit. - -⸻ - -Kurz gesagt - -Ich baue Websites, die: -• schnell sind -• auf allen Geräten sauber funktionieren -• datenschutzkonform betrieben werden -• technisch überwacht sind -• langfristig wartbar bleiben - -Die Technik steht nicht im Vordergrund – -aber sie sorgt dafür, dass Ihre Website zuverlässig ihren Zweck erfüllt. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/TONE.md b/apps/web/src/payload/collections/ContextFiles/seed/TONE.md deleted file mode 100644 index e460cdc..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/TONE.md +++ /dev/null @@ -1,53 +0,0 @@ -Ton & Haltung in der Kommunikation - -Dieses Dokument beschreibt die verbindlichen Prinzipien, nach denen ich mit Kunden kommuniziere – schriftlich wie mündlich, auf der Website wie im Projektalltag. - -1. Klarheit vor Höflichkeit - -Ich kommuniziere klar, direkt und verständlich. -Unklare Formulierungen, Marketingfloskeln oder beschwichtigende Aussagen werden vermieden. -Lieber eine ehrliche, präzise Aussage als eine „freundliche“ Unverbindlichkeit. - -2. Ehrlichkeit ohne Verkaufsdruck - -Ich verspreche nichts, was ich nicht sicher einhalten kann. -Grenzen, Risiken und Unsicherheiten werden offen benannt. -Es gibt keine künstliche Dringlichkeit, kein Upselling aus Prinzip und keine verdeckten Interessen. - -3. Sachlich, ruhig, professionell - -Die Kommunikation bleibt sachlich und respektvoll – auch bei Kritik, Verzögerungen oder Meinungsverschiedenheiten. -Emotionale Eskalation, Schuldzuweisungen oder Rechtfertigungsschleifen werden vermieden. - -4. Verantwortung statt Ausreden - -Probleme werden benannt, nicht relativiert. -Wenn etwas nicht funktioniert, wird erklärt warum – und wie damit umgegangen wird. -Ich übernehme Verantwortung für meine Arbeit, nicht für äußere Faktoren außerhalb meines Einflusses. - -5. Transparenz statt Fachchinesisch - -Komplexe Sachverhalte werden verständlich erklärt, ohne künstliche Vereinfachung oder Herablassung. -Fachbegriffe werden nur verwendet, wenn sie notwendig sind. -Wissen dient der Orientierung des Kunden, nicht der Selbstdarstellung. - -6. Gleichbehandlung aller Kunden - -Alle Kunden werden gleich behandelt – unabhängig von Projektgröße, Budget oder Laufzeit. -Es gibt keine versteckten Prioritäten, Sonderregeln oder impliziten Erwartungshaltungen. - -7. Langfristige Perspektive - -Die Kommunikation ist auf nachhaltige Zusammenarbeit ausgelegt, nicht auf kurzfristige Zustimmung. -Entscheidungen und Empfehlungen orientieren sich am langfristigen Nutzen des Kunden. - -8. Persona: Marc Mintel - -- Mitte 30, deutsch, bodenständig -- Umgangssprachlich aber professionell — wie ein Gespräch unter Kollegen, nicht wie ein Vortrag -- Technisch kompetent, erklärt aber auf Augenhöhe statt zu dozieren -- Der hilfreiche technische Nachbar, nicht der Silicon-Valley-Guru -- Keine Arroganz, kein Belehren — Wissen teilen statt damit angeben. Wir machen unsere Dinge auch nicht größer als Sie sind. Wir sind bescheiden. -- Spricht Probleme direkt an, ohne dramatisch zu werden -- Nutzt "ich" statt "wir" oder Passivkonstruktionen -- Vermeidet englische Buzzwords wo deutsche Begriffe existieren: "Kunden verlieren" statt "Churn Rate", "Ladezeit" statt "Time to Interactive" diff --git a/apps/web/src/payload/collections/ContextFiles/seed/WEBSITES.md b/apps/web/src/payload/collections/ContextFiles/seed/WEBSITES.md deleted file mode 100644 index 7aab5b9..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/WEBSITES.md +++ /dev/null @@ -1,136 +0,0 @@ -Wie ich Websites baue – und warum Sie damit Ruhe haben - -Die meisten Websites funktionieren. -Bis jemand sie anfasst. -Oder Google etwas ändert. -Oder ein Plugin ein Update macht. -Oder die Agentur nicht mehr antwortet. - -Ich baue Websites so, dass das alles egal ist. - -⸻ - -Ich baue Websites wie Systeme – nicht wie Broschüren - -Eine Website ist kein Flyer. -Sie ist ein System, das jeden Tag arbeitet. - -Deshalb baue ich sie auch so: -• stabil -• schnell -• vorhersehbar -• ohne Überraschungen - -Sie müssen nichts warten. -Sie müssen nichts lernen. -Sie müssen nichts pflegen, wenn Sie nicht wollen. - -⸻ - -Geschwindigkeit ist kein Extra. Sie ist Standard. - -Viele Websites sind langsam, weil sie zusammengeklickt sind. - -Meine sind schnell, weil sie gebaut sind. - -Das bedeutet für Sie: -• Seiten laden sofort -• Google mag sie -• Besucher bleiben -• weniger Absprünge -• bessere Sichtbarkeit - -90+ Pagespeed ist bei mir kein Ziel. -Es ist der Normalzustand. - -⸻ - -Keine Plugins. Keine Updates. Keine Wartungshölle. - -Ich nutze keine Baukästen. -Keine Plugin-Sammlungen. -Keine Systeme, die sich selbst zerstören. - -Ihre Website besteht aus: -• sauberem Code -• klarer Struktur -• festen Bausteinen - -Das heißt: - -Wenn etwas geändert wird, geht nichts kaputt. - -⸻ - -Inhalte und Technik sind getrennt (absichtlich) - -Wenn Sie Inhalte selbst pflegen wollen, können Sie das. -Aber nur Inhalte. - -Kein Design. -Keine Struktur. -Keine Technik. - -Sie können nichts kaputt machen. -Ich verspreche es. - -Und wenn Sie nichts selbst pflegen wollen: -Dann schreiben Sie mir einfach. -Ich erledige das. - -⸻ - -Änderungen sind einfach. Wirklich. - -Neue Seite? -Neue Funktion? -Neue Idee? - -Kein Ticket. -Kein Formular. -Kein Projektplan. - -Sie schreiben mir, was Sie brauchen. -Ich setze es um. -Fertig. - -⸻ - -Warum das alles so gebaut ist - -Weil ich 15 Jahre Agenturen gesehen habe. - -Zu viele Meetings. -Zu viele Konzepte. -Zu viele Übergaben. -Zu viele „eigentlich müsste man mal“. - -Meine Websites sind dafür gebaut, -dass Dinge einfach passieren. - -⸻ - -Das Ergebnis für Sie -• schnelle Website -• keine Pflegepflicht -• keine Überraschungen -• keine Abhängigkeit -• keine Agentur -• kein Stress - -Oder anders gesagt: - -Eine Website, die sich wie eine erledigte Aufgabe anfühlt. - -⸻ - -Und technisch? - -Technisch ist das alles sehr modern. -Aber das ist mein Problem, nicht Ihres. - -⸻ - -Wenn Sie wollen, erkläre ich Ihnen das gerne. - -Wenn nicht, funktioniert es trotzdem. diff --git a/apps/web/src/payload/collections/ContextFiles/seed/WORDING.md b/apps/web/src/payload/collections/ContextFiles/seed/WORDING.md deleted file mode 100644 index dd4710d..0000000 --- a/apps/web/src/payload/collections/ContextFiles/seed/WORDING.md +++ /dev/null @@ -1,56 +0,0 @@ -1. Aktiv statt passiv - -Sätze werden aktiv formuliert. -Keine unpersönlichen Konstruktionen, kein „es wird“, „man sollte“, „könnte“. - -2. Kurz und eindeutig - -Sätze sind so kurz wie möglich, so lang wie nötig. -Ein Gedanke pro Satz. Keine Schachtelsätze. - -3. Keine Weichmacher - -Keine Wörter wie: -• eventuell -• möglicherweise -• grundsätzlich -• in der Regel -• normalerweise - -Wenn etwas gilt, wird es gesagt. Wenn nicht, wird es ausgeschlossen. - -4. Keine Marketingbegriffe - -Keine Buzzwords, Superlative oder leeren Versprechen. -Keine emotional aufgeladenen Begriffe. Keine Werbesprache. - -5. Konkrete Aussagen - -Keine abstrakten Formulierungen. -Aussagen beziehen sich auf konkrete Ergebnisse, Zustände oder Abläufe. - -6. Ich-Form - -Kommunikation erfolgt konsequent in der Ich-Form. -Kein „wir“, kein „unser Team“, keine künstliche Vergrößerung. - -7. Keine Rechtfertigungen - -Keine erklärenden Absicherungen im Satz. -Aussagen stehen für sich und werden nicht relativiert. - -8. Neutraler Ton - -Keine Umgangssprache. -Keine Ironie. -Keine Emojis. - -9. Verbindliche Sprache - -Keine offenen Enden ohne Grund. -Wenn etwas nicht garantiert wird, wird das klar benannt – ohne Abschwächung. - -10. Technisch präzise, sprachlich einfach - -Technische Inhalte werden präzise beschrieben, sprachlich jedoch simpel gehalten. -Kein unnötiger Jargon. diff --git a/apps/web/src/payload/collections/CrmAccounts.ts b/apps/web/src/payload/collections/CrmAccounts.ts deleted file mode 100644 index 63af4e7..0000000 --- a/apps/web/src/payload/collections/CrmAccounts.ts +++ /dev/null @@ -1,189 +0,0 @@ -import type { CollectionConfig } from "payload"; -import { aiEndpointHandler } from "../endpoints/aiEndpoint"; - -export const CrmAccounts: CollectionConfig = { - slug: "crm-accounts", - labels: { - singular: "Account", - plural: "Accounts", - }, - admin: { - useAsTitle: "name", - defaultColumns: ["name", "status", "leadTemperature", "updatedAt"], - group: "CRM", - description: - "Accounts represent companies or organizations. They are the central hub linking Contacts and Interactions together. Use this to track the overall relationship status.", - }, - endpoints: [ - { - path: "/:id/analyze", - method: "post", - handler: aiEndpointHandler, - }, - ], - access: { - read: ({ req: { user } }) => Boolean(user), // Admin only - create: ({ req: { user } }) => Boolean(user), - update: ({ req: { user } }) => Boolean(user), - delete: ({ req: { user } }) => Boolean(user), - }, - fields: [ - { - name: "analyzeButton", - type: "ui", - admin: { - components: { - Field: "@/src/payload/components/AiAnalyzeButton#AiAnalyzeButton", - }, - }, - }, - { - name: "name", - type: "text", - required: true, - label: "Company / Project Name", - admin: { - description: - "Enter the official name of the business or the research project name.", - }, - }, - { - name: "website", - type: "text", - label: "Website URL", - admin: { - description: - "The main website of the account. Required for triggering the AI Website Analysis.", - placeholder: "https://example.com", - }, - }, - { - type: "row", - fields: [ - { - name: "status", - type: "select", - options: [ - { label: "Lead (Prospect)", value: "lead" }, - { label: "Active Client", value: "client" }, - { label: "Business Partner", value: "partner" }, - { label: "Lost / Archive", value: "lost" }, - ], - defaultValue: "lead", - admin: { - width: "50%", - description: "Current lifecycle stage of this business relation.", - }, - }, - { - name: "leadTemperature", - type: "select", - options: [ - { label: "❄️ Cold (New Research)", value: "cold" }, - { label: "🔥 Warm (In Contact)", value: "warm" }, - { label: "⚡ Hot (Negotiation / Quote)", value: "hot" }, - ], - admin: { - condition: (data) => { - return data?.status === "lead"; - }, - width: "50%", - description: "Indicates how likely this lead is to convert soon.", - }, - }, - ], - }, - { - type: "row", - fields: [ - { - name: "industry", - type: "text", - admin: { - width: "50%", - description: "Industry or category of this account (e.g. Messebauer, Handwerk).", - }, - }, - { - name: "websiteStatus", - type: "select", - options: [ - { label: "🟢 Good", value: "gut" }, - { label: "🟡 OK / Average", value: "ok" }, - { label: "🔴 Bad / Old", value: "schlecht" }, - { label: "❓ Unknown", value: "unknown" }, - ], - admin: { - width: "50%", - description: "Quality assessment of their current website.", - }, - }, - ], - }, - { - name: "notes", - type: "textarea", - admin: { - description: "Internal notes and research findings for this account.", - }, - }, - { - name: "assignedTo", - type: "relationship", - relationTo: "users", - label: "Account Manager (User)", - admin: { - description: "The internal team member responsible for this account.", - }, - }, - { - name: "reports", - type: "relationship", - relationTo: "media", - hasMany: true, - label: "AI Reports & Documents", - admin: { - description: - "All generated PDF estimates and strategy documents appear here.", - }, - }, - { - name: "topics", - type: "join", - collection: "crm-topics", - on: "account", - admin: { - description: - "Projects, deals, or specific topics active for this client.", - }, - }, - { - name: "contacts", - type: "join", - collection: "crm-contacts", - on: "account", - admin: { - description: "All contacts associated with this account.", - }, - }, - { - name: "interactions", - type: "join", - collection: "crm-interactions", - on: "account", - admin: { - description: - "Timeline of all communication logged against this account.", - }, - }, - { - name: "projects", - type: "join", - collection: "projects", - on: "account", - admin: { - description: "All high-level projects associated with this account.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/collections/CrmContacts.ts b/apps/web/src/payload/collections/CrmContacts.ts deleted file mode 100644 index 8ed909e..0000000 --- a/apps/web/src/payload/collections/CrmContacts.ts +++ /dev/null @@ -1,145 +0,0 @@ -import type { CollectionConfig } from "payload"; -import { bulkMailEndpointHandler } from "../endpoints/bulkMailEndpoint"; -export const CrmContacts: CollectionConfig = { - slug: "crm-contacts", - labels: { - singular: "Contact", - plural: "Contacts", - }, - admin: { - useAsTitle: "fullName", - defaultColumns: ["fullName", "email", "account"], - group: "CRM", - description: - "Contacts are the individual people linked to an Account. A person should only be created once and can be assigned to a company here.", - components: { - views: { - list: { - actions: ["@/src/payload/components/BulkMailButton#BulkMailButton"], - }, - }, - }, - }, - endpoints: [ - { - path: "/bulk-mail", - method: "post", - handler: bulkMailEndpointHandler, - }, - ], - access: { - read: ({ req: { user } }) => Boolean(user), - create: ({ req: { user } }) => Boolean(user), - update: ({ req: { user } }) => Boolean(user), - delete: ({ req: { user } }) => Boolean(user), - }, - hooks: { - beforeChange: [ - ({ data }) => { - if (data?.firstName || data?.lastName) { - data.fullName = - `${data.firstName || ""} ${data.lastName || ""}`.trim(); - } - return data; - }, - ], - afterRead: [ - ({ doc }) => { - if (!doc.fullName && (doc.firstName || doc.lastName)) { - return { - ...doc, - fullName: `${doc.firstName || ""} ${doc.lastName || ""}`.trim(), - }; - } - return doc; - }, - ], - }, - fields: [ - { - name: "fullName", - type: "text", - admin: { - hidden: true, - }, - }, - { - type: "row", - fields: [ - { - name: "firstName", - type: "text", - required: true, - admin: { - width: "50%", - }, - }, - { - name: "lastName", - type: "text", - required: true, - admin: { - width: "50%", - }, - }, - ], - }, - { - name: "email", - type: "email", - required: true, - unique: true, - admin: { - description: "Primary email address for communication tracking.", - }, - }, - { - type: "row", - fields: [ - { - name: "phone", - type: "text", - admin: { - width: "50%", - }, - }, - { - name: "linkedIn", - type: "text", - admin: { - width: "50%", - placeholder: "https://linkedin.com/in/...", - }, - }, - ], - }, - { - name: "role", - type: "text", - label: "Job Title / Role", - admin: { - description: "e.g. CEO, Marketing Manager, Technical Lead", - }, - }, - { - name: "account", - type: "relationship", - relationTo: "crm-accounts", - label: "Company / Account", - admin: { - description: - "Link this person to an organization from the Accounts collection.", - }, - }, - { - name: "interactions", - type: "join", - collection: "crm-interactions", - on: "contact", - admin: { - description: - "Timeline of all communication logged directly with this person.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/collections/CrmInteractions.ts b/apps/web/src/payload/collections/CrmInteractions.ts deleted file mode 100644 index 30ea04c..0000000 --- a/apps/web/src/payload/collections/CrmInteractions.ts +++ /dev/null @@ -1,143 +0,0 @@ -import type { CollectionConfig } from "payload"; -import { lexicalEditor } from "@payloadcms/richtext-lexical"; - -export const CrmInteractions: CollectionConfig = { - slug: "crm-interactions", - labels: { - singular: "Journal Entry", - plural: "Journal", - }, - admin: { - useAsTitle: "subject", - defaultColumns: ["type", "subject", "date", "contact", "account"], - group: "CRM", - description: - "Your CRM journal. Log what happened, when, on which channel, and attach any relevant files. This is for summaries and facts — not for sending messages.", - }, - access: { - read: ({ req: { user } }) => Boolean(user), - create: ({ req: { user } }) => Boolean(user), - update: ({ req: { user } }) => Boolean(user), - delete: ({ req: { user } }) => Boolean(user), - }, - fields: [ - { - type: "row", - fields: [ - { - name: "type", - type: "select", - label: "Channel", - options: [ - { label: "📧 Email", value: "email" }, - { label: "📞 Phone Call", value: "call" }, - { label: "🤝 Meeting", value: "meeting" }, - { label: "📱 WhatsApp", value: "whatsapp" }, - { label: "🌐 Social Media", value: "social" }, - { label: "📄 Document / File", value: "document" }, - { label: "📝 Internal Note", value: "note" }, - ], - required: true, - defaultValue: "note", - admin: { - width: "50%", - description: "Where did this communication take place?", - }, - }, - { - name: "direction", - type: "select", - options: [ - { label: "📥 Incoming (from Client)", value: "inbound" }, - { label: "📤 Outgoing (to Client)", value: "outbound" }, - ], - admin: { - hidden: true, // Hide from UI to prevent usage, but keep in DB schema to avoid Drizzle prompts - }, - }, - { - name: "date", - type: "date", - required: true, - defaultValue: () => new Date().toISOString(), - admin: { - width: "50%", - date: { - pickerAppearance: "dayAndTime", - }, - description: "When did this happen?", - }, - }, - ], - }, - { - name: "subject", - type: "text", - required: true, - label: "Subject / Title", - admin: { - placeholder: "e.g. Herr X hat Website-Relaunch beauftragt", - }, - }, - { - type: "row", - fields: [ - { - name: "contact", - type: "relationship", - relationTo: "crm-contacts", - label: "Contact Person", - admin: { - width: "50%", - description: "Who was involved?", - }, - }, - { - name: "account", - type: "relationship", - relationTo: "crm-accounts", - label: "Company / Account", - admin: { - width: "50%", - }, - }, - ], - }, - { - name: "topic", - type: "relationship", - relationTo: "crm-topics", - label: "Related Topic", - admin: { - description: - "Optional: Group this entry under a specific project or topic.", - condition: (data) => { - return Boolean(data?.account); - }, - }, - }, - { - name: "content", - type: "richText", - label: "Summary / Notes", - editor: lexicalEditor({ - features: ({ defaultFeatures }) => [...defaultFeatures], - }), - admin: { - description: - "Summarize what happened, what was decided, or what the next steps are.", - }, - }, - { - name: "attachments", - type: "relationship", - relationTo: "media", - hasMany: true, - label: "Attachments", - admin: { - description: - "Attach received documents, screenshots, contracts, or any relevant files.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/collections/CrmTopics.ts b/apps/web/src/payload/collections/CrmTopics.ts deleted file mode 100644 index 1205407..0000000 --- a/apps/web/src/payload/collections/CrmTopics.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { CollectionConfig } from "payload"; - -export const CrmTopics: CollectionConfig = { - slug: "crm-topics", - labels: { - singular: "Topic", - plural: "Topics", - }, - admin: { - useAsTitle: "title", - defaultColumns: ["title", "account", "status"], - group: "CRM", - description: - "Group your interactions (emails, calls, notes) into Topics. This helps you keep track of specific projects with a client.", - }, - access: { - read: ({ req: { user } }) => Boolean(user), - create: ({ req: { user } }) => Boolean(user), - update: ({ req: { user } }) => Boolean(user), - delete: ({ req: { user } }) => Boolean(user), - }, - fields: [ - { - name: "title", - type: "text", - required: true, - label: "Topic Name", - admin: { - placeholder: "e.g. Website Relaunch 2026", - }, - }, - { - name: "account", - type: "relationship", - relationTo: "crm-accounts", - required: true, - label: "Client / Account", - admin: { - description: "Which account does this topic belong to?", - }, - }, - { - name: "status", - type: "select", - options: [ - { label: "🟢 Active / Open", value: "active" }, - { label: "🟡 On Hold", value: "paused" }, - { label: "🔴 Closed / Won", value: "won" }, - { label: "⚫ Closed / Lost", value: "lost" }, - ], - defaultValue: "active", - required: true, - }, - { - name: "stage", - type: "select", - options: [ - { label: "Discovery / Briefing", value: "discovery" }, - { label: "Proposal / Quote sent", value: "proposal" }, - { label: "Negotiation", value: "negotiation" }, - { label: "Implementation", value: "implementation" }, - ], - admin: { - description: "Optional: What stage is this deal/project currently in?", - }, - }, - { - name: "interactions", - type: "join", - collection: "crm-interactions", - on: "topic", - admin: { - description: - "Timeline of all emails and notes specifically related to this topic.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/collections/Inquiries.ts b/apps/web/src/payload/collections/Inquiries.ts deleted file mode 100644 index abb6be3..0000000 --- a/apps/web/src/payload/collections/Inquiries.ts +++ /dev/null @@ -1,98 +0,0 @@ -import type { CollectionConfig } from "payload"; -import { convertInquiryEndpoint } from "../endpoints/convertInquiryEndpoint"; - -export const Inquiries: CollectionConfig = { - slug: "inquiries", - labels: { - singular: "Inquiry", - plural: "Inquiries", - }, - admin: { - useAsTitle: "name", - defaultColumns: ["name", "email", "companyName", "createdAt"], - description: "Contact form leads and inquiries.", - }, - access: { - read: ({ req: { user } }) => Boolean(user), // Admin only - create: () => true, // Everyone can submit - update: ({ req: { user } }) => Boolean(user), - delete: ({ req: { user } }) => Boolean(user), - }, - endpoints: [ - { - path: "/:id/convert-to-lead", - method: "post", - handler: convertInquiryEndpoint, - }, - ], - fields: [ - { - name: "convertButton", - type: "ui", - admin: { - components: { - Field: - "@/src/payload/components/ConvertInquiryButton#ConvertInquiryButton", - }, - condition: (data) => { - return !data?.processed; - }, - }, - }, - { - name: "processed", - type: "checkbox", - defaultValue: false, - admin: { - description: "Has this inquiry been converted into a CRM Lead?", - readOnly: true, - }, - }, - { - name: "name", - type: "text", - required: true, - }, - { - name: "email", - type: "text", // Using text for email format, or 'email' type if strictly enforced - required: true, - }, - { - name: "companyName", - type: "text", - }, - { - name: "phone", - type: "text", - }, - { - name: "role", - type: "text", - }, - { - name: "projectType", - type: "text", - }, - { - name: "deadline", - type: "text", - }, - { - name: "message", - type: "textarea", - }, - { - name: "isFreeText", - type: "checkbox", - defaultValue: false, - }, - { - name: "config", - type: "json", - admin: { - description: "The JSON data from the configurator.", - }, - }, - ], -}; diff --git a/apps/web/src/payload/collections/Media.ts b/apps/web/src/payload/collections/Media.ts deleted file mode 100644 index 0f52ad8..0000000 --- a/apps/web/src/payload/collections/Media.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { CollectionConfig } from "payload"; -import path from "path"; -import { fileURLToPath } from "url"; -import { replicateMediaHandler } from "@mintel/payload-ai/endpoints/replicateMediaEndpoint"; - -const filename = fileURLToPath(import.meta.url); -const dirname = path.dirname(filename); - -export const Media: CollectionConfig = { - slug: "media", - admin: { - useAsTitle: "alt", - defaultColumns: ["filename", "alt", "updatedAt"], - }, - access: { - read: () => true, // Publicly readable - }, - endpoints: [ - { - path: "/:id/ai-process", - method: "post", - handler: replicateMediaHandler as any, - }, - ], - upload: { - staticDir: path.resolve(dirname, "../../../../public/media"), - adminThumbnail: "thumbnail", - imageSizes: [ - { - name: "thumbnail", - width: 400, - height: 300, - position: "centre", - }, - { - name: "card", - width: 768, - height: 1024, - position: "centre", - }, - { - name: "tablet", - width: 1024, - height: undefined, - position: "centre", - }, - ], - }, - fields: [ - { - name: "aiProcessButtons", - type: "ui", - admin: { - components: { - Field: "@mintel/payload-ai/components/AiMediaButtons#AiMediaButtons", - }, - }, - }, - { - name: "alt", - type: "text", - required: true, - }, - ], -}; diff --git a/apps/web/src/payload/collections/Posts.ts b/apps/web/src/payload/collections/Posts.ts deleted file mode 100644 index bb10d2c..0000000 --- a/apps/web/src/payload/collections/Posts.ts +++ /dev/null @@ -1,121 +0,0 @@ -import type { CollectionConfig } from "payload"; -import { lexicalEditor, BlocksFeature } from "@payloadcms/richtext-lexical"; -import { payloadBlocks } from "../blocks/allBlocks"; - -export const Posts: CollectionConfig = { - slug: "posts", - admin: { - useAsTitle: "title", - defaultColumns: ["featuredImage", "title", "date", "updatedAt", "_status"], - }, - versions: { - drafts: true, - }, - access: { - read: () => true, // Publicly readable API - }, - fields: [ - { - name: "aiOptimizer", - type: "ui", - admin: { - position: "sidebar", - components: { - Field: "@mintel/payload-ai/components/OptimizeButton#OptimizeButton", - }, - }, - }, - { - name: "title", - type: "text", - required: true, - }, - { - name: "slug", - type: "text", - required: true, - unique: true, - admin: { - position: "sidebar", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/GenerateSlugButton#GenerateSlugButton", - ], - }, - }, - hooks: { - beforeValidate: [ - ({ value, data }) => { - if (value) return value; - if (data?.title) { - return data.title - .toLowerCase() - .replace(/ /g, "-") - .replace(/[^\w-]+/g, ""); - } - return value; - }, - ], - }, - }, - { - name: "description", - type: "text", - required: true, - }, - { - name: "date", - type: "date", - required: true, - admin: { - position: "sidebar", - description: - "Set a future date and save as 'Published' to schedule this post. It will not appear on the frontend until this date is reached.", - }, - }, - { - name: "tags", - type: "array", - required: true, - admin: { - position: "sidebar", - }, - fields: [ - { - name: "tag", - type: "text", - admin: { - description: "Kategorisiere diesen Post mit einem eindeutigen Tag", - components: { Field: "@/src/payload/components/TagSelector" }, - }, - }, - ], - }, - { - name: "featuredImage", - type: "upload", - relationTo: "media", - admin: { - description: "The main hero image for the blog post.", - position: "sidebar", - components: { - afterInput: [ - "@mintel/payload-ai/components/FieldGenerators/GenerateThumbnailButton#GenerateThumbnailButton", - ], - }, - }, - }, - { - name: "content", - type: "richText", - editor: lexicalEditor({ - features: ({ defaultFeatures }) => [ - ...defaultFeatures, - BlocksFeature({ - blocks: payloadBlocks, - }), - ], - }), - }, - ], -}; diff --git a/apps/web/src/payload/collections/Projects.ts b/apps/web/src/payload/collections/Projects.ts deleted file mode 100644 index 8f42018..0000000 --- a/apps/web/src/payload/collections/Projects.ts +++ /dev/null @@ -1,192 +0,0 @@ -import type { CollectionConfig } from "payload"; - -export const Projects: CollectionConfig = { - slug: "projects", - labels: { - singular: "Project", - plural: "Projects", - }, - admin: { - useAsTitle: "title", - defaultColumns: ["title", "account", "status", "startDate", "targetDate"], - group: "Project Management", - description: "Manage high-level projects for your clients.", - components: { - beforeListTable: ["@/src/payload/views/GanttChart#GanttChartView"], - }, - }, - access: { - read: ({ req: { user } }) => Boolean(user), - create: ({ req: { user } }) => Boolean(user), - update: ({ req: { user } }) => Boolean(user), - delete: ({ req: { user } }) => Boolean(user), - }, - fields: [ - { - name: "title", - type: "text", - required: true, - label: "Project Title", - }, - { - name: "account", - type: "relationship", - relationTo: "crm-accounts", - required: true, - label: "Client / Account", - admin: { - description: "Which account is this project for?", - }, - }, - { - name: "contact", - type: "relationship", - relationTo: "crm-contacts", - hasMany: true, - label: "Project Stakeholders", - admin: { - description: - "Key contacts from the client side involved in this project.", - }, - }, - { - name: "status", - type: "select", - options: [ - { label: "Draft", value: "draft" }, - { label: "In Progress", value: "in_progress" }, - { label: "Review", value: "review" }, - { label: "Completed", value: "completed" }, - ], - defaultValue: "draft", - required: true, - }, - { - type: "row", - fields: [ - { - name: "startDate", - type: "date", - label: "Start Date", - admin: { width: "25%" }, - }, - { - name: "targetDate", - type: "date", - label: "Target Date", - admin: { width: "25%" }, - }, - { - name: "valueMin", - type: "number", - label: "Value From (€)", - admin: { - width: "25%", - placeholder: "z.B. 5000", - }, - }, - { - name: "valueMax", - type: "number", - label: "Value To (€)", - admin: { - width: "25%", - placeholder: "z.B. 8000", - }, - }, - ], - }, - { - name: "briefing", - type: "richText", - label: "Briefing", - admin: { - description: "Project briefing, requirements, or notes.", - }, - }, - { - name: "attachments", - type: "upload", - relationTo: "media", - hasMany: true, - label: "Attachments", - admin: { - description: - "Upload files, documents, or assets related to this project.", - }, - }, - { - name: "milestones", - type: "array", - label: "Milestones", - admin: { - description: "Granular deliverables or milestones within this project.", - }, - fields: [ - { - name: "name", - type: "text", - required: true, - label: "Milestone Name", - admin: { - placeholder: "e.g. Authentication System", - }, - }, - { - type: "row", - fields: [ - { - name: "status", - type: "select", - options: [ - { label: "To Do", value: "todo" }, - { label: "In Progress", value: "in_progress" }, - { label: "Done", value: "done" }, - ], - defaultValue: "todo", - required: true, - admin: { width: "50%" }, - }, - { - name: "priority", - type: "select", - options: [ - { label: "Low", value: "low" }, - { label: "Medium", value: "medium" }, - { label: "High", value: "high" }, - ], - defaultValue: "medium", - admin: { width: "50%" }, - }, - ], - }, - { - type: "row", - fields: [ - { - name: "startDate", - type: "date", - label: "Start Date", - admin: { width: "50%" }, - }, - { - name: "targetDate", - type: "date", - label: "Target Date", - admin: { width: "50%" }, - }, - ], - }, - { - name: "assignee", - type: "relationship", - relationTo: "users", - label: "Assignee", - admin: { - description: "Internal team member responsible for this milestone.", - }, - }, - ], - }, - ], -}; diff --git a/apps/web/src/payload/collections/Redirects.ts b/apps/web/src/payload/collections/Redirects.ts deleted file mode 100644 index 7378da2..0000000 --- a/apps/web/src/payload/collections/Redirects.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { CollectionConfig } from "payload"; - -export const Redirects: CollectionConfig = { - slug: "redirects", - admin: { - useAsTitle: "from", - defaultColumns: ["from", "to", "createdAt"], - }, - access: { - read: () => true, - }, - fields: [ - { - name: "from", - type: "text", - required: true, - unique: true, - admin: { - description: - "The old URL slug that should be redirected (e.g. 'old-post-name')", - }, - }, - { - name: "to", - type: "text", - required: true, - admin: { - description: - "The new URL slug to redirect to (e.g. 'new-awesome-post')", - }, - }, - ], -}; diff --git a/apps/web/src/payload/collections/Users.ts b/apps/web/src/payload/collections/Users.ts deleted file mode 100644 index c1ba5fa..0000000 --- a/apps/web/src/payload/collections/Users.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { CollectionConfig } from "payload"; - -export const Users: CollectionConfig = { - slug: "users", - admin: { - useAsTitle: "email", - }, - auth: true, - fields: [ - // Email added by default due to auth - // Add more fields as needed - ], -}; diff --git a/apps/web/src/payload/components/AiAnalyzeButton.tsx b/apps/web/src/payload/components/AiAnalyzeButton.tsx deleted file mode 100644 index 57f195c..0000000 --- a/apps/web/src/payload/components/AiAnalyzeButton.tsx +++ /dev/null @@ -1,100 +0,0 @@ -"use client"; - -import React, { useState, useEffect } from "react"; -import { useDocumentInfo } from "@payloadcms/ui"; -import { toast } from "@payloadcms/ui"; - -export const AiAnalyzeButton: React.FC = () => { - const { id } = useDocumentInfo(); - const [isAnalyzing, setIsAnalyzing] = useState(false); - const [hasWebsite, setHasWebsite] = useState(false); - - useEffect(() => { - // Basic check if a website URL is likely present - would ideally check true document state - // but the fields might not be fully available in this context depending on Payload version. - // For now we just enable the button and the backend will validate. - setHasWebsite(true); - }, []); - - const handleAnalyze = async (e: React.MouseEvent) => { - e.preventDefault(); - if (!id) return; - - setIsAnalyzing(true); - toast.info( - "Starting AI analysis for this account. This may take a few minutes...", - ); - - try { - const response = await fetch(`/api/crm-accounts/${id}/analyze`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - }); - - const result = await response.json(); - - if (!response.ok) { - throw new Error(result.error || "Analysis failed"); - } - - toast.success( - result.message || - "Analysis started in background. The page will update when finished.", - ); - // Removed router.refresh() here because the background task takes ~60s - } catch (error) { - console.error("Analysis error:", error); - toast.error( - error instanceof Error - ? error.message - : "An error occurred during analysis", - ); - } finally { - setIsAnalyzing(false); - } - }; - - if (!id) return null; // Only show on existing documents, not when creating new - - return ( -
- -

- Note: This will crawl the website, generate a strategy - concept, and create a budget estimation. The resulting PDFs will be - attached to the "AI Reports" field below. -

-
- ); -}; diff --git a/apps/web/src/payload/components/BulkMailButton.tsx b/apps/web/src/payload/components/BulkMailButton.tsx deleted file mode 100644 index 66bf2e7..0000000 --- a/apps/web/src/payload/components/BulkMailButton.tsx +++ /dev/null @@ -1,147 +0,0 @@ -"use client"; - -import React, { useState } from "react"; -import { useSelection, Button, toast } from "@payloadcms/ui"; - -export const BulkMailButton: React.FC = () => { - const { selected } = useSelection(); - const [isOpen, setIsOpen] = useState(false); - const [prompt, setPrompt] = useState(""); - const [isTest, setIsTest] = useState(true); - const [isLoading, setIsLoading] = useState(false); - - const selectedCount = Object.keys(selected).length; - - if (selectedCount === 0) { - return null; - } - - const handleBulkMail = async () => { - setIsLoading(true); - try { - const contactIds = Object.keys(selected); - - const response = await fetch("/api/crm-contacts/bulk-mail", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - contactIds, - instructions: prompt, - isTest, - }), - }); - - const data = await response.json(); - - if (data.success) { - toast.success( - `Successfully sent emails to ${contactIds.length} contacts.`, - ); - setIsOpen(false); - } else { - toast.error(`Failed: ${data.error}`); - } - } catch (e: any) { - toast.error(`An error occurred: ${e.message}`); - } finally { - setIsLoading(false); - } - }; - - return ( -
- - - {isOpen && ( -
-
-

AI Bulk Mail

-

- Generate and send personalized emails to {selectedCount} contacts. -

- -
- -