diff --git a/apps/api/package.json b/apps/api/package.json
index 1c16e53d3..c7630a538 100644
--- a/apps/api/package.json
+++ b/apps/api/package.json
@@ -13,6 +13,7 @@
"@nestjs/swagger": "^11.2.0",
"@trycompai/db": "^1.3.4",
"archiver": "^7.0.1",
+ "axios": "^1.12.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.2",
"jose": "^6.0.12",
diff --git a/apps/app/public/badges/pci-dss.svg b/apps/app/public/badges/pci-dss.svg
new file mode 100644
index 000000000..ec647137b
--- /dev/null
+++ b/apps/app/public/badges/pci-dss.svg
@@ -0,0 +1,16 @@
+
diff --git a/apps/app/src/actions/organization/update-organization-advanced-mode-action.ts b/apps/app/src/actions/organization/update-organization-advanced-mode-action.ts
new file mode 100644
index 000000000..0044f1a30
--- /dev/null
+++ b/apps/app/src/actions/organization/update-organization-advanced-mode-action.ts
@@ -0,0 +1,48 @@
+'use server';
+
+import { db } from '@db';
+import { revalidatePath, revalidateTag } from 'next/cache';
+import { headers } from 'next/headers';
+import { authActionClient } from '../safe-action';
+import { organizationAdvancedModeSchema } from '../schema';
+
+export const updateOrganizationAdvancedModeAction = authActionClient
+ .inputSchema(organizationAdvancedModeSchema)
+ .metadata({
+ name: 'update-organization-advanced-mode',
+ track: {
+ event: 'update-organization-advanced-mode',
+ channel: 'server',
+ },
+ })
+ .action(async ({ parsedInput, ctx }) => {
+ const { advancedModeEnabled } = parsedInput;
+ const { activeOrganizationId } = ctx.session;
+
+ if (!activeOrganizationId) {
+ throw new Error('No active organization');
+ }
+
+ try {
+ await db.$transaction(async () => {
+ await db.organization.update({
+ where: { id: activeOrganizationId },
+ data: { advancedModeEnabled },
+ });
+ });
+
+ const headersList = await headers();
+ let path = headersList.get('x-pathname') || headersList.get('referer') || '';
+ path = path.replace(/\/[a-z]{2}\//, '/');
+
+ revalidatePath(path);
+ revalidateTag(`organization_${activeOrganizationId}`);
+
+ return {
+ success: true,
+ };
+ } catch (error) {
+ console.error(error);
+ throw new Error('Failed to update advanced mode setting');
+ }
+ });
diff --git a/apps/app/src/actions/schema.ts b/apps/app/src/actions/schema.ts
index 8a95aa782..6dc15fe11 100644
--- a/apps/app/src/actions/schema.ts
+++ b/apps/app/src/actions/schema.ts
@@ -61,6 +61,10 @@ export const organizationWebsiteSchema = z.object({
.max(255, 'Website cannot exceed 255 characters'),
});
+export const organizationAdvancedModeSchema = z.object({
+ advancedModeEnabled: z.boolean(),
+});
+
// Risks
export const createRiskSchema = z.object({
title: z
diff --git a/apps/app/src/app/(app)/[orgId]/frameworks/components/FrameworksOverview.tsx b/apps/app/src/app/(app)/[orgId]/frameworks/components/FrameworksOverview.tsx
index 184deb60c..a17329ff9 100644
--- a/apps/app/src/app/(app)/[orgId]/frameworks/components/FrameworksOverview.tsx
+++ b/apps/app/src/app/(app)/[orgId]/frameworks/components/FrameworksOverview.tsx
@@ -36,6 +36,10 @@ export function mapFrameworkToBadge(framework: FrameworkInstanceWithControls) {
return '/badges/gdpr.svg';
}
+ if (framework.framework.name === 'PCI DSS') {
+ return '/badges/pci-dss.svg';
+ }
+
return null;
}
diff --git a/apps/app/src/app/(app)/[orgId]/settings/page.tsx b/apps/app/src/app/(app)/[orgId]/settings/page.tsx
index 8b3a39311..4e4a00f92 100644
--- a/apps/app/src/app/(app)/[orgId]/settings/page.tsx
+++ b/apps/app/src/app/(app)/[orgId]/settings/page.tsx
@@ -1,4 +1,5 @@
import { DeleteOrganization } from '@/components/forms/organization/delete-organization';
+import { UpdateOrganizationAdvancedMode } from '@/components/forms/organization/update-organization-advanced-mode';
import { UpdateOrganizationName } from '@/components/forms/organization/update-organization-name';
import { UpdateOrganizationWebsite } from '@/components/forms/organization/update-organization-website';
import { auth } from '@/utils/auth';
@@ -14,6 +15,9 @@ export default async function OrganizationSettings() {
+
);
@@ -40,6 +44,7 @@ const organizationDetails = cache(async () => {
name: true,
id: true,
website: true,
+ advancedModeEnabled: true,
},
});
diff --git a/apps/app/src/app/(app)/[orgId]/settings/trust-portal/actions/update-trust-portal-frameworks.ts b/apps/app/src/app/(app)/[orgId]/settings/trust-portal/actions/update-trust-portal-frameworks.ts
index 55934b4b6..192624f84 100644
--- a/apps/app/src/app/(app)/[orgId]/settings/trust-portal/actions/update-trust-portal-frameworks.ts
+++ b/apps/app/src/app/(app)/[orgId]/settings/trust-portal/actions/update-trust-portal-frameworks.ts
@@ -7,26 +7,34 @@ import { headers } from 'next/headers';
interface UpdateTrustPortalFrameworksParams {
orgId: string;
- soc2?: boolean;
+ soc2type1?: boolean;
+ soc2type2?: boolean;
iso27001?: boolean;
gdpr?: boolean;
hipaa?: boolean;
- soc2Status?: 'started' | 'in_progress' | 'compliant';
+ pcidss?: boolean;
+ soc2type1Status?: 'started' | 'in_progress' | 'compliant';
+ soc2type2Status?: 'started' | 'in_progress' | 'compliant';
iso27001Status?: 'started' | 'in_progress' | 'compliant';
gdprStatus?: 'started' | 'in_progress' | 'compliant';
hipaaStatus?: 'started' | 'in_progress' | 'compliant';
+ pcidssStatus?: 'started' | 'in_progress' | 'compliant';
}
export async function updateTrustPortalFrameworks({
orgId,
- soc2,
+ soc2type1,
+ soc2type2,
iso27001,
gdpr,
hipaa,
- soc2Status,
+ pcidss,
+ soc2type1Status,
+ soc2type2Status,
iso27001Status,
gdprStatus,
hipaaStatus,
+ pcidssStatus,
}: UpdateTrustPortalFrameworksParams) {
const session = await auth.api.getSession({
headers: await headers(),
@@ -51,14 +59,20 @@ export async function updateTrustPortalFrameworks({
organizationId: orgId,
},
data: {
- soc2: soc2 ?? trustPortal.soc2,
+ soc2: soc2type2 ?? trustPortal.soc2,
+ soc2type1: soc2type1 ?? trustPortal.soc2type1,
+ soc2type2: soc2type2 ?? trustPortal.soc2type2,
iso27001: iso27001 ?? trustPortal.iso27001,
gdpr: gdpr ?? trustPortal.gdpr,
hipaa: hipaa ?? trustPortal.hipaa,
- soc2_status: soc2Status ?? trustPortal.soc2_status,
+ pci_dss: pcidss ?? trustPortal.pci_dss,
+ soc2_status: soc2type2Status ?? trustPortal.soc2_status,
+ soc2type1_status: soc2type1Status ?? trustPortal.soc2type1_status,
+ soc2type2_status: soc2type2Status ?? trustPortal.soc2type2_status,
iso27001_status: iso27001Status ?? trustPortal.iso27001_status,
gdpr_status: gdprStatus ?? trustPortal.gdpr_status,
hipaa_status: hipaaStatus ?? trustPortal.hipaa_status,
+ pci_dss_status: pcidssStatus ?? trustPortal.pci_dss_status,
},
});
diff --git a/apps/app/src/app/(app)/[orgId]/settings/trust-portal/components/TrustPortalSwitch.tsx b/apps/app/src/app/(app)/[orgId]/settings/trust-portal/components/TrustPortalSwitch.tsx
index af6ca0fcb..7b49ef5d7 100644
--- a/apps/app/src/app/(app)/[orgId]/settings/trust-portal/components/TrustPortalSwitch.tsx
+++ b/apps/app/src/app/(app)/[orgId]/settings/trust-portal/components/TrustPortalSwitch.tsx
@@ -17,20 +17,24 @@ import { z } from 'zod';
import { isFriendlyAvailable } from '../actions/is-friendly-available';
import { trustPortalSwitchAction } from '../actions/trust-portal-switch';
import { updateTrustPortalFrameworks } from '../actions/update-trust-portal-frameworks';
-import { GDPR, HIPAA, ISO27001, SOC2 } from './logos';
+import { GDPR, HIPAA, ISO27001, SOC2, SOC2Type1, SOC2Type2, PCIDSS } from './logos';
const trustPortalSwitchSchema = z.object({
enabled: z.boolean(),
contactEmail: z.string().email().or(z.literal('')).optional(),
friendlyUrl: z.string().optional(),
- soc2: z.boolean(),
+ soc2type1: z.boolean(),
+ soc2type2: z.boolean(),
iso27001: z.boolean(),
gdpr: z.boolean(),
hipaa: z.boolean(),
- soc2Status: z.enum(['started', 'in_progress', 'compliant']),
+ pcidss: z.boolean(),
+ soc2type1Status: z.enum(['started', 'in_progress', 'compliant']),
+ soc2type2Status: z.enum(['started', 'in_progress', 'compliant']),
iso27001Status: z.enum(['started', 'in_progress', 'compliant']),
gdprStatus: z.enum(['started', 'in_progress', 'compliant']),
hipaaStatus: z.enum(['started', 'in_progress', 'compliant']),
+ pcidssStatus: z.enum(['started', 'in_progress', 'compliant']),
});
export function TrustPortalSwitch({
@@ -40,14 +44,18 @@ export function TrustPortalSwitch({
domain,
contactEmail,
orgId,
- soc2,
+ soc2type1,
+ soc2type2,
iso27001,
gdpr,
hipaa,
- soc2Status,
+ pcidss,
+ soc2type1Status,
+ soc2type2Status,
iso27001Status,
gdprStatus,
hipaaStatus,
+ pcidssStatus,
friendlyUrl,
}: {
enabled: boolean;
@@ -56,14 +64,18 @@ export function TrustPortalSwitch({
domain: string;
contactEmail: string | null;
orgId: string;
- soc2: boolean;
+ soc2type1: boolean;
+ soc2type2: boolean;
iso27001: boolean;
gdpr: boolean;
hipaa: boolean;
- soc2Status: 'started' | 'in_progress' | 'compliant';
+ pcidss: boolean;
+ soc2type1Status: 'started' | 'in_progress' | 'compliant';
+ soc2type2Status: 'started' | 'in_progress' | 'compliant';
iso27001Status: 'started' | 'in_progress' | 'compliant';
gdprStatus: 'started' | 'in_progress' | 'compliant';
hipaaStatus: 'started' | 'in_progress' | 'compliant';
+ pcidssStatus: 'started' | 'in_progress' | 'compliant';
friendlyUrl: string | null;
}) {
const trustPortalSwitch = useAction(trustPortalSwitchAction, {
@@ -82,14 +94,18 @@ export function TrustPortalSwitch({
defaultValues: {
enabled: enabled,
contactEmail: contactEmail ?? undefined,
- soc2: soc2 ?? false,
+ soc2type1: soc2type1 ?? false,
+ soc2type2: soc2type2 ?? false,
iso27001: iso27001 ?? false,
gdpr: gdpr ?? false,
hipaa: hipaa ?? false,
- soc2Status: soc2Status ?? 'started',
+ pcidss: pcidss ?? false,
+ soc2type1Status: soc2type1Status ?? 'started',
+ soc2type2Status: soc2type2Status ?? 'started',
iso27001Status: iso27001Status ?? 'started',
gdprStatus: gdprStatus ?? 'started',
hipaaStatus: hipaaStatus ?? 'started',
+ pcidssStatus: pcidssStatus ?? 'started',
friendlyUrl: friendlyUrl ?? undefined,
},
});
@@ -314,35 +330,6 @@ export function TrustPortalSwitch({
Share the frameworks your organization is compliant with or working towards.
- {/* SOC 2 */}
- {
- try {
- await updateTrustPortalFrameworks({
- orgId,
- soc2Status: value as 'started' | 'in_progress' | 'compliant',
- });
- toast.success('SOC 2 status updated');
- } catch (error) {
- toast.error('Failed to update SOC 2 status');
- }
- }}
- onToggle={async (checked) => {
- try {
- await updateTrustPortalFrameworks({
- orgId,
- soc2: checked,
- });
- toast.success('SOC 2 status updated');
- } catch (error) {
- toast.error('Failed to update SOC 2 status');
- }
- }}
- />
{/* ISO 27001 */}
+ {/* SOC 2 TYPE I*/}
+ {
+ try {
+ await updateTrustPortalFrameworks({
+ orgId,
+ soc2type1Status: value as 'started' | 'in_progress' | 'compliant',
+ });
+ toast.success('SOC 2 TYPE I status updated');
+ } catch (error) {
+ toast.error('Failed to update SOC 2 TYPE I status');
+ }
+ }}
+ onToggle={async (checked) => {
+ try {
+ await updateTrustPortalFrameworks({
+ orgId,
+ soc2type1: checked,
+ });
+ toast.success('SOC 2 TYPE I status updated');
+ } catch (error) {
+ toast.error('Failed to update SOC 2 TYPE I status');
+ }
+ }}
+ />
+ {/* SOC 2 TYPE II*/}
+ {
+ try {
+ await updateTrustPortalFrameworks({
+ orgId,
+ soc2type2Status: value as 'started' | 'in_progress' | 'compliant',
+ });
+ toast.success('SOC 2 TYPE II status updated');
+ } catch (error) {
+ toast.error('Failed to update SOC 2 TYPE II status');
+ }
+ }}
+ onToggle={async (checked) => {
+ try {
+ await updateTrustPortalFrameworks({
+ orgId,
+ soc2type2: checked,
+ });
+ toast.success('SOC 2 TYPE II status updated');
+ } catch (error) {
+ toast.error('Failed to update SOC 2 TYPE II status');
+ }
+ }}
+ />
+ {/* PCI DSS */}
+ {
+ try {
+ await updateTrustPortalFrameworks({
+ orgId,
+ pcidssStatus: value as 'started' | 'in_progress' | 'compliant',
+ });
+ toast.success('PCI DSS status updated');
+ } catch (error) {
+ toast.error('Failed to update PCI DSS status');
+ }
+ }}
+ onToggle={async (checked) => {
+ try {
+ await updateTrustPortalFrameworks({
+ orgId,
+ pcidss: checked,
+ });
+ toast.success('PCI DSS status updated');
+ } catch (error) {
+ toast.error('Failed to update PCI DSS status');
+ }
+ }}
+ />
@@ -458,11 +532,7 @@ function ComplianceFramework({
onToggle: (checked: boolean) => Promise;
}) {
const logo =
- title === 'SOC 2' ? (
-
-
-
- ) : title === 'ISO 27001' ? (
+ title === 'ISO 27001' ? (
@@ -474,6 +544,18 @@ function ComplianceFramework({
+ ) : title === 'SOC 2 TYPE I' ? (
+
+
+
+ ) : title === 'SOC 2 TYPE II' ? (
+
+
+
+ ) : title === 'PCI DSS' ? (
+
) : null;
return (
diff --git a/apps/app/src/app/(app)/[orgId]/settings/trust-portal/components/logos.tsx b/apps/app/src/app/(app)/[orgId]/settings/trust-portal/components/logos.tsx
index 0a3a6fb2e..d353f1282 100644
--- a/apps/app/src/app/(app)/[orgId]/settings/trust-portal/components/logos.tsx
+++ b/apps/app/src/app/(app)/[orgId]/settings/trust-portal/components/logos.tsx
@@ -2,7 +2,7 @@ import * as React from 'react';
export const SOC2 = (props: React.SVGProps) => (
);
+
+export const SOC2Type1 = (props: React.SVGProps) => (
+
+);
+
+export const SOC2Type2 = (props: React.SVGProps) => (
+
+);
+
+export const PCIDSS = (props: React.SVGProps) => (
+
+);
diff --git a/apps/app/src/app/(app)/[orgId]/settings/trust-portal/page.tsx b/apps/app/src/app/(app)/[orgId]/settings/trust-portal/page.tsx
index 1105435ec..919ebecc7 100644
--- a/apps/app/src/app/(app)/[orgId]/settings/trust-portal/page.tsx
+++ b/apps/app/src/app/(app)/[orgId]/settings/trust-portal/page.tsx
@@ -23,14 +23,18 @@ export default async function TrustPortalSettings({
domainVerified={trustPortal?.domainVerified ?? false}
contactEmail={trustPortal?.contactEmail ?? null}
orgId={orgId}
- soc2={trustPortal?.soc2 ?? false}
+ soc2type1={trustPortal?.soc2type1 ?? false}
+ soc2type2={trustPortal?.soc2type2 ?? false}
iso27001={trustPortal?.iso27001 ?? false}
gdpr={trustPortal?.gdpr ?? false}
hipaa={trustPortal?.hipaa ?? false}
- soc2Status={trustPortal?.soc2Status ?? 'started'}
+ pcidss={trustPortal?.pcidss ?? false}
+ soc2type1Status={trustPortal?.soc2type1Status ?? 'started'}
+ soc2type2Status={trustPortal?.soc2type2Status ?? 'started'}
iso27001Status={trustPortal?.iso27001Status ?? 'started'}
gdprStatus={trustPortal?.gdprStatus ?? 'started'}
hipaaStatus={trustPortal?.hipaaStatus ?? 'started'}
+ pcidssStatus={trustPortal?.pcidssStatus ?? 'started'}
friendlyUrl={trustPortal?.friendlyUrl ?? null}
/>
{
domain: trustPortal?.domain,
domainVerified: trustPortal?.domainVerified,
contactEmail: trustPortal?.contactEmail ?? '',
- soc2: trustPortal?.soc2,
+ soc2type1: trustPortal?.soc2type1,
+ soc2type2: trustPortal?.soc2type2 || trustPortal?.soc2,
iso27001: trustPortal?.iso27001,
gdpr: trustPortal?.gdpr,
hipaa: trustPortal?.hipaa,
- soc2Status: trustPortal?.soc2_status,
+ pcidss: trustPortal?.pci_dss,
+ soc2type1Status: trustPortal?.soc2type1_status,
+ soc2type2Status: !trustPortal?.soc2type2 && trustPortal?.soc2 ? trustPortal?.soc2_status : trustPortal?.soc2type2_status,
iso27001Status: trustPortal?.iso27001_status,
gdprStatus: trustPortal?.gdpr_status,
hipaaStatus: trustPortal?.hipaa_status,
+ pcidssStatus: trustPortal?.pci_dss_status,
isVercelDomain: trustPortal?.isVercelDomain,
vercelVerification: trustPortal?.vercelVerification,
friendlyUrl: trustPortal?.friendlyUrl,
diff --git a/apps/app/src/app/(app)/upgrade/[orgId]/components/booking-step.tsx b/apps/app/src/app/(app)/upgrade/[orgId]/components/booking-step.tsx
index 176963467..30ce09888 100644
--- a/apps/app/src/app/(app)/upgrade/[orgId]/components/booking-step.tsx
+++ b/apps/app/src/app/(app)/upgrade/[orgId]/components/booking-step.tsx
@@ -1,9 +1,12 @@
'use client';
+import { useState } from 'react';
+import { ArrowRight, Check, Copy } from 'lucide-react';
+import { toast } from 'sonner';
+import Link from 'next/link';
import { Button } from '@comp/ui/button';
import { Card } from '@comp/ui/card';
-import { ArrowRight } from 'lucide-react';
-import Link from 'next/link';
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@comp/ui/tooltip';
export function BookingStep({
email,
@@ -20,6 +23,8 @@ export function BookingStep({
complianceFrameworks: string[];
hasAccess: boolean;
}) {
+ const [isCopied, setIsCopied] = useState(false);
+
const title = !hasAccess ? `Let's get ${company} approved` : 'Talk to us to upgrade';
const description = !hasAccess
@@ -28,6 +33,23 @@ export function BookingStep({
const cta = !hasAccess ? 'Book Your Demo' : 'Book a Call';
+ const handleCopyOrgId = async () => {
+ if (isCopied) return;
+
+ try {
+ await navigator.clipboard.writeText(orgId);
+ setIsCopied(true);
+ toast.success('Org ID copied to clipboard');
+
+ // Reset after 3 seconds
+ setTimeout(() => {
+ setIsCopied(false);
+ }, 3000);
+ } catch (error) {
+ toast.error('Failed to copy Org ID');
+ }
+ };
+
return (
@@ -38,6 +60,36 @@ export function BookingStep({
{description}
+ {/* Org ID Display with Copy Button */}
+
+
+ Org ID: {orgId}
+
+
+
+
+
+
+
+ {isCopied ? "Copied!" : "Copy Org ID"}
+
+
+
+
+
{/* CTA Button */}
{
+ toast.success('Advanced mode setting updated');
+ },
+ onError: () => {
+ toast.error('Error updating advanced mode setting');
+ },
+ });
+
+ const form = useForm
>({
+ resolver: zodResolver(organizationAdvancedModeSchema),
+ defaultValues: {
+ advancedModeEnabled,
+ },
+ });
+
+ const onSubmit = (data: z.infer) => {
+ updateAdvancedMode.execute(data);
+ };
+
+ return (
+
+
+ );
+}
diff --git a/apps/app/src/components/main-menu.tsx b/apps/app/src/components/main-menu.tsx
index 4be652028..4a4070eff 100644
--- a/apps/app/src/components/main-menu.tsx
+++ b/apps/app/src/components/main-menu.tsx
@@ -44,7 +44,12 @@ interface ItemProps {
itemRef: (el: HTMLDivElement | null) => void;
}
-export function MainMenu({ organizationId, isCollapsed = false, onItemClick }: Props) {
+export function MainMenu({
+ organizationId,
+ organization,
+ isCollapsed = false,
+ onItemClick,
+}: Props) {
const pathname = usePathname();
const [activeStyle, setActiveStyle] = useState({ top: '0px', height: '0px' });
const itemRefs = useRef<(HTMLDivElement | null)[]>([]);
@@ -65,6 +70,7 @@ export function MainMenu({ organizationId, isCollapsed = false, onItemClick }: P
disabled: false,
icon: ShieldEllipsis,
protected: false,
+ hidden: !organization?.advancedModeEnabled,
},
{
id: 'policies',
@@ -314,6 +320,7 @@ const Item = ({
type Props = {
organizationId?: string;
+ organization?: { advancedModeEnabled?: boolean } | null;
isCollapsed?: boolean;
onItemClick?: () => void;
};
diff --git a/apps/app/src/components/mobile-menu.tsx b/apps/app/src/components/mobile-menu.tsx
index 673c7e5a3..2eeeef227 100644
--- a/apps/app/src/components/mobile-menu.tsx
+++ b/apps/app/src/components/mobile-menu.tsx
@@ -45,7 +45,11 @@ export function MobileMenu({ organizationId, organizations }: MobileMenuProps) {
organization={currentOrganization}
isCollapsed={false}
/>
-
+
diff --git a/apps/app/src/components/sidebar.tsx b/apps/app/src/components/sidebar.tsx
index 761a58ff7..d0fca391e 100644
--- a/apps/app/src/components/sidebar.tsx
+++ b/apps/app/src/components/sidebar.tsx
@@ -30,7 +30,11 @@ export async function Sidebar({
organization={organization}
isCollapsed={isCollapsed}
/>
-
+
diff --git a/bun.lock b/bun.lock
index 10200f0e0..23e443eb7 100644
--- a/bun.lock
+++ b/bun.lock
@@ -69,6 +69,7 @@
"@nestjs/swagger": "^11.2.0",
"@trycompai/db": "^1.3.4",
"archiver": "^7.0.1",
+ "axios": "^1.12.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.2",
"jose": "^6.0.12",
@@ -2297,7 +2298,7 @@
"axe-core": ["axe-core@4.10.3", "", {}, "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg=="],
- "axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
+ "axios": ["axios@1.12.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
@@ -5065,6 +5066,8 @@
"@comp/api/zod": ["zod@4.0.17", "", {}, "sha512-1PHjlYRevNxxdy2JZ8JcNAw7rX8V9P1AKkP+x/xZfxB0K5FYfuV+Ug6P/6NVSR2jHQ+FzDDoDHS04nYUsOIyLQ=="],
+ "@comp/app/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
+
"@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="],
"@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
@@ -5123,6 +5126,10 @@
"@jest/transform/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
+ "@mendable/firecrawl-js/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
+
+ "@nangohq/types/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
+
"@nangohq/types/type-fest": ["type-fest@4.32.0", "", {}, "sha512-rfgpoi08xagF3JSdtJlCwMq9DGNDE0IMh3Mkpc1wUypg9vPi786AiqeBBKcqvIkq42azsBM85N490fyZjeUftw=="],
"@nestjs/cli/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
@@ -5235,6 +5242,8 @@
"@slack/bolt/@types/express": ["@types/express@4.17.23", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ=="],
+ "@slack/bolt/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
+
"@slack/bolt/express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="],
"@slack/oauth/@slack/logger": ["@slack/logger@3.0.0", "", { "dependencies": { "@types/node": ">=12.0.0" } }, "sha512-DTuBFbqu4gGfajREEMrkq5jBhcnskinhr4+AnfJEk48zhVeEv3XnUKGIX98B74kxhYsIMfApGGySTn7V3b5yBA=="],
@@ -5247,6 +5256,8 @@
"@slack/socket-mode/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
+ "@slack/web-api/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
+
"@smithy/core/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
"@smithy/middleware-retry/uuid": ["uuid@9.0.1", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="],
@@ -6237,12 +6248,16 @@
"@slack/bolt/express/type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="],
+ "@slack/oauth/@slack/web-api/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
+
"@slack/oauth/@slack/web-api/eventemitter3": ["eventemitter3@3.1.2", "", {}, "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="],
"@slack/oauth/@slack/web-api/form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="],
"@slack/oauth/@slack/web-api/is-stream": ["is-stream@1.1.0", "", {}, "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ=="],
+ "@slack/socket-mode/@slack/web-api/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="],
+
"@slack/socket-mode/@slack/web-api/eventemitter3": ["eventemitter3@3.1.2", "", {}, "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="],
"@slack/socket-mode/@slack/web-api/form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="],
@@ -6571,10 +6586,14 @@
"@slack/bolt/express/type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
+ "@slack/oauth/@slack/web-api/axios/form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
+
"@slack/oauth/@slack/web-api/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"@slack/oauth/@slack/web-api/form-data/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
+ "@slack/socket-mode/@slack/web-api/axios/form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="],
+
"@slack/socket-mode/@slack/web-api/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"@slack/socket-mode/@slack/web-api/form-data/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
@@ -6655,8 +6674,12 @@
"@slack/bolt/express/type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+ "@slack/oauth/@slack/web-api/axios/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
+
"@slack/oauth/@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+ "@slack/socket-mode/@slack/web-api/axios/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
+
"@slack/socket-mode/@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"cli-highlight/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
@@ -6673,6 +6696,10 @@
"@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit/p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="],
+ "@slack/oauth/@slack/web-api/axios/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+
+ "@slack/socket-mode/@slack/web-api/axios/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
+
"pkg-dir/find-up/locate-path/p-locate/p-limit/p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="],
}
}
diff --git a/packages/db/package.json b/packages/db/package.json
index 9ed8a996f..da4a62d1d 100644
--- a/packages/db/package.json
+++ b/packages/db/package.json
@@ -1,7 +1,7 @@
{
"name": "@trycompai/db",
"description": "Database package with Prisma client and schema for Comp AI",
- "version": "1.3.4",
+ "version": "1.3.5",
"dependencies": {
"@prisma/client": "^6.13.0",
"dotenv": "^16.4.5"
diff --git a/packages/db/prisma/migrations/20250910222020_add_soc2_type_I_II_columns/migration.sql b/packages/db/prisma/migrations/20250910222020_add_soc2_type_I_II_columns/migration.sql
new file mode 100644
index 000000000..05eac663f
--- /dev/null
+++ b/packages/db/prisma/migrations/20250910222020_add_soc2_type_I_II_columns/migration.sql
@@ -0,0 +1,11 @@
+-- AlterTable
+ALTER TABLE "Trust" ADD COLUMN "soc2typei" BOOLEAN NOT NULL DEFAULT false;
+
+-- AlterTable
+ALTER TABLE "Trust" ADD COLUMN "soc2typei_status" "FrameworkStatus" NOT NULL DEFAULT 'started';
+
+-- AlterTable
+ALTER TABLE "Trust" ADD COLUMN "soc2typeii" BOOLEAN NOT NULL DEFAULT false;
+
+-- AlterTable
+ALTER TABLE "Trust" ADD COLUMN "soc2typeii_status" "FrameworkStatus" NOT NULL DEFAULT 'started';
diff --git a/packages/db/prisma/migrations/20250910233442_add_pci_dss_columns/migration.sql b/packages/db/prisma/migrations/20250910233442_add_pci_dss_columns/migration.sql
new file mode 100644
index 000000000..22bedf470
--- /dev/null
+++ b/packages/db/prisma/migrations/20250910233442_add_pci_dss_columns/migration.sql
@@ -0,0 +1,5 @@
+-- AlterTable
+ALTER TABLE "Trust" ADD COLUMN "pci_dss" BOOLEAN NOT NULL DEFAULT false;
+
+-- AlterTable
+ALTER TABLE "Trust" ADD COLUMN "pci_dss_status" "FrameworkStatus" NOT NULL DEFAULT 'started';
diff --git a/packages/db/prisma/migrations/20250911095434_rename_soc2_type_columns/migration.sql b/packages/db/prisma/migrations/20250911095434_rename_soc2_type_columns/migration.sql
new file mode 100644
index 000000000..3b1acde0c
--- /dev/null
+++ b/packages/db/prisma/migrations/20250911095434_rename_soc2_type_columns/migration.sql
@@ -0,0 +1,13 @@
+-- Rename SOC2 Type I/II columns to use numbers instead of Roman numerals
+
+-- Rename soc2typei to soc2type1
+ALTER TABLE "Trust" RENAME COLUMN "soc2typei" TO "soc2type1";
+
+-- Rename soc2typeii to soc2type2
+ALTER TABLE "Trust" RENAME COLUMN "soc2typeii" TO "soc2type2";
+
+-- Rename soc2typei_status to soc2type1_status
+ALTER TABLE "Trust" RENAME COLUMN "soc2typei_status" TO "soc2type1_status";
+
+-- Rename soc2typeii_status to soc2type2_status
+ALTER TABLE "Trust" RENAME COLUMN "soc2typeii_status" TO "soc2type2_status";
diff --git a/packages/db/prisma/migrations/20250911162601_add_advanced_mode_to_organization/migration.sql b/packages/db/prisma/migrations/20250911162601_add_advanced_mode_to_organization/migration.sql
new file mode 100644
index 000000000..0bfcceb8d
--- /dev/null
+++ b/packages/db/prisma/migrations/20250911162601_add_advanced_mode_to_organization/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "public"."Organization" ADD COLUMN "advancedModeEnabled" BOOLEAN NOT NULL DEFAULT false;
diff --git a/packages/db/prisma/schema/organization.prisma b/packages/db/prisma/schema/organization.prisma
index 99b63d01a..211f6d1d3 100644
--- a/packages/db/prisma/schema/organization.prisma
+++ b/packages/db/prisma/schema/organization.prisma
@@ -9,6 +9,7 @@ model Organization {
website String?
onboardingCompleted Boolean @default(false)
hasAccess Boolean @default(false)
+ advancedModeEnabled Boolean @default(false)
// FleetDM
fleetDmLabelId Int?
diff --git a/packages/db/prisma/schema/trust.prisma b/packages/db/prisma/schema/trust.prisma
index 150f23c1b..ae4273cf6 100644
--- a/packages/db/prisma/schema/trust.prisma
+++ b/packages/db/prisma/schema/trust.prisma
@@ -12,14 +12,20 @@ model Trust {
email String?
privacyPolicy String?
soc2 Boolean @default(false)
+ soc2type1 Boolean @default(false)
+ soc2type2 Boolean @default(false)
iso27001 Boolean @default(false)
gdpr Boolean @default(false)
hipaa Boolean @default(false)
+ pci_dss Boolean @default(false)
- soc2_status FrameworkStatus @default(started)
- iso27001_status FrameworkStatus @default(started)
- gdpr_status FrameworkStatus @default(started)
- hipaa_status FrameworkStatus @default(started)
+ soc2_status FrameworkStatus @default(started)
+ soc2type1_status FrameworkStatus @default(started)
+ soc2type2_status FrameworkStatus @default(started)
+ iso27001_status FrameworkStatus @default(started)
+ gdpr_status FrameworkStatus @default(started)
+ hipaa_status FrameworkStatus @default(started)
+ pci_dss_status FrameworkStatus @default(started)
@@id([status, organizationId])
@@unique([organizationId])