From 6bd2bd85151c4945cf3f8043d757a696cd2877ff Mon Sep 17 00:00:00 2001 From: Claudio Fuentes Date: Mon, 4 Aug 2025 08:22:40 -0400 Subject: [PATCH 1/3] chore: update API documentation by removing deprecated employee and risk endpoints - Deleted the `employees.mdx` and `risks.mdx` files from the API reference documentation, as they are no longer relevant. - Updated `docs.json` to replace the API Reference group with a direct link to the OpenAPI documentation, streamlining access to API details. --- packages/docs/api-reference/v1/employees.mdx | 437 ------------------- packages/docs/api-reference/v1/index.mdx | 68 --- packages/docs/api-reference/v1/risks.mdx | 369 ---------------- packages/docs/docs.json | 7 +- 4 files changed, 1 insertion(+), 880 deletions(-) delete mode 100644 packages/docs/api-reference/v1/employees.mdx delete mode 100644 packages/docs/api-reference/v1/index.mdx delete mode 100644 packages/docs/api-reference/v1/risks.mdx diff --git a/packages/docs/api-reference/v1/employees.mdx b/packages/docs/api-reference/v1/employees.mdx deleted file mode 100644 index a02226233..000000000 --- a/packages/docs/api-reference/v1/employees.mdx +++ /dev/null @@ -1,437 +0,0 @@ ---- -title: 'Employees' -description: 'Endpoints for managing organization employees' ---- - -# Employees - -The Employees endpoints allow you to manage employees within your organization. You can list employees, create new employees, and delete existing employees. - -## Base URL - -``` -https://app.trycomp.ai/v1/people -``` - -or, if you self-host - -``` -https://app.yourdomain.com/v1/people -``` - -## Authentication - -All API endpoints require authentication using an API key. You can pass the API key using one of the following methods: - -- In the `Authorization` header as a Bearer token: `Authorization: Bearer {api_key}` -- In the `X-API-Key` header: `X-API-Key: {api_key}` - -## Endpoints - -The following endpoints are available for managing employees: - -- `GET /api/v1/people` - List all employees with optional filtering -- `GET /api/v1/people/:id` - Get a single employee by ID -- `POST /api/v1/people` - Create a new employee -- `DELETE /api/v1/people/:id` - Delete an employee by ID - -### List Employees - - - Retrieves employees from your organization with optional filtering. - - -#### Query Parameters - - - Filter employees by active status. If not provided, all employees are returned. - - - - Filter employees by department. Must be a valid department value. - - - - Search employees by name or email. Performs a case-insensitive search. - - -#### Response - - - Indicates if the request was successful. - - - - Array of employee objects, each containing: - - - - Unique identifier for the employee. - - - Full name of the employee. - - - Email address of the employee. - - - Department the employee belongs to. - - - Whether the employee is active. - - - External identifier for the employee, if any. - - - ISO 8601 timestamp of when the employee was created. - - - ISO 8601 timestamp of when the employee was last updated. - - - - -#### Error Responses - - - Will be `false` when an error occurs. - - - - Error message describing what went wrong. - - - - Detailed validation errors, if applicable. - - -#### Example Request - -```bash -curl -X GET "https://app.trycomp.ai/api/v1/people?active=true&department=engineering&search=john" \ - -H "Authorization: Bearer YOUR_API_KEY" -``` - -#### Example Response - -```json -{ - "success": true, - "data": [ - { - "id": "clg3a4x6y000789ajdg7l8e9f", - "name": "John Doe", - "email": "john.doe@example.com", - "department": "engineering", - "isActive": true, - "externalEmployeeId": "EMP-123", - "createdAt": "2023-01-15T00:00:00.000Z", - "updatedAt": "2023-06-01T12:34:56.789Z" - } - ] -} -``` - -### Get Employee - - - Retrieves a single employee by ID. - - -#### Path Parameters - - - The unique identifier of the employee to retrieve. - - -#### Response - - - Indicates if the request was successful. - - - - The employee object. - - - - Unique identifier for the employee. - - - Full name of the employee. - - - Email address of the employee. - - - Department the employee belongs to. - - - Whether the employee is active. - - - External identifier for the employee, if any. - - - ISO 8601 timestamp of when the employee was created. - - - ISO 8601 timestamp of when the employee was last updated. - - - - -#### Error Responses - - - Will be `false` when an error occurs. - - - - Error message describing what went wrong. - - -#### Example Request - -```bash -curl -X GET "https://app.trycomp.ai/api/v1/people/clg3a4x6y000789ajdg7l8e9f" \ - -H "Authorization: Bearer YOUR_API_KEY" -``` - -#### Example Response - -```json -{ - "success": true, - "data": { - "id": "clg3a4x6y000789ajdg7l8e9f", - "name": "John Doe", - "email": "john.doe@example.com", - "department": "engineering", - "isActive": true, - "externalEmployeeId": "EMP-123", - "createdAt": "2023-01-15T00:00:00.000Z", - "updatedAt": "2023-06-01T12:34:56.789Z" - } -} -``` - -#### Example Error Response - -```json -{ - "success": false, - "error": "Employee not found" -} -``` - -### Add Employee - - - Adds a new employee to your organization. - - -#### Request Body - - - Full name of the employee. - - - - Email address of the employee. Must be a valid email format. - - - - Department the employee belongs to. If not provided, defaults to "none". - - - - Whether the employee is active. Defaults to true if not provided. - - - - Optional external identifier for the employee. - - - - Optional user ID to associate with the employee. - - - - Optional link ID to associate with the employee. - - -#### Response - - - Indicates if the request was successful. - - - - The newly created employee object. - - - - Unique identifier for the employee. - - - Full name of the employee. - - - Email address of the employee. - - - Department the employee belongs to. - - - Whether the employee is active. - - - External identifier for the employee, if any. - - - ISO 8601 timestamp of when the employee was created. - - - ISO 8601 timestamp of when the employee was last updated. - - - ID of the organization the employee belongs to. - - - User ID associated with the employee, if any. - - - Link ID associated with the employee, if any. - - - - -#### Error Responses - - - Will be `false` when an error occurs. - - - - Error message describing what went wrong. - - - - Detailed validation errors, if applicable. - - -#### Example Request - -```bash -curl -X POST "https://app.trycomp.ai/api/v1/people" \ - -H "Authorization: Bearer YOUR_API_KEY" \ - -H "Content-Type: application/json" \ - -d '{ - "name": "Jane Smith", - "email": "jane.smith@example.com", - "department": "marketing", - "isActive": true, - "externalEmployeeId": "EMP-456" - }' -``` - -#### Example Response - -```json -{ - "success": true, - "data": { - "id": "clg3a4x6y000101ajdg7l8e9f", - "name": "Jane Smith", - "email": "jane.smith@example.com", - "department": "marketing", - "isActive": true, - "externalEmployeeId": "EMP-456", - "createdAt": "2023-07-15T00:00:00.000Z", - "updatedAt": "2023-07-15T00:00:00.000Z", - "organizationId": "org_123456", - "userId": null, - "linkId": null - } -} -``` - -#### Example Response for Validation Error - -```json -{ - "success": false, - "error": "Validation failed", - "details": { - "name": { - "_errors": ["Name is required"] - }, - "email": { - "_errors": ["Valid email is required"] - } - } -} -``` - -### Delete Employee - - - Deletes an employee from your organization by ID. - - -#### Path Parameters - - - The unique identifier of the employee to delete. - - -#### Response - - - Indicates if the request was successful. - - - - - A success message confirming the employee was deleted. - - - -#### Error Responses - - - Will be `false` when an error occurs. - - - - Error message describing what went wrong. - - -#### Example Request - -```bash -curl -X DELETE "https://app.trycomp.ai/api/v1/people/clg3a4x6y000789ajdg7l8e9f" \ - -H "Authorization: Bearer YOUR_API_KEY" -``` - -#### Example Response - -```json -{ - "success": true, - "data": { - "message": "Employee deleted successfully" - } -} -``` - -#### Example Error Response - -```json -{ - "success": false, - "error": "Employee not found" -} -``` diff --git a/packages/docs/api-reference/v1/index.mdx b/packages/docs/api-reference/v1/index.mdx deleted file mode 100644 index 3bab4a31c..000000000 --- a/packages/docs/api-reference/v1/index.mdx +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: 'Overview' -description: 'Comp AI API v1 Reference' ---- - -# Comp AI API v1 - -Welcome to the Comp AI API v1 reference documentation. This section provides detailed information about our REST API endpoints, including request parameters, response formats, and example code. - -## Authentication - -Most API endpoints require authentication using an API key. You can manage your API keys in the [Settings > API Keys](https://app.trycomp.ai/settings/api-keys) section of the dashboard. - -API keys can be passed in one of two ways: - -- In the `Authorization` header as a Bearer token: `Authorization: Bearer {api_key}` -- In the `X-API-Key` header: `X-API-Key: {api_key}` - -## Base URL - -All API endpoints are relative to: - -``` -https://app.trycomp.ai/api/v1 -``` - -or, if you self-host: - -``` -https://app.yourdomain.com/v1/people -``` - -## Available Endpoints - -The API provides access to the following resources: - -- [Employees](/api-reference/v1/people) - Manage employees in your organization -- [Risks](/api-reference/v1/risks) - Manage risks and their mitigations - -## Response Format - -All API responses follow a consistent JSON format: - -```json -{ - "success": true | false, - "data": {...} | null, // Present on successful responses - "error": "Error message", // Present on error responses - "details": {...} // Optional detailed error information -} -``` - -## Error Codes - -Common error codes you might encounter: - -| Status Code | Description | -| ----------- | -------------------------------------------------------- | -| 400 | Bad Request - Often due to missing or invalid parameters | -| 401 | Unauthorized - Invalid or missing API key | -| 403 | Forbidden - Valid API key but insufficient permissions | -| 404 | Not Found - The requested resource doesn't exist | -| 429 | Too Many Requests - Rate limit exceeded | -| 500 | Internal Server Error - Something went wrong on our end | - -## Need Help? - -If you have questions or need assistance with the API, please contact our support team at [support@trycomp.ai](mailto:hello@trycomp.ai) or join our [Discord community](https://discord.gg/compai). diff --git a/packages/docs/api-reference/v1/risks.mdx b/packages/docs/api-reference/v1/risks.mdx deleted file mode 100644 index c5498b99d..000000000 --- a/packages/docs/api-reference/v1/risks.mdx +++ /dev/null @@ -1,369 +0,0 @@ ---- -title: 'Risks' ---- - -# Risks - -The Risks endpoints allow you to list risks, create new risks, retrieve individual risks, and delete existing risks. Risks represent potential threats to your organization that need to be tracked, assessed, and mitigated. - -## Authentication - -All endpoints require authentication using an API key. You can provide the API key in one of two ways: - -1. **Bearer token** in the `Authorization` header: - -``` -Authorization: Bearer your_api_key -``` - -2. Using the `X-API-Key` header: - -``` -X-API-Key: your_api_key -``` - -## Endpoints - -- `GET /api/v1/risks` - List all risks with optional filtering -- `POST /api/v1/risks` - Create a new risk -- `GET /api/v1/risks/:id` - Get a risk by ID -- `DELETE /api/v1/risks/:id` - Delete a risk by ID - -## List Risks - -``` -GET /api/v1/risks -``` - -Get all risks for the organization associated with the API key. - -### Query Parameters - -| Parameter | Type | Description | -| ---------- | ------ | ---------------------------------------------------------------------------------------- | -| status | string | Filter by risk status. Possible values: `open`, `pending`, `closed`, `archived` | -| category | string | Filter by risk category (e.g., `technology`, `operations`, `regulatory`, etc.) | -| department | string | Filter by department. Possible values: `none`, `admin`, `gov`, `hr`, `it`, `itsm`, `qms` | -| search | string | Search by title or description | - -### Response - -```json -{ - "success": true, - "data": [ - { - "id": "clc123abc456", - "title": "Server vulnerability", - "description": "Outdated software on production servers", - "category": "technology", - "department": "it", - "status": "open", - "probability": 7, - "impact": 8, - "residual_probability": 3, - "residual_impact": 5, - "createdAt": "2023-01-15T12:00:00.000Z", - "updatedAt": "2023-01-16T09:30:00.000Z", - "assigneeId": "u123abc456", - "assignee": { - "id": "u123abc456", - "user": { - "name": "John Doe", - "email": "john.doe@example.com" - } - } - } - // More risks... - ] -} -``` - -### Error Responses - -**Invalid API key (401):** - -```json -{ - "success": false, - "error": "Invalid or missing API key" -} -``` - -**Validation Error (400):** - -```json -{ - "success": false, - "error": "Validation failed", - "details": { - "status": { - "_errors": ["Invalid enum value. Expected 'open' | 'pending' | 'closed' | 'archived'"] - } - } -} -``` - -**Internal Error (500):** - -```json -{ - "success": false, - "error": "Failed to fetch risks" -} -``` - -## Create Risk - -``` -POST /api/v1/risks -``` - -Create a new risk for the organization associated with the API key. - -### Request Body - -| Field | Type | Description | Required | -| -------------------- | ------ | ------------------------------------------------------------------------ | -------- | -| title | string | The title of the risk | Yes | -| description | string | A detailed description of the risk | Yes | -| category | string | The risk category (e.g., `technology`, `operations`, `regulatory`, etc.) | Yes | -| department | string | The department associated with the risk | No | -| status | string | The risk status. Default: `open` | No | -| probability | number | The initial probability score (0-10). Default: 0 | No | -| impact | number | The initial impact score (0-10). Default: 0 | No | -| residual_probability | number | The residual probability score after mitigation (0-10). Default: 0 | No | -| residual_impact | number | The residual impact score after mitigation (0-10). Default: 0 | No | -| assigneeId | string | The ID of the user who owns the risk | No | - -#### Example Request - -```json -{ - "title": "Server vulnerability", - "description": "Outdated software on production servers", - "category": "technology", - "department": "it", - "probability": 7, - "impact": 8 -} -``` - -### Response - -```json -{ - "success": true, - "data": { - "id": "clc123abc456", - "title": "Server vulnerability", - "description": "Outdated software on production servers", - "category": "technology", - "department": "it", - "status": "open", - "probability": 7, - "impact": 8, - "residual_probability": 0, - "residual_impact": 0, - "createdAt": "2023-01-15T12:00:00.000Z", - "updatedAt": "2023-01-15T12:00:00.000Z", - "assigneeId": null, - "organizationId": "org123abc456" - } -} -``` - -### Error Responses - -**Invalid API key (401):** - -```json -{ - "success": false, - "error": "Invalid or missing API key" -} -``` - -**Validation Error (400):** - -```json -{ - "success": false, - "error": "Validation failed", - "details": { - "title": { - "_errors": ["Title is required"] - }, - "category": { - "_errors": ["Invalid enum value"] - } - } -} -``` - -**Internal Error (500):** - -```json -{ - "success": false, - "error": "Failed to create risk" -} -``` - -## Get Risk - -``` -GET /api/v1/risks/:id -``` - -Get a single risk by ID for the organization associated with the API key. - -### Path Parameters - -| Parameter | Type | Description | -| --------- | ------ | ------------------------- | -| id | string | The ID of the risk to get | - -### Response - -```json -{ - "success": true, - "data": { - "id": "clc123abc456", - "title": "Server vulnerability", - "description": "Outdated software on production servers", - "category": "technology", - "department": "it", - "status": "open", - "probability": 7, - "impact": 8, - "residual_probability": 3, - "residual_impact": 5, - "createdAt": "2023-01-15T12:00:00.000Z", - "updatedAt": "2023-01-16T09:30:00.000Z", - "assigneeId": "u123abc456", - "assignee": { - "id": "u123abc456", - "user": { - "name": "John Doe", - "email": "john.doe@example.com" - } - }, - "treatmentStrategy": { - "id": "trt123abc456", - "type": "mitigate", - "description": "Update software and implement regular updates", - "createdAt": "2023-01-15T14:00:00.000Z", - "updatedAt": "2023-01-15T14:00:00.000Z" - }, - "mitigationTasks": [ - { - "id": "tsk123abc456", - "title": "Update server software", - "description": "Update all production servers to the latest stable version", - "status": "open", - "dueDate": "2023-02-15T00:00:00.000Z", - "completedAt": null, - "createdAt": "2023-01-15T14:10:00.000Z", - "updatedAt": "2023-01-15T14:10:00.000Z", - "assigneeId": "u123abc456" - }, - { - "id": "tsk789xyz123", - "title": "Implement automatic updates", - "description": "Set up automatic security updates for all servers", - "status": "open", - "dueDate": "2023-03-01T00:00:00.000Z", - "completedAt": null, - "createdAt": "2023-01-15T14:15:00.000Z", - "updatedAt": "2023-01-15T14:15:00.000Z", - "assigneeId": "u123abc456" - } - ] - } -} -``` - -### Error Responses - -**Invalid API key (401):** - -```json -{ - "success": false, - "error": "Invalid or missing API key" -} -``` - -**Risk Not Found (404):** - -```json -{ - "success": false, - "error": "Risk not found" -} -``` - -**Internal Error (500):** - -```json -{ - "success": false, - "error": "Failed to fetch risk" -} -``` - -## Delete Risk - -``` -DELETE /api/v1/risks/:id -``` - -Delete a risk by ID for the organization associated with the API key. - -### Path Parameters - -| Parameter | Type | Description | -| --------- | ------ | ---------------------------- | -| id | string | The ID of the risk to delete | - -### Response - -```json -{ - "success": true, - "data": { - "message": "Risk deleted successfully" - } -} -``` - -### Error Responses - -**Invalid API key (401):** - -```json -{ - "success": false, - "error": "Invalid or missing API key" -} -``` - -**Risk Not Found (404):** - -```json -{ - "success": false, - "error": "Risk not found" -} -``` - -**Internal Error (500):** - -```json -{ - "success": false, - "error": "Failed to delete risk" -} -``` diff --git a/packages/docs/docs.json b/packages/docs/docs.json index 44ca14b3b..3340d78ef 100644 --- a/packages/docs/docs.json +++ b/packages/docs/docs.json @@ -47,12 +47,7 @@ }, { "tab": "API", - "groups": [ - { - "group": "API Reference", - "pages": ["api-reference/v1/index", "api-reference/v1/people"] - } - ] + "openapi": "https://api.trycomp.ai/api/docs-json" } ], "global": { From bd8203f22adee2f5d852a984561e84bbf6c49b57 Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Mon, 4 Aug 2025 12:11:01 -0400 Subject: [PATCH 2/3] chore: update @trycompai/db to version 1.3.1 and add HIPAA framework support - Updated the @trycompai/db package version from 1.3.0 to 1.3.1. - Added HIPAA framework support in the Trust Portal settings, including new state management and UI components. - Updated database schema to include 'hipaa' and 'hipaa_status' fields in the Trust model. - Created a migration script for adding HIPAA framework columns to the database. --- apps/app/package.json | 2 +- .../actions/update-trust-portal-frameworks.ts | 6 ++ .../components/TrustPortalSwitch.tsx | 59 +++++++++++++++++-- .../trust-portal/components/logos.tsx | 58 ++++++++++++++++++ .../[orgId]/settings/trust-portal/page.tsx | 4 ++ bun.lock | 4 +- packages/db/package.json | 2 +- .../migration.sql | 3 + packages/db/prisma/schema/trust.prisma | 2 + 9 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 packages/db/prisma/migrations/20250804151544_add_hipaa_framework/migration.sql diff --git a/apps/app/package.json b/apps/app/package.json index 4f6a83534..27f2b9b25 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -46,7 +46,7 @@ "@tiptap/extension-table-row": "^2.22.3", "@trigger.dev/react-hooks": "3.3.17", "@trigger.dev/sdk": "3.3.17", - "@trycompai/db": "^1.3.0", + "@trycompai/db": "^1.3.1", "@types/canvas-confetti": "^1.9.0", "@types/three": "^0.177.0", "@uploadthing/react": "^7.3.0", 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 f898c53af..55934b4b6 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 @@ -10,9 +10,11 @@ interface UpdateTrustPortalFrameworksParams { soc2?: boolean; iso27001?: boolean; gdpr?: boolean; + hipaa?: boolean; soc2Status?: 'started' | 'in_progress' | 'compliant'; iso27001Status?: 'started' | 'in_progress' | 'compliant'; gdprStatus?: 'started' | 'in_progress' | 'compliant'; + hipaaStatus?: 'started' | 'in_progress' | 'compliant'; } export async function updateTrustPortalFrameworks({ @@ -20,9 +22,11 @@ export async function updateTrustPortalFrameworks({ soc2, iso27001, gdpr, + hipaa, soc2Status, iso27001Status, gdprStatus, + hipaaStatus, }: UpdateTrustPortalFrameworksParams) { const session = await auth.api.getSession({ headers: await headers(), @@ -50,9 +54,11 @@ export async function updateTrustPortalFrameworks({ soc2: soc2 ?? trustPortal.soc2, iso27001: iso27001 ?? trustPortal.iso27001, gdpr: gdpr ?? trustPortal.gdpr, + hipaa: hipaa ?? trustPortal.hipaa, soc2_status: soc2Status ?? trustPortal.soc2_status, iso27001_status: iso27001Status ?? trustPortal.iso27001_status, gdpr_status: gdprStatus ?? trustPortal.gdpr_status, + hipaa_status: hipaaStatus ?? trustPortal.hipaa_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 6f69379b5..e0e55fff2 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,7 +17,7 @@ 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, ISO27001, SOC2 } from './logos'; +import { GDPR, HIPAA, ISO27001, SOC2 } from './logos'; const trustPortalSwitchSchema = z.object({ enabled: z.boolean(), @@ -26,9 +26,11 @@ const trustPortalSwitchSchema = z.object({ soc2: z.boolean(), iso27001: z.boolean(), gdpr: z.boolean(), + hipaa: z.boolean(), soc2Status: 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']), }); export function TrustPortalSwitch({ @@ -41,9 +43,11 @@ export function TrustPortalSwitch({ soc2, iso27001, gdpr, + hipaa, soc2Status, iso27001Status, gdprStatus, + hipaaStatus, friendlyUrl, }: { enabled: boolean; @@ -55,9 +59,11 @@ export function TrustPortalSwitch({ soc2: boolean; iso27001: boolean; gdpr: boolean; + hipaa: boolean; soc2Status: 'started' | 'in_progress' | 'compliant'; iso27001Status: 'started' | 'in_progress' | 'compliant'; gdprStatus: 'started' | 'in_progress' | 'compliant'; + hipaaStatus: 'started' | 'in_progress' | 'compliant'; friendlyUrl: string | null; }) { const trustPortalSwitch = useAction(trustPortalSwitchAction, { @@ -79,9 +85,11 @@ export function TrustPortalSwitch({ soc2: soc2 ?? false, iso27001: iso27001 ?? false, gdpr: gdpr ?? false, + hipaa: hipaa ?? false, soc2Status: soc2Status ?? 'started', iso27001Status: iso27001Status ?? 'started', gdprStatus: gdprStatus ?? 'started', + hipaaStatus: hipaaStatus ?? 'started', friendlyUrl: friendlyUrl ?? undefined, }, }); @@ -393,6 +401,35 @@ export function TrustPortalSwitch({ } }} /> + {/* HIPAA */} + { + try { + await updateTrustPortalFrameworks({ + orgId, + hipaaStatus: value as 'started' | 'in_progress' | 'compliant', + }); + toast.success('HIPAA status updated'); + } catch (error) { + toast.error('Failed to update HIPAA status'); + } + }} + onToggle={async (checked) => { + try { + await updateTrustPortalFrameworks({ + orgId, + hipaa: checked, + }); + toast.success('HIPAA status updated'); + } catch (error) { + toast.error('Failed to update HIPAA status'); + } + }} + /> @@ -422,12 +459,22 @@ function ComplianceFramework({ }) { const logo = title === 'SOC 2' ? ( - +
+ +
) : title === 'ISO 27001' ? ( - - ) : ( - - ); +
+ +
+ ) : title === 'GDPR' ? ( +
+ +
+ ) : title === 'HIPAA' ? ( +
+ +
+ ) : 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 f72356bf9..f9ed8cc66 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 @@ -127,3 +127,61 @@ export const GDPR = (props: React.SVGProps) => ( /> ); + +export const HIPAA = (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 8bf074bf0..1105435ec 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 @@ -26,9 +26,11 @@ export default async function TrustPortalSettings({ soc2={trustPortal?.soc2 ?? false} iso27001={trustPortal?.iso27001 ?? false} gdpr={trustPortal?.gdpr ?? false} + hipaa={trustPortal?.hipaa ?? false} soc2Status={trustPortal?.soc2Status ?? 'started'} iso27001Status={trustPortal?.iso27001Status ?? 'started'} gdprStatus={trustPortal?.gdprStatus ?? 'started'} + hipaaStatus={trustPortal?.hipaaStatus ?? 'started'} friendlyUrl={trustPortal?.friendlyUrl ?? null} /> { soc2: trustPortal?.soc2, iso27001: trustPortal?.iso27001, gdpr: trustPortal?.gdpr, + hipaa: trustPortal?.hipaa, soc2Status: trustPortal?.soc2_status, iso27001Status: trustPortal?.iso27001_status, gdprStatus: trustPortal?.gdpr_status, + hipaaStatus: trustPortal?.hipaa_status, isVercelDomain: trustPortal?.isVercelDomain, vercelVerification: trustPortal?.vercelVerification, friendlyUrl: trustPortal?.friendlyUrl, diff --git a/bun.lock b/bun.lock index 2fa340951..4fa90630e 100644 --- a/bun.lock +++ b/bun.lock @@ -145,7 +145,7 @@ "@tiptap/extension-table-row": "^2.22.3", "@trigger.dev/react-hooks": "3.3.17", "@trigger.dev/sdk": "3.3.17", - "@trycompai/db": "^1.3.0", + "@trycompai/db": "^1.3.1", "@types/canvas-confetti": "^1.9.0", "@types/three": "^0.177.0", "@uploadthing/react": "^7.3.0", @@ -1775,7 +1775,7 @@ "@trycompai/analytics": ["@trycompai/analytics@workspace:packages/analytics"], - "@trycompai/db": ["@trycompai/db@1.3.0", "", { "dependencies": { "@prisma/client": "^6.13.0", "dotenv": "^16.4.5" } }, "sha512-yj6jLYjnB1zGUk4tef+2tnDBYEgtoLT9sMqtxYcYEztUZuv3WWr/zbtj1yNNxaL/6aPy1OFjkcc3qjf/9iJ9vw=="], + "@trycompai/db": ["@trycompai/db@1.3.1", "", { "dependencies": { "@prisma/client": "^6.13.0", "dotenv": "^16.4.5" } }, "sha512-OpGOrkGC1a/g5kLZmXTaAAC2dWma/kaBPSXUf875zGLufK3vbsyLGVoNGD5PPPDk7KDiwMx9FjR5h3/qrFUZQg=="], "@trycompai/email": ["@trycompai/email@workspace:packages/email"], diff --git a/packages/db/package.json b/packages/db/package.json index 6a8134993..aa7b895db 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.0", + "version": "1.3.1", "dependencies": { "@prisma/client": "^6.13.0", "dotenv": "^16.4.5" diff --git a/packages/db/prisma/migrations/20250804151544_add_hipaa_framework/migration.sql b/packages/db/prisma/migrations/20250804151544_add_hipaa_framework/migration.sql new file mode 100644 index 000000000..ac2f2d2f0 --- /dev/null +++ b/packages/db/prisma/migrations/20250804151544_add_hipaa_framework/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "public"."Trust" ADD COLUMN "hipaa" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "hipaa_status" "public"."FrameworkStatus" NOT NULL DEFAULT 'started'; diff --git a/packages/db/prisma/schema/trust.prisma b/packages/db/prisma/schema/trust.prisma index 2da5b3460..150f23c1b 100644 --- a/packages/db/prisma/schema/trust.prisma +++ b/packages/db/prisma/schema/trust.prisma @@ -14,10 +14,12 @@ model Trust { soc2 Boolean @default(false) iso27001 Boolean @default(false) gdpr Boolean @default(false) + hipaa Boolean @default(false) soc2_status FrameworkStatus @default(started) iso27001_status FrameworkStatus @default(started) gdpr_status FrameworkStatus @default(started) + hipaa_status FrameworkStatus @default(started) @@id([status, organizationId]) @@unique([organizationId]) From 5f282018f3c9bee323a92503ff6a20406306a5ec Mon Sep 17 00:00:00 2001 From: Mariano Fuentes Date: Mon, 4 Aug 2025 12:58:34 -0400 Subject: [PATCH 3/3] fix: prevent infinite loop in TrustPortalSwitch by updating useEffect dependencies - Removed trustPortalSwitch from the dependencies array to avoid an infinite loop. - Adjusted dependencies in another useEffect to streamline checks for friendly URL availability. - Ensured proper handling of state updates related to friendly URL checks. --- .../settings/trust-portal/components/TrustPortalSwitch.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 e0e55fff2..0564ba678 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 @@ -98,7 +98,7 @@ export function TrustPortalSwitch({ async (data: z.infer) => { await trustPortalSwitch.execute(data); }, - [trustPortalSwitch], + [], // Remove trustPortalSwitch from dependencies to prevent infinite loop ); const portalUrl = domainVerified ? `https://${domain}` : `https://trust.inc/${slug}`; @@ -156,7 +156,7 @@ export function TrustPortalSwitch({ } setFriendlyUrlStatus('checking'); checkFriendlyUrl.execute({ friendlyUrl: debouncedFriendlyUrl, orgId }); - }, [debouncedFriendlyUrl, orgId, friendlyUrl, checkFriendlyUrl]); + }, [debouncedFriendlyUrl, orgId, friendlyUrl]); useEffect(() => { if (checkFriendlyUrl.status === 'executing') return; if (checkFriendlyUrl.result?.data?.isAvailable === true) { @@ -169,7 +169,7 @@ export function TrustPortalSwitch({ } else if (checkFriendlyUrl.result?.data?.isAvailable === false) { setFriendlyUrlStatus('unavailable'); } - }, [checkFriendlyUrl.status, checkFriendlyUrl.result, autoSave, form, debouncedFriendlyUrl]); + }, [checkFriendlyUrl.status, checkFriendlyUrl.result, debouncedFriendlyUrl, form, autoSave]); const handleFriendlyUrlBlur = useCallback( (e: React.FocusEvent) => {