Compare commits

..

18 Commits

Author SHA1 Message Date
Piyush Gupta
fa7f52a72b Merge branch 'main' of https://github.com/formbricks/formbricks into feat/heic 2025-02-20 09:16:47 +05:30
Matti Nannt
7d4409e2b4 docs: add monitoring page to self-hosting (#4774) 2025-02-20 00:55:19 +01:00
mintlify[bot]
64a385b835 docs: Tweak Docs for Cloud Integrations (#4754)
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
2025-02-19 18:41:09 +00:00
Dhruwang Jariwala
ee2573d128 docs: coding standards (#4770)
Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
Co-authored-by: Johannes <johannes@formbricks.com>
Co-authored-by: Matti Nannt <mail@matthiasnannt.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-02-19 18:45:13 +01:00
Piyush Gupta
d082e7c44d docs: saml-sso (#4772)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
2025-02-19 18:39:42 +01:00
Piyush Gupta
5306aecec4 Merge branch 'feat/heic' of https://github.com/paribesh01/formbricks into feat/heic 2025-02-18 18:24:57 +05:30
Piyush Gupta
cdc332d44e fix: import 2025-02-18 18:24:23 +05:30
Paribesh Nepal
2e58f337b0 Merge branch 'main' into feat/heic 2025-02-18 16:56:28 +05:30
Piyush Gupta
1390b071ea fix: action -> actions 2025-02-18 16:23:57 +05:30
Piyush Gupta
d5a4a4736b Merge branch 'main' of https://github.com/formbricks/formbricks into feat/heic 2025-02-18 15:45:08 +05:30
Piyush Gupta
57725783e8 fix: server action 2025-02-18 15:27:24 +05:30
Matti Nannt
8f5527ac34 Merge branch 'main' into feat/heic 2025-02-17 12:07:32 +01:00
Paribesh01
3632c9ec94 fix: minor changes 2025-02-07 02:11:48 +05:30
Paribesh01
1acf334ad3 fix: file size 2025-02-07 02:04:24 +05:30
Paribesh01
a526bb08be fix: minor change 2025-02-07 01:55:10 +05:30
Paribesh01
787cf2d56f fix: minor changes 2025-02-07 01:06:24 +05:30
Paribesh01
12b7dbd567 fix: minor changes 2025-02-07 01:02:08 +05:30
Paribesh01
423466d30a feat: Support HEIC format for images 2025-02-07 00:43:23 +05:30
62 changed files with 1964 additions and 258 deletions

View File

@@ -138,7 +138,7 @@ export const EditLogo = ({ project, environmentId, isReadOnly }: EditLogoProps)
) : (
<FileInput
id="logo-input"
allowedFileExtensions={["png", "jpeg", "jpg", "webp"]}
allowedFileExtensions={["png", "jpeg", "jpg", "webp", "heic"]}
environmentId={environmentId}
onFileUpload={(files: string[]) => {
setLogoUrl(files[0]);
@@ -151,7 +151,7 @@ export const EditLogo = ({ project, environmentId, isReadOnly }: EditLogoProps)
<Input
ref={fileInputRef}
type="file"
accept="image/jpeg, image/png, image/webp"
accept="image/jpeg, image/png, image/webp, image/heic"
className="hidden"
disabled={isReadOnly}
onChange={handleFileChange}

View File

@@ -308,7 +308,7 @@ export const QuestionFormInput = ({
{showImageUploader && id === "headline" && (
<FileInput
id="question-image"
allowedFileExtensions={["png", "jpeg", "jpg", "webp"]}
allowedFileExtensions={["png", "jpeg", "jpg", "webp", "heic"]}
environmentId={localSurvey.environmentId}
onFileUpload={(url: string[] | undefined, fileType: "image" | "video") => {
if (url) {

View File

@@ -114,7 +114,7 @@ export const EditWelcomeCard = ({
<div className="mt-3 flex w-full items-center justify-center">
<FileInput
id="welcome-card-image"
allowedFileExtensions={["png", "jpeg", "jpg", "webp"]}
allowedFileExtensions={["png", "jpeg", "jpg", "webp", "heic"]}
environmentId={environmentId}
onFileUpload={(url: string[]) => {
updateSurvey({ fileUrl: url[0] });

View File

@@ -16,7 +16,7 @@ export const UploadImageSurveyBg = ({
<div className="flex w-full items-center justify-center">
<FileInput
id="survey-bg-file-input"
allowedFileExtensions={["png", "jpeg", "jpg", "webp"]}
allowedFileExtensions={["png", "jpeg", "jpg", "webp", "heic"]}
environmentId={environmentId}
onFileUpload={(url: string[]) => {
if (url.length > 0) {

View File

@@ -133,7 +133,7 @@ export const PictureSelectionForm = ({
<div className="mt-3 flex w-full items-center justify-center">
<FileInput
id="choices-file-input"
allowedFileExtensions={["png", "jpeg", "jpg", "webp"]}
allowedFileExtensions={["png", "jpeg", "jpg", "webp", "heic"]}
environmentId={environmentId}
onFileUpload={handleFileInputChanges}
fileUrl={question?.choices?.map((choice) => choice.imageUrl)}

View File

@@ -68,7 +68,7 @@ export const FileInput = ({
toast.error(t("common.only_one_file_allowed"));
}
const allowedFiles = getAllowedFiles(files, allowedFileExtensions, maxSizeInMB);
const allowedFiles = await getAllowedFiles(files, allowedFileExtensions, maxSizeInMB);
if (allowedFiles.length === 0) {
return;
@@ -137,7 +137,7 @@ export const FileInput = ({
};
const handleUploadMore = async (files: File[]) => {
const allowedFiles = getAllowedFiles(files, allowedFileExtensions, maxSizeInMB);
const allowedFiles = await getAllowedFiles(files, allowedFileExtensions, maxSizeInMB);
if (allowedFiles.length === 0) {
return;
}

View File

@@ -0,0 +1,29 @@
"use server";
import { authenticatedActionClient } from "@/lib/utils/action-client";
import { z } from "zod";
const ZConvertHeicToJpegInput = z.object({
file: z.instanceof(File),
});
export const convertHeicToJpegAction = authenticatedActionClient
.schema(ZConvertHeicToJpegInput)
.action(async ({ parsedInput }) => {
if (!parsedInput.file || !parsedInput.file.name.endsWith(".heic")) return parsedInput.file;
const convert = (await import("heic-convert")).default;
const arrayBuffer = await parsedInput.file.arrayBuffer();
const nodeBuffer = Buffer.from(arrayBuffer) as unknown as ArrayBufferLike;
const convertedBuffer = await convert({
buffer: nodeBuffer,
format: "JPEG",
quality: 0.9,
});
return new File([convertedBuffer], parsedInput.file.name.replace(/\.heic$/, ".jpg"), {
type: "image/jpeg",
});
});

View File

@@ -2,6 +2,7 @@
import { toast } from "react-hot-toast";
import { TAllowedFileExtension } from "@formbricks/types/common";
import { convertHeicToJpegAction } from "./actions";
export const uploadFile = async (
file: File | Blob,
@@ -15,8 +16,6 @@ export const uploadFile = async (
const fileBuffer = await file.arrayBuffer();
// check the file size
const bufferBytes = fileBuffer.byteLength;
const bufferKB = bufferBytes / 1024;
@@ -74,7 +73,6 @@ export const uploadFile = async (
});
}
// Add the actual file to be uploaded
formData.append("file", file);
const uploadResponse = await fetch(signedUrl, {
@@ -96,34 +94,63 @@ export const uploadFile = async (
}
};
export const getAllowedFiles = (
const isFileSizeExceed = (fileSizeInMB: number, maxSizeInMB?: number) => {
if (maxSizeInMB && fileSizeInMB > maxSizeInMB) {
return true;
}
return false;
};
export const getAllowedFiles = async (
files: File[],
allowedFileExtensions: string[],
maxSizeInMB?: number
): File[] => {
): Promise<File[]> => {
const sizeExceedFiles: string[] = [];
const unsupportedExtensionFiles: string[] = [];
const convertedFiles: File[] = [];
const allowedFiles = files.filter((file) => {
for (const file of files) {
if (!file || !file.type) {
return false;
continue;
}
const extension = file.name.split(".").pop();
const fileSizeInMB = file.size / 1000000; // Kb -> Mb
const extension = file.name.split(".").pop()?.toLowerCase();
const fileSizeInMB = file.size / 1000000;
if (!allowedFileExtensions.includes(extension as TAllowedFileExtension)) {
unsupportedExtensionFiles.push(file.name);
return false; // Exclude file if extension not allowed
} else if (maxSizeInMB && fileSizeInMB > maxSizeInMB) {
sizeExceedFiles.push(file.name);
return false; // Exclude files larger than the maximum size
continue;
}
return true;
});
if (isFileSizeExceed(fileSizeInMB, maxSizeInMB)) {
sizeExceedFiles.push(file.name);
continue;
}
if (extension === "heic") {
const convertedFileResponse = await convertHeicToJpegAction({ file });
if (!convertedFileResponse?.data) {
unsupportedExtensionFiles.push(file.name);
continue;
} else {
const convertedFileSizeInMB = convertedFileResponse.data.size / 1000000;
if (isFileSizeExceed(convertedFileSizeInMB, maxSizeInMB)) {
sizeExceedFiles.push(file.name);
continue;
}
const convertedFile = new File([convertedFileResponse.data], file.name.replace(/\.heic$/, ".jpg"), {
type: "image/jpeg",
});
convertedFiles.push(convertedFile);
continue;
}
}
convertedFiles.push(file);
}
// Constructing toast messages based on the issues found
let toastMessage = "";
if (sizeExceedFiles.length > 0) {
toastMessage += `Files exceeding size limit (${maxSizeInMB} MB): ${sizeExceedFiles.join(", ")}. `;
@@ -134,7 +161,7 @@ export const getAllowedFiles = (
if (toastMessage) {
toast.error(toastMessage);
}
return allowedFiles;
return convertedFiles;
};
export const checkForYoutubePrivacyMode = (url: string): boolean => {

View File

@@ -83,6 +83,7 @@
"file-loader": "6.2.0",
"framer-motion": "11.15.0",
"googleapis": "144.0.0",
"heic-convert": "2.1.0",
"https-proxy-agent": "7.0.6",
"jiti": "2.4.1",
"jsonwebtoken": "9.0.2",
@@ -129,6 +130,7 @@
"@formbricks/eslint-config": "workspace:*",
"@neshca/cache-handler": "1.9.0",
"@types/bcryptjs": "2.4.6",
"@types/heic-convert": "2.1.0",
"@types/lodash": "4.17.13",
"@types/markdown-it": "14.1.2",
"@types/nodemailer": "6.4.17",

View File

@@ -1,32 +1,38 @@
# Mintlify Starter Kit
# Formbricks Documentation
Click on `Use this template` to copy the Mintlify starter kit. The starter kit contains examples including
This documentation is built using Mintlify. Here's how to run it locally and contribute.
- Guide pages
- Navigation
- Customizations
- API Reference pages
- Use of popular components
## Local Development
### Development
1. Install the [Mintlify CLI](https://www.npmjs.com/package/mintlify):
Install the [Mintlify CLI](https://www.npmjs.com/package/mintlify) to preview the documentation changes locally. To install, use the following command
```
```bash
npm i -g mintlify
```
Run the following command at the root of your documentation (where mint.json is)
2. Clone the Formbricks repository and navigate to the docs folder:
```bash
git clone https://github.com/formbricks/formbricks.git
cd formbricks/docs
```
3. Run the documentation locally:
```bash
mintlify dev
```
### Publishing Changes
The documentation will be available at `http://localhost:3000`.
Install our Github App to auto propagate changes from your repo to your deployment. Changes will be deployed to production automatically after pushing to the default branch. Find the link to install on your dashboard.
### Contributing
#### Troubleshooting
1. Create a new branch for your changes
2. Make your documentation updates
3. Submit a pull request to the main repository
- Mintlify dev isn't running - Run `mintlify install` it'll re-install dependencies.
- Page loads as a 404 - Make sure you are running in a folder with `mint.json`
### Troubleshooting
- If Mintlify dev isn't running, try `mintlify install` to reinstall dependencies
- If a page loads as a 404, ensure you're in the `docs` folder with the `mint.json` file
- For other issues, please check our [Contributing Guidelines](./CONTRIBUTING.md)

View File

@@ -1,5 +1,5 @@
---
title: "Contributing to Formbricks 🤗"
title: "Contribute to Formbricks"
description: "How to contribute to Formbricks"
icon: "code"
---

View File

@@ -0,0 +1,76 @@
---
title: "How to setup SAML with Identity Providers"
---
### SAML Registration with Identity Providers
This guide explains the settings you need to use to configure SAML with your Identity Provider. Once configured, obtain an XML metadata file and upload it on your Formbricks instance.
> **Note:** Please do not add a trailing slash at the end of the URLs. Create them exactly as shown below.
**Assertion consumer service URL / Single Sign-On URL / Destination URL:** https://app.formbricks.com/api/auth/saml/callback
**Entity ID / Identifier / Audience URI / Audience Restriction:** [https://saml.formbricks.com](https://saml.formbricks.com)
**Response:** Signed
**Assertion Signature:** Signed
**Signature Algorithm:** RSA-SHA256
**Assertion Encryption:** Unencrypted
**Mapping Attributes / Attribute Statements:**
- http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier -> id
- http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress -> email
- http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname -> firstName
- http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname -> lastName
### SAML With Okta
<Steps>
<Step title="Create an application with your OIDC provider">
For example, in Okta, once you create an account, you can click on Applications on the sidebar menu:
<img src="/images/development/guides/auth-and-provision/okta/okta-applications.webp" />
</Step>
<Step title="Click on Create App Integration">
<img src="/images/development/guides/auth-and-provision/okta/create-app-integration.webp" />
</Step>
<Step title="Select SAML 2.0 in the modal form, and click Next">
<img src="/images/development/guides/auth-and-provision/okta/select-saml-2.0.webp" />
</Step>
<Step title="Fill the general settings as shown and click Next">
<img src="/images/development/guides/auth-and-provision/okta/general-settings.webp" />
</Step>
<Step title="Fill the fields mapping as shown and click Next">
<img src="/images/development/guides/auth-and-provision/okta/fields-mapping.webp" />
</Step>
<Step title="Enter the SAML Integration Settings as shown and click Next">
<img src="/images/development/guides/auth-and-provision/okta/saml-integration-settings.webp" />
</Step>
<Step title="Check the internal app checkbox and click Finish">
<img src="/images/development/guides/auth-and-provision/okta/internal-app.webp" />
</Step>
<Step title="Check that the app is created successfully">
<img src="/images/development/guides/auth-and-provision/okta/app-created.webp" />
</Step>
<Step title="Click on the app and head over to the Assignments tab">
<img src="/images/development/guides/auth-and-provision/okta/assignments-tab.webp" />
</Step>
<Step title="Click on Assign button and select Assign to People">
<img src="/images/development/guides/auth-and-provision/okta/assign-to-people.webp" />
</Step>
<Step title="Select the users you want to assign the app to and click Assign">
<img src="/images/development/guides/auth-and-provision/okta/select-users.webp" />
</Step>
<Step title="Head over to the Sign On tab and scroll to the bottom to get the metadata, click on the Actions button">
<img src="/images/development/guides/auth-and-provision/okta/actions-button.webp" />
</Step>
<Step title="Click on View IdP metadata">
<img src="/images/development/guides/auth-and-provision/okta/view-idp-metadata.webp" />
</Step>
<Step title="Copy the metadata and paste it in the Formbricks SAML configuration"></Step>
</Steps>
That's it. Now when you try to login with SSO, your application on Okta will handle the authentication.

View File

@@ -1,6 +1,6 @@
---
title: Development
description: Learn how to setup formbricks locally and develop on it
title: Overview
description: Learn how to setup formbricks locally and build custom integrations and services.
icon: "code"
---

View File

@@ -0,0 +1,257 @@
---
title: File and Directory Org.
description: This document outlines the structure and organization of files and directories in the Formbricks codebase, providing guidelines for maintaining consistency and clarity across the project.
icon: folder-tree
---
## Project Structure Overview
The Formbricks codebase follows a monorepo structure using pnpm workspaces, with two main directories:
* `apps/` - Contains full applications
* `packages/` - Contains shared libraries and utilities
## Apps Directory
The `apps/` directory contains complete applications:
### apps/web/
* Main Formbricks web application (Next.js)
* Primary application with full feature set
* Uses App Router architecture
* Contains environment-specific settings and configurations
### apps/demo/
* Demo application (Next.js)
* Showcases Formbricks in-product surveying functionality
* Used for testing and demonstration purposes
### apps/demo-react-native/
* React Native demo app (React Native)
* Demonstrates mobile integration capabilities
* Example implementation for React Native
### apps/storybook/
* Component documentation
* Visual documentation of UI components
* Testing environment for isolated components
## Packages Directory
The `packages/` directory contains shared libraries and utilities:
### packages/js-core/
* Contains core functionality for in-product surveys
* Shared logic between different SDK implementations
* Base classes and utilities
### packages/js/
* JavaScript SDK for browser-based applications
* Used for running surveys on websites and web apps (browser)
* Public NPM package
### packages/react-native/
* React Native SDK
* Used to run surveys in mobile apps built with React Native / Expo
* Includes native platform adaptations
### packages/lib/
* Shared business logic
* Shared utilities and helpers
### packages/types/
* TypeScript type definitions
* Zod schemas for validation
### packages/database/
* Database schemas and migrations
* Prisma schema definitions
* Migration management
### packages/surveys/
* Survey-specific functionality
* Survey rendering logic and UI components
* Survey state management
## Module Organization
### Core Module Structure
Each feature module follows a consistent structure:
```
modules/
└── ee/
├── insights/
│ ├── components/
│ ├── experience/
│ └── types/
└── contacts/
├── segments/
└── components/
```
## Adding New Code
### New Features
When adding new features, follow these guidelines:
1. **Determine Scope**:
* Complete application → `apps/`
* Shared library → `packages/`
* Feature for existing app → appropriate module in `apps/web/modules/`
2. **Module Creation**:
Create a new module with the standard structure:
```
modules/
└── your-feature/
├── components/ # React components
├── lib/ # Business logic
├── types/ # TypeScript types
├── actions.ts # Server actions
└── route.ts # API routes
```
3. **Component Organization**:
* Base UI components → `modules/ui/components/`
* Feature-specific components → `modules/[feature]/components/`
## Best Practices
### Code Organization
* Keep modules focused and single-purpose
* Maintain clear separation between UI and business logic
* Use proper TypeScript interfaces and types
### File Structure
* Group related files in descriptive directories
* Use consistent naming patterns
* Keep files focused and modular
### Module Independence
* Minimize dependencies between modules
* Share common utilities through appropriate packages
* Maintain clear module boundaries
### Documentation
* Document complex logic and APIs as laid out in the [Documentation](/development/standards/practices/documentation) section
* Keep documentation current with code changes
## Testing Organization
### Test File Location
* Test files should be located alongside the code they test
* Use `.test.ts` or `.spec.ts` suffix for test files
* Example: `user-service.test.ts` for `user-service.ts`
### Test Directory Structure
```
feature/
├── tests/ # Test directory (if grouping tests)
├── components/ # Feature components
└── lib/ # Business logic
```
## Configuration Files
### Root Level Configuration
* `.eslintrc.js` - ESLint configuration
* `tsconfig.json` - TypeScript configuration
* `package.json` - Package metadata and scripts
* `.env` - Environment variables
### Package Level Configuration
Each package maintains its own configuration files:
* `package.json` - Package-specific dependencies and scripts
* `tsconfig.json` - Package-specific TypeScript settings
* `.eslintrc.js` - Package-specific linting rules
## Version Control
### Git Organization
* `.gitignore` - Specifies ignored files and directories
* `.github/` - GitHub specific configurations and workflows
* `CHANGELOG.md` - Documents version changes
* `LICENSE` - License information
## Conclusion
Following these organizational patterns ensures:
* Consistent code structure across the project
* Easy navigation and maintenance
* Clear separation of concerns
* Scalable architecture for future growth
Remember to maintain these patterns when adding new code to keep the codebase organized and maintainable.

View File

@@ -0,0 +1,102 @@
---
title: Modules & Components
description: In this document we outline the best practices for organizing modules and components across the codebase. Clear separation of concerns between modules (which encompass business logic and domain-specific functionality) and components (reusable UI elements and building blocks) promotes clarity, scalability, and maintainability.
icon: boxes-stacked
---
## Introduction
Our codebase follows a modular architecture with two primary organizational units:
1. **UI Components**: Reusable components in the `modules/ui/components` directory
2. **Feature Modules**: Domain-specific functionality organized by feature in the `modules` directory
## Module Organization
### Core Module Structure
Modules are organized by feature and can be found in the `modules` directory. Each module typically includes:
```
modules/
└── feature-name/
├── components/ # Feature-specific components
├── lib/ # Business logic and utilities
├── types/ # TypeScript types
├── actions.ts # Server actions
└── route.ts # API routes (if needed)
```
### Enterprise Edition (EE) Modules
Enterprise features are organized in a dedicated `modules/ee` directory:
```
modules/
└── ee/
├── insights/
│ ├── components/
│ ├── experience/
│ └── types/
└── contacts/
├── segments/
└── components/
```
## Component Organization
### UI Component Structure
UI components are centralized in `modules/ui/components` and follow a consistent structure:
```
modules/ui/components/
└── component-name/
├── index.tsx # Main component implementation
├── stories.tsx # Storybook stories
└── components/ # Sub-components (if needed)
```
### Component Types
1. **Base Components**: Fundamental UI elements like Button, Input, Modal
2. **Composite Components**: More complex components that combine base components
3. **Feature-Specific Components**: Components tied to specific features
### Feature Module Example
A feature module with its components and business logic:
```
modules/survey/
├── components/
│ ├── question-form-input/
│ └── template-list/
├── editor/
│ └── components/
├── lib/
│ └── utils.ts
└── types/
└── index.ts
```
## Best Practices
1. **Component Organization**
- Keep components focused and single-purpose
- Use proper TypeScript interfaces for props
- Implement Storybook stories for UI components
2. **Module Structure**
- Organize by feature domain
- Separate business logic from UI components
- Use proper type definitions
3. **Code Sharing**
- Share common utilities through the ui/lib directory
- Maintain clear boundaries between modules
- Use proper imports with aliases (@/modules/...)

View File

@@ -0,0 +1,98 @@
---
title: Naming Conventions
description: This section outlines the guidelines for naming conventions across the codebase, ensuring consistency and clarity in the project.
icon: input-text
---
## Files and Directories
### General Files
- Use lowercase and hyphen-separated names (kebab-case) for files and directories
- ✅ `user-profile.ts`
- ❌ `UserProfile.ts`
- Group related files in directories with descriptive plural names
- ✅ `components`, `services`, `utils`
- ❌ `component`, `util`
### Special Files
- Configuration files should follow framework conventions
- ✅ `next.config.mjs`, `tailwind.config.js`
- Test files should mirror source files with `.test` or `.spec` suffix
- ✅ `user-service.test.ts` for `user-service.ts`
- Database migration files should include timestamp and description
- ✅ `20241017124431_add_documents_and_insights.sql`
## Code Symbols
### Variables and Functions
- Use camelCase for variables and function names
- ✅ `fetchUserData`, `isLoading`, `handleSubmit`
- ❌ `FetchUserData`, `is_loading`
- Boolean variables should use is/has/should prefix
- ✅ `isVerifyEmailEnabled`, `hasPermission`, `shouldDisplay`
- Async functions should use verb prefixes suggesting async
- ✅ `fetchData`, `createUser`, `updateProfile`
### Classes and Types
- Use PascalCase for:
- Classes: `Config`, `Client`, `ResponseAPI`
- Interfaces: `TSurveySummaryResponse`, `ApiConfig`
- Type aliases: `TResponseData`, `TJsTrackProperties`
- Prefix types with T and interfaces with I (when helpful)
- ✅ `TStats`, `TResponseData`, `IApiConfig`
- Enum names should be PascalCase, values in UPPER_SNAKE_CASE
```typescript
enum ProjectFeatureKeys {
FREE = "free",
STARTUP = "startup",
SCALE = "scale"
}
```
### Constants
- Use UPPER_SNAKE_CASE for constant values
- ✅ `API_TIMEOUT`, `MAX_RETRIES`, `CONTAINER_ID`
- Use PascalCase for constant references/objects
- ✅ `ErrorCodes`, `Config`
### Database Models
- Use PascalCase singular form for model names
- ✅ `Survey`, `Response`, `Document`
- Use camelCase for field names
- ✅ `createdAt`, `environmentId`, `isSpam`
- Use snake_case for database column names
- ✅ `created_at`, `updated_at`
### Components
- Use PascalCase for React components and their files
- ✅ `SurveyCard.tsx`, `UserProfile.tsx`
- Component-specific types should be prefixed with component name
- ✅ `SurveyCardProps`, `UserProfileData`
### API and Endpoints
- Use kebab-case for API endpoints
- ✅ `/api/user-profile`, `/api/survey-responses`
- Use camelCase for query parameters
- ✅ `/api/surveys?pageSize=10&sortOrder=desc`
## Schema and Validation
- Prefix Zod schemas with Z
- ✅ `ZSurvey`, `ZDocument`, `ZInsight`
- Use descriptive names for validation schemas
- ✅ `ZUpdateDocumentAction`, `ZGenerateDocumentObjectSchema`
## Error Handling
- Suffix error classes with "Error"
- ✅ `ValidationError`, `DatabaseError`, `AuthenticationError`
- Use descriptive names for error types
- ✅ `SURVEY_NOT_FOUND`, `INVALID_RESPONSE`
## Best Practices
- Keep names descriptive but concise
- Be consistent within each context
- Follow existing patterns in the codebase
- Use full words instead of abbreviations unless widely accepted
- ✅ `configuration` vs ❌ `config` (except in standard terms)
- ✅ `id`, `url` (standard abbreviations are acceptable)
By following these conventions, we maintain consistency and clarity across the codebase, making it more maintainable and easier to understand for all team members.

View File

@@ -0,0 +1,184 @@
---
title: "Code Formatting"
description: "Standards for consistent code formatting across the Formbricks project"
icon: code
---
## Core Configuration
### Prettier Config
Formbricks uses a standardized Prettier configuration defined in `@formbricks/config-prettier`:
```javascript
module.exports = {
bracketSpacing: true,
bracketSameLine: true,
singleQuote: false,
jsxSingleQuote: false,
trailingComma: "es5",
semi: true,
printWidth: 110,
arrowParens: "always",
importOrder: [
// Mocks must be at the top as they contain vi.mock calls
"(.*)/__mocks__/(.*)",
"server-only",
"<THIRD_PARTY_MODULES>",
"^@formbricks/(.*)$",
"^~/(.*)$",
"^[./]",
],
importOrderSeparation: false,
importOrderSortSpecifiers: true,
};
```
Key configurations:
- 110 characters line width
- Double quotes for strings
- ES5 trailing commas
- Always use parentheses for arrow functions
- Strict import ordering
### Import Order
All imports follow a strict ordering:
1. Mocks (for testing)
2. Server-only imports
3. Third-party modules
4. Internal `@formbricks/*` modules
5. Local aliases (`~/*)
6. Relative imports
### TypeScript Config
- Strict TypeScript checking enabled
- Consistent use of `tsconfig.json` extending from `@formbricks/config-typescript`
- Example configuration:
```json
{
"compilerOptions": {
"allowImportingTsExtensions": true,
"isolatedModules": true,
"noEmit": true,
"resolveJsonModule": true,
"strict": true
},
"extends": "@formbricks/config-typescript/js-library.json",
"include": ["src", "package.json"]
}
```
### JSDoc Comments
Required for public APIs and complex functions:
```typescript
/**
* Creates a new user
* @param {string} name - User's name
* @returns {Promise<User>} The created user object
*/
function createUser(name: string): Promise<User> {
// implementation
}
```
### Error Handling
Standardized error handling using the ErrorHandler class:
```typescript
export class ErrorHandler {
private static instance: ErrorHandler | null;
private handleError: (error: unknown) => void;
public customized = false;
public static initialized = false;
private constructor(errorHandler?: (error: unknown) => void) {
if (errorHandler) {
this.handleError = errorHandler;
this.customized = true;
} else {
this.handleError = (error) => {
Logger.getInstance().error(JSON.stringify(error));
};
}
}
// ... additional methods
}
```
## Enforcement Tools
### Pre-commit Hooks
Using Husky and lint-staged for automated checks:
```json
{
"lint-staged": {
"(apps|packages)/**/*.{js,ts,jsx,tsx}": [
"prettier --write",
"eslint --fix"
],
"*.json": [
"prettier --write"
],
"packages/database/schema.prisma": [
"prisma format"
]
}
}
```
### ESLint Configuration
Each package extends from `@formbricks/eslint-config` with specific presets:
- `library.js` for packages
- `next.js` for Next.js applications
- `react.js` for React applications
### Continuous Integration
- Automated formatting checks in CI/CD pipeline
- SonarCloud integration for code quality analysis
- Coverage requirements for tests
## VS Code Integration
### Required Extensions
- `esbenp.prettier-vscode` - Prettier formatting
- `dbaeumer.vscode-eslint` - ESLint integration
- `bradlc.vscode-tailwindcss` - Tailwind CSS support
### Recommended Settings
```json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"typescript.tsdk": "node_modules/typescript/lib"
}
```
## Best Practices
1. **Consistent Formatting**
- Always run `pnpm format` before committing
- Use VS Code's format on save feature
- Follow the established import order
2. **Type Safety**
- Enable strict TypeScript checks
- Use explicit type annotations when necessary
- Avoid using `any` type
3. **Code Organization**
- Keep files focused and modular
- Group related functionality
- Use clear, descriptive names
4. **Documentation**
- Document complex logic
- Use JSDoc for public APIs
- Keep comments current with code changes
These standards ensure consistency across the Formbricks codebase while maintaining high code quality and developer productivity.

View File

@@ -0,0 +1,133 @@
---
title: "Documentation"
description: "Standards for documenting code and features in the Formbricks codebase"
icon: "book"
---
## Overview
At Formbricks, we maintain strict documentation standards to ensure code clarity, maintainability, and ease of use for both internal developers and external contributors.
### Contribute to Documentation
We use Mintlify to maintain our documentation. You can find more information about how to contribute to the documentation in the [README](https://github.com/formbricks/formbricks/blob/main/docs/README.md) file.
## Code Documentation
### Function Documentation
1. **Complex Logic Documentation**
- All functions with complex logic must include JSDoc comments
- Document parameters, return types, and potential side effects
- Example:
```typescript
/**
Creates a new user and initializes their preferences
@param {string} name - User's full name
@param {UserOptions} options - Configuration options for user creation
@returns {Promise<User>} The created user object
@throws {ValidationError} If name is invalid
*/
async function createUser(name: string, options: UserOptions): Promise<User> {
// implementation
}
```
2. **TypeScript Ignore Comments**
- When using `@ts-ignore` or `@ts-expect-error`, always include a comment explaining why
- Example:
```typescript
// @ts-expect-error -- Required for dynamic function calls
void window.formbricks.init(...args);
```
### API Documentation
1. **API Endpoints**
- All new API endpoints must be documented in the OpenAPI specification
- Include request/response schemas, authentication requirements, and examples
- Document both Client API and Management API endpoints
- Place API documentation in the `docs/api-reference` directory
2. **Authentication**
- Clearly specify authentication requirements
- Document API key usage and permissions
- Include error scenarios and handling
### Feature Documentation
- All new features must include a feature documentation file
- Document the feature's purpose, usage, and implementation details
- Include code examples and best practices
## Working with Mintlify
We use Mintlify to write our documentation.
### File Structure
1. **MDX Files**
- All documentation files must use the `.mdx` extension
- Include frontmatter with required metadata:
```markdown
---
title: "Document Title"
description: "Brief description of the content"
icon: "appropriate-icon"
---
```
2. **Navigation**
- Add new pages to the appropriate section in `docs/mint.json`
- Follow the existing navigation structure
- Include proper redirects if URLs change
### Content Guidelines
1. **Writing Style**
- Use clear, concise language
- Break content into logical sections with proper headings
- Include practical examples and code snippets
- Use Mintlify components for notes, warnings, and callouts:
```markdown
<Note>
Important information goes here
</Note>
```
2. **Media and Assets**
- Store images in the appropriate `/images` subdirectory
- Use descriptive alt text for all images
- Optimize images for web delivery
- Use relative paths for internal links
3. **Code Examples**
- Specify the language for all code blocks
- Include comments for complex code snippets
- Use proper indentation and formatting
## Validation
1. **Local Testing**
- Test documentation locally using Mintlify CLI:
```bash
mintlify dev
```
2. **Review Process**
- Documentation changes require peer review
- Verify all links and references work
- Ensure proper formatting and rendering
These documentation requirements ensure that our codebase remains maintainable, accessible, and well-documented for both current and future developers.

View File

@@ -0,0 +1,137 @@
---
title: "Error Handling"
description: "Standards for handling errors across the Formbricks codebase"
icon: "triangle-exclamation"
---
## Overview
At Formbricks, we follow consistent error handling patterns to ensure reliability, debuggability, and maintainability across our codebase. This document outlines our standard approaches to error handling.
## Core Principles
1. **Type Safety**: Use typed errors and results
2. **Meaningful Messages**: Provide clear, actionable error messages
3. **Proper Propagation**: Handle or propagate errors appropriately
4. **Logging**: Ensure errors are properly logged for debugging
5. **Recovery**: Implement graceful fallbacks where possible
## Standard Error Types
We maintain a set of standardized error types for different scenarios:
```typescript
export interface ApiErrorResponse {
code:
| "not_found"
| "gone"
| "bad_request"
| "internal_server_error"
| "unauthorized"
| "method_not_allowed"
| "not_authenticated"
| "forbidden"
| "network_error";
message: string;
status: number;
url: URL;
details?: Record<string, string | string[] | number | number[] | boolean | boolean[]>;
responseMessage?: string;
}
```
## Error Handling Patterns
### API Error Handling
For API endpoints:
```typescript
export const GET = async (request: Request) => {
try {
const authentication = await authenticateRequest(request);
if (!authentication) return responses.notAuthenticatedResponse();
const data = await fetchData(authentication.environmentId!);
return responses.successResponse(data);
} catch (error) {
if (error instanceof DatabaseError) {
return responses.badRequestResponse(error.message);
}
throw error;
}
};
```
### Client-Side Error Handling
For client-side operations:
```typescript
const handleOperation = async () => {
const result = await performAction();
if (!result.ok) {
logger.error(`Operation failed: ${result.error.message}`);
toast.error("Operation failed. Please try again.");
return;
}
// Process successful result
processResult(result.data);
};
```
## Best Practices
1. **Never Swallow Errors**
- Always handle or propagate errors
- Log errors appropriately for debugging
- Use error boundaries in React components
2. **Type Safety**
- Use typed error responses
- Leverage TypeScript for compile-time error checking
- Define clear error interfaces
3. **Error Messages**
- Include relevant context in error messages
- Make messages actionable for developers
- Use consistent error formatting
4. **Error Recovery**
- Implement fallback behaviors where appropriate
- Gracefully degrade functionality when possible
- Provide user feedback for recoverable errors
5. **Documentation**
- Document expected errors in function JSDoc
- Include error handling in code examples
- Keep error handling documentation up to date
## Testing Error Scenarios
Always include error case testing:
```typescript
describe("fetchEnvironmentState()", () => {
test("returns err(...) on network error", async () => {
const mockNetworkError = {
code: "network_error",
message: "Timeout",
responseMessage: "Network fail",
};
const result = await fetchEnvironmentState();
expect(result.ok).toBe(false);
if (!result.ok) {
expect(result.error.code).toBe(mockNetworkError.code);
expect(result.error.message).toBe(mockNetworkError.message);
}
});
});
```
These standards ensure consistent, reliable error handling across the Formbricks codebase while maintaining good developer experience and system reliability.

View File

@@ -0,0 +1,100 @@
---
title: Code Reviews
description: This document outlines our comprehensive code review process at Formbricks. We maintain high quality, consistency, and best practices within our codebase through this structured approach.
icon: eyes
---
## Initial Checks via GitHub Workflows
When a Pull Request (PR) is opened, our automated GitHub workflows perform several critical checks:
> **Note:** At Formbricks, all feature changes must be submitted through Pull Requests - direct pushes to protected branches are not allowed.
- **PR Title Validation**: Ensures clear, descriptive titles following our conventions
- **Build Verification**: Confirms that the build process completes successfully
- **Test Suite**: Runs all automated tests to catch potential regressions
- **Translation Check**: Identifies any missing translation keys
- **Linting**: Enforces our coding standards and style guidelines
These checks must pass before proceeding to manual review.
## Reviewer Assignment
Once all automated checks pass successfully:
- A team member with relevant expertise is assigned as the reviewer
- The reviewer is notified automatically through GitHub
- Priority is given based on PR urgency and complexity
## Functional Testing and UI Review
The assigned reviewer performs thorough testing:
### Functionality Testing
- Verifies that new features work as specified
- Tests edge cases and error scenarios
- Ensures proper error handling
- Checks integration with existing features
### UI Review (if applicable)
- Validates visual consistency
- Checks responsive behavior
- Ensures accessibility standards
- Reviews user interaction flows
## Feedback Process
If improvements are needed:
- Reviewers add inline comments on GitHub
- Feedback is specific and actionable
- Code suggestions are provided when helpful
- Comments follow our constructive feedback guidelines
## In-depth Code Review
Our code review process utilizes both human expertise and AI assistance:
### Manual Review
- Code structure and organization
- Design patterns and best practices
- Performance considerations
- Security implications
- Documentation completeness
### AI-Assisted Review
We leverage advanced AI tools for additional insights:
- **Code Rabbit**: Automated code analysis and suggestions
- **Sonarqube**: Code quality metrics and potential issues
## Resolution and Merge
Final steps before merging:
- All review comments must be addressed
- Required changes are implemented
- At least one reviewer approval is required
- All conversations must be resolved
- CI/CD pipeline passes again
- PR is merged into the target branch
## Best Practices
- Keep PRs focused and reasonably sized
- Respond to review comments promptly
- Use the "Request Changes" feature when necessary
- Mark conversations as resolved when addressed
- Use approve/request changes workflow appropriately
## Conclusion
Our code review process combines automated checks, manual review, and AI assistance to ensure high-quality code contributions. This multi-layered approach helps maintain code quality while promoting knowledge sharing within the team.
Remember: Code reviews are not just about finding issues—they're opportunities for learning and improving our codebase together.

View File

@@ -0,0 +1,127 @@
---
title: Testing Methodology
icon: magnifying-glass
---
## Overview
At Formbricks, we maintain a rigorous testing strategy to ensure high-quality code and reliable functionality. Our testing approach is standardized and integrated into our development workflow.
## Testing Structure
### Unit Testing with Vitest
We use Vitest as our primary testing framework. All unit tests follow these conventions:
1. **File Location and Naming**
- Test files are co-located with the source files they test
- Test files use the `.test.ts` extension (e.g., `utils.test.ts` tests `utils.ts`)
2. **Test Organization**
```typescript
import { describe, expect, it } from "vitest";
describe("ComponentName or FeatureName", () => {
describe("functionName or scenario", () => {
it("should describe expected behavior", () => {
// test implementation
});
});
});
```
3. **Coverage Requirements**
- Minimum 85% code coverage requirement (WIP 👷‍♂️)
- Coverage is tracked using V8 provider
- Coverage reports include:
- Text summaries
- HTML reports
- LCOV reports
### End-to-End Testing with Playwright
E2E tests are located in `apps/web/playwright/` and focus on critical user workflows.
## Testing Setup
### Configuration
Our Vitest configuration (`vite.config.ts`) includes:
```typescript
test: {
exclude: ['playwright/', 'node_modules/'],
setupFiles: ['../../packages/lib/vitestSetup.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'html', 'lcov'],
reportsDirectory: './coverage',
},
}
```
### Test Utilities
Common test utilities are available in `vitestSetup.ts`:
- Mock implementations for commonly used functions
- Test lifecycle hooks (beforeEach, afterEach)
- Validation test helpers
## Best Practices
1. **Test Independence**
```typescript
beforeEach(() => {
vi.resetModules();
vi.resetAllMocks();
});
afterEach(() => {
vi.clearAllMocks();
});
```
2. **Mocking**
- Use Vitest's built-in mocking utilities
- Mock external dependencies and services
- Example:
```typescript
vi.mock("@formbricks/database", () => ({
prisma: {
user: {
create: vi.fn(),
findUnique: vi.fn(),
},
},
}));
```
3. **Assertions**
- Write clear, specific assertions
- Test both success and error cases
- Example:
```typescript
expect(result.ok).toBe(true);
expect(result.data).toEqual(expectedData);
expect(async () => await invalidCall()).rejects.toThrow(ValidationError);
```
## Quality Assurance Process
1. **Continuous Integration**
- Automated test suite execution on pull requests
- Coverage reports generation
- Test results reporting
2. **New Features**
- Must include corresponding unit tests
- Must maintain or improve coverage metrics
- Must include relevant E2E tests for user-facing features

View File

@@ -0,0 +1,38 @@
---
title: Framework Usage
icon: book
---
## Introduction
This document outlines the framework usage guidelines for Formbricks, which is built primarily on Next.js (with heavy use of Server-Side Rendering through the App Router), Tailwind CSS, and Prisma ORM.
## Next.js
### App Router and Server Components
- Use the Next.js App Router with the /app directory for building the application.
- Leverage React Server Components, which are the default in the App Router.
- Perform server-side data fetching directly within page.tsx files using async function components.
### Data Fetching in page.tsx
- Implement data fetching logic directly in your page.tsx components. This allows for server-side rendering without needing separate data fetching methods like getServerSideProps.
- Utilize React Suspense and streaming features if using advanced asynchronous patterns.
### Server Actions for Mutations
- Define Server Actions in dedicated action.ts files.
- Server actions serve as entry points for mutations and delegate to service layers that perform Prisma operations and other business logic.
- This approach promotes separation of concerns and maintainability by keeping form actions and mutations decoupled from UI components.
### Error Handling and Performance
- Integrate error boundaries and loading states appropriately within your App Router structure.
- Optimize performance with Next.js built-in features such as dynamic imports, the Image component, and code splitting.
## Tailwind CSS
We follow the Tailwind framework as intended. Please have a look at the [Tailwind CSS Guidelines](https://tailwindcss.com/docs/styling-with-utility-classes) for more information.
## Prisma ORM
We're working with Prisma as our ORM. Please have a look at the [Prisma ORM Documentation](https://www.prisma.io/docs/orm) for more information.

View File

@@ -0,0 +1,107 @@
---
title: Language-Specific
description: This document outlines the language-specific conventions for the Formbricks codebase, providing guidelines for writing code in TypeScript/JavaScript.
icon: code
---
## TypeScript
Our codebase follows the Vercel Engineering Style Guide conventions.
### ESLint Configuration
We maintain three primary ESLint configurations for different project types:
1. **Library Configuration** (for packages):
```javascript
extends: [
"@vercel/style-guide/eslint/node",
"@vercel/style-guide/eslint/typescript"
]
```
2. **React Configuration** (for React applications):
```javascript
extends: [
"@vercel/style-guide/eslint/node",
"@vercel/style-guide/eslint/typescript",
"@vercel/style-guide/eslint/browser",
"@vercel/style-guide/eslint/react",
"@vercel/style-guide/eslint/next"
]
```
3. **Next.js Configuration** (for Next.js applications):
```javascript
extends: [
"@vercel/style-guide/eslint/node",
"@vercel/style-guide/eslint/typescript",
"@vercel/style-guide/eslint/browser",
"@vercel/style-guide/eslint/react",
"@vercel/style-guide/eslint/next"
]
```
### Key Conventions
1. **TypeScript Usage**
- Strict TypeScript checking enabled
- Explicit type annotations when necessary
- Proper interface and type naming (prefix with T for types, I for interfaces when helpful)
- No use of `any` type unless absolutely necessary
2. **Imports/Exports**
- Follow strict import ordering:
1. Mocks (for testing)
2. Server-only imports
3. Third-party modules
4. Internal `@formbricks/*` modules
5. Local aliases (`~/*)
6. Relative imports
3. **Error Handling**
- Use typed error responses
- Proper error propagation
- Consistent error message formatting
- Implement error boundaries in React components
4. **Async/Await**
- Prefer async/await over raw promises
- Proper error handling in async functions
- Use Promise.all for parallel operations
5. **React Specific**
- Functional components with TypeScript
- Proper use of hooks
- Consistent prop typing
- Server Components by default in Next.js App Router
### Code Formatting
We use Prettier with specific configurations:
```javascript
{
bracketSpacing: true,
bracketSameLine: true,
singleQuote: false,
jsxSingleQuote: false,
trailingComma: "es5",
semi: true,
printWidth: 110,
arrowParens: "always"
}
```
## Swift
Will be added upon release of the native iOS SDK.
## Kotlin
Will be added upon release of the native Android SDK.

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -92,7 +92,6 @@
}
]
},
{
"group": "Core Features",
"pages": [
@@ -139,6 +138,10 @@
"xm-and-surveys/core-features/email-customization"
]
},
{
"group": "Enterprise Features",
"pages": ["xm-and-surveys/enterprise-features/saml-sso"]
},
{
"group": "XM",
"pages": [
@@ -179,9 +182,55 @@
"pages": ["development/technical-handbook/overview", "development/technical-handbook/database-model"]
},
{
"group": "Contribution",
"group": "Standards",
"pages": [
{
"group": "Code Organization",
"icon": "code",
"pages": [
"development/standards/organization/file-and-directory-organization",
"development/standards/organization/naming-conventions",
"development/standards/organization/module-component-structure"
]
},
{
"group": "Development Practices",
"icon": "laptop",
"pages": [
"development/standards/practices/code-formatting",
"development/standards/practices/documentation",
"development/standards/practices/error-handling"
]
},
{
"group": "Technical Standards",
"icon": "gear",
"pages": [
"development/standards/technical/language-specific-conventions",
"development/standards/technical/framework-usage"
]
},
{
"group": "Quality Assurance",
"icon": "shield",
"pages": ["development/standards/qa/code-reviews", "development/standards/qa/testing-methodology"]
}
]
},
{
"group": "Contributions",
"pages": ["development/contribution/contribution"]
},
{
"group": "Guides",
"pages": [
{
"group": "Auth & Provision",
"icon": "user-shield",
"pages": ["development/guides/auth-and-provision/setup-saml-with-identity-providers"]
}
]
},
{
"group": "Support",
"pages": ["development/support/troubleshooting"]
@@ -195,7 +244,8 @@
"pages": [
"self-hosting/setup/one-click",
"self-hosting/setup/docker",
"self-hosting/setup/cluster-setup"
"self-hosting/setup/cluster-setup",
"self-hosting/setup/monitoring"
]
},
{
@@ -203,7 +253,14 @@
"pages": [
"self-hosting/configuration/custom-ssl",
"self-hosting/configuration/environment-variables",
"self-hosting/configuration/oauth",
{
"group": "Auth & SSO",
"icon": "lock",
"pages": [
"self-hosting/configuration/auth-sso/oauth",
"self-hosting/configuration/auth-sso/saml-sso"
]
},
{
"group": "Integrations",
"icon": "bridge",

View File

@@ -0,0 +1,76 @@
---
title: "SAML SSO"
icon: "user-shield"
description: "How to set up SAML SSO for Formbricks"
---
<Note>You require an Enterprise License along with a SAML SSO add-on to avail this feature.</Note>
## Overview
Formbricks supports SAML Single Sign-On (SSO) to enable secure, centralized authentication. With SAML, organizations can integrate their existing Identity Provider (IdP) infrastructure for streamlined access management. Formbricks internally uses BoxyHQ's SAML Jackson to manage SAML connections. SAML Jackson is a service provided by BoxyHQ that manages SAML connection details and validates assertions. It is part of the Formbricks server.
To learn more about SAML Jackson, please refer to the [BoxyHQ SAML Jackson documentation](https://boxyhq.com/docs/jackson/deploy).
## How SAML Works in Formbricks
SAML (Security Assertion Markup Language) is an XML-based standard for exchanging authentication and authorization data between an Identity Provider (IdP) and Formbricks. Here's how the integration works with BoxyHQ Jackson embedded into the flow:
1. **Login Initiation:**
The user clicks “Sign in with SAML” on Formbricks.
2. **Configuration Retrieval via BoxyHQ:**
Formbricks requests the SAML connection details from BoxyHQ Jackson. BoxyHQ securely stores and manages the IdP configuration, including endpoints, certificates, and other metadata.
3. **Redirection:**
With the configuration details from BoxyHQ, Formbricks redirects the user to the IdPs login page (e.g., Okta).
4. **Authentication:**
The user authenticates directly with the IdP.
5. **SAML Response:**
Upon successful authentication, the IdP sends a signed SAML response back to Formbricks via the users browser.
6. **Validation via BoxyHQ:**
BoxyHQ Jackson validates the SAML assertion—verifying the signature and extracting user details—before sending the validated data back to Formbricks.
7. **Access Granted:**
Formbricks logs the user in using the verified information.
## SAML Authentication Flow Sequence Diagram
Below is a sequence diagram illustrating the complete SAML authentication flow with BoxyHQ Jackson integrated:
```mermaid
sequenceDiagram
participant U as User
participant FB as Formbricks (SP)
participant BHQ as BoxyHQ Jackson
participant OK as Okta (IdP)
Note over FB,BHQ: (Setup phase, done beforehand)<br/>1. Admin configures SAML metadata in Formbricks<br/>2. BoxyHQ stores & manages SAML connection details
U->>FB: Clicks “Sign in with SAML”
FB->>BHQ: Request SAML connection details
BHQ->>FB: Returns SAML configuration (IdP info)
FB->>OK: Redirect user to Okta (SAML Auth Request)
OK->>U: Prompts user for credentials
U->>OK: Submits credentials
OK->>FB: Sends SAML Assertion (Callback URL)
FB->>BHQ: Validates assertion & extracts user info
BHQ->>FB: Returns validated user data
FB->>U: Logs user into Formbricks
```
## Setting Up SAML SSO
To configure SAML SSO in Formbricks, follow these steps:
1. **Database Setup:** Configure a dedicated database for SAML by setting the `SAML_DATABASE_URL` environment variable (e.g., `postgresql://postgres:@localhost:5432/formbricks-saml`). If you're using a self-signed certificate for Postgres, include the `sslmode=no-verify` parameter.
2. **Admin Configuration:** Define the SAML administrators by setting `SAML_ADMINS` as a comma-separated list of admin emails.
3. **IdP Application:** Create a SAML application in your IdP by following your provider's instructions([SAML Setup](/development/guides/auth-and-provision/setup-saml-with-identity-providers))
4. **User Provisioning:** Provision users in your IdP and configure access to the IdP SAML app for all your users (who need access to Formbricks).
5. **Metadata:** Keep the XML metadata from your IdP handy for the next step.
6. **Metadata Upload:** Log in with one of the SAML admin accounts and navigate to **Organization Settings -> Single Sign-On** in Formbricks. Paste the XML metadata from your IdP into the SAML configuration section.
7. **Finalize Setup:** Save your configuration. Provisioned users can now use SAML SSO to access Formbricks.

View File

@@ -0,0 +1,91 @@
---
title: "Monitoring"
description: "Monitoring your Formbricks installation for optimal performance."
icon: "magnifying-glass-chart"
---
## Logging
Formbricks follows Next.js best practices with all logs being written to stdout/stderr, making it easy to collect and forward logs to your preferred logging solution.
### Docker Container Logs
```bash
# One-Click setup
cd formbricks
docker compose logs
# Standard Docker commands
docker logs <container-name>
docker logs -f <container-name> # Follow logs
```
### Kubernetes Pod Logs
```bash
kubectl logs <pod-name> -n <namespace>
kubectl logs -f <pod-name> -n <namespace> # Follow logs
```
### Log Forwarding
Since all logs are written to stdout/stderr, you can integrate with various logging solutions:
- ELK Stack (Elasticsearch, Logstash, Kibana)
- Fluentd/Fluent Bit
- Datadog
- Splunk
- CloudWatch Logs (AWS)
## OpenTelemetry Integration (Beta)
Formbricks leverages Next.js's built-in OpenTelemetry instrumentation for comprehensive observability. When enabled, it automatically instruments various aspects of your application.
Set the following environment variables:
```env
OTEL_ENABLED=true
OTEL_ENDPOINT=<your-collector-endpoint>
OTEL_SERVICE_NAME=formbricks
NEXT_OTEL_VERBOSE=1 # Optional: enables detailed tracing
```
### Default Instrumentation
The OpenTelemetry integration automatically tracks:
- HTTP requests and responses
- Route rendering
- API route execution
- Server-side operations
- Database queries
- External API calls
### Supported Backends
OpenTelemetry can export data to:
- Jaeger
- Zipkin
- Prometheus
- New Relic
- Datadog
- Azure Monitor
### Key Metrics
- HTTP request duration
- Database performance
- Memory usage
- Response times
- Error rates
## Health Checks
Available endpoints:
```
GET /health
```
Use these endpoints for monitoring system health in container orchestration and monitoring tools.

View File

@@ -1,19 +1,12 @@
export const metadata = {
title: "Airtable Setup",
description: "Instantly populate your airtable table with survey data",
};
#### Integrations
# Airtable
---
title: "Airtable"
description: "A step-by-step guide to integrate Airtable with Formbricks Cloud."
---
The Airtable integration allows you to automatically send responses to an Airtable of your choice.
<Note>
If you are on a self-hosted instance, you will need to configure this
integration separately. Please follow the guides
[here](/self-hosting/configuration/integrations) to configure integrations on your
self-hosted instance.
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow the guides [here](/self-hosting/configuration/integrations) to configure integrations on your self-hosted instance.
</Note>
## Formbricks Cloud
@@ -22,34 +15,31 @@ The Airtable integration allows you to automatically send responses to an Airtab
![Formbricks Integration Tab](/images/xm-and-surveys/core-features/integrations/airtable/integrations-tab.webp)
2. Now click on the "Connect with Airtable" button to authenticate yourself with Airtable.
1. Now click on the "Connect with Airtable" button to authenticate yourself with Airtable.
![Connect Formbricks with Airtable](/images/xm-and-surveys/core-features/integrations/airtable/connect-with-airtable.webp)
3. You will now be taken to a page where you need to add and grant access to the base you want to use for the integration.
1. You will now be taken to a page where you need to add and grant access to the base you want to use for the integration.
![Add and grant access to airtable base](/images/xm-and-surveys/core-features/integrations/airtable/add-base.webp)
4. Once you add and grant access to your base, you will be taken back to Formbricks Cloud and see the connected status as below:
1. Once you add and grant access to your base, you will be taken back to Formbricks Cloud and see the connected status as below:
![Formbricks is now connected with Google](/images/xm-and-surveys/core-features/integrations/airtable/airtable-connected.webp)
<Note>
Before the next step, make sure that you have a Formbricks Survey with at least one question and a Airtable base with atleast one table in the Airtable account you integrated.
Before the next step, make sure that you have a Formbricks Survey with at least one question and a Airtable base with atleast one table in the Airtable account you integrated.
</Note>
6. Now click on the "Link New Table" button to link an Airtable with Formbricks and a modal will open up.
1. Now click on the "Link New Table" button to link an Airtable with Formbricks and a modal will open up.
![Link Formbricks with a Airtable](/images/xm-and-surveys/core-features/integrations/airtable/link-survey-with-table.webp)
7. Select the Base and table you want to link with Formbricks and the Survey. On doing so, you will be asked with what questions' responses you want to feed in Airtable. Select the questions and click on the "Save" button.
1. Select the Base and table you want to link with Formbricks and the Survey. On doing so, you will be asked with what questions' responses you want to feed in Airtable. Select the questions and click on the "Save" button.
![Select question to link with Airtable](/images/xm-and-surveys/core-features/integrations/airtable/link-with-questions.webp)
8. On submitting, the modal will close and you will see the linked table in the list of linked tables.
1. On submitting, the modal will close and you will see the linked table in the list of linked tables.
![List of linked tables](/images/xm-and-surveys/core-features/integrations/airtable/list-linked-surveys.webp)
@@ -62,10 +52,13 @@ Still struggling or something not working as expected? [Join us on Github Discus
To remove the integration with Airtable,
1. Visit the Integrations tab in your Formbricks Cloud dashboard.
2. Select "Manage" button in the Airtable card.
3. Click on the "Connected with `<your-email-here`>" just before the "Link new Table" button.
4. It will now ask for a confirmation to remove the integration. Click on the "Delete" button to remove the integration. You can always come back and connect again with the same Airtable Account.
![Delete Airtable Integration with Formbricks](/images/xm-and-surveys/core-features/integrations/airtable/delete-integration.webp)
Still struggling or something not working as expected? [Join our Github Discussions](https://github.com/formbricks/formbricks/discussions) and we'd be glad to assist you!
Still struggling or something not working as expected? [Join our Github Discussions](https://github.com/formbricks/formbricks/discussions) and we'd be glad to assist you!

View File

@@ -4,17 +4,8 @@ description:
"The Google Sheets integration allows you to automatically send responses to a Google Sheet of your choice."
---
#### Integrations
# Google Sheets
The Google Sheets integration allows you to automatically send responses to a Google Sheet of your choice.
<Note>
If you are on a self-hosted instance, you will need to configure this
integration separately. Please follow the guides
[here](/self-hosting/configuration/integrations) to configure integrations on your
self-hosted instance.
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow the guides [here](/self-hosting/configuration/integrations) to configure integrations on your self-hosted instance.
</Note>
## Connect Google Sheets
@@ -23,31 +14,29 @@ The Google Sheets integration allows you to automatically send responses to a Go
![Formbricks Integrations Tab](/images/xm-and-surveys/core-features/integrations/google-sheets/integrations-tab.webp)
2. Now click on the "Connect with Google" button to authenticate yourself with Google.
1. Now click on the "Connect with Google" button to authenticate yourself with Google.
![Connect Formbricks with your Google](/images/xm-and-surveys/core-features/integrations/google-sheets/connect-with-google.webp)
3. You will now be taken to the Google OAuth page where you can select the Google account you want to use for the integration.
1. You will now be taken to the Google OAuth page where you can select the Google account you want to use for the integration.
4. Once you have selected the account and completed the authentication process, you will be taken back to Formbricks Cloud and see the connected status as below:
2. Once you have selected the account and completed the authentication process, you will be taken back to Formbricks Cloud and see the connected status as below:
![Formbricks is now connected with Google](/images/xm-and-surveys/core-features/integrations/google-sheets/google-connected.webp)
<Note>
Before the next step, make sure that you have a Formbricks Survey with at least one question and a Google Sheet in the Google account you integrated.
Before the next step, make sure that you have a Formbricks Survey with at least one question and a Google Sheet in the Google account you integrated.
</Note>
5. Now click on the "Link New Sheet" button to link a Google Sheet with Formbricks and a modal will open up.
1. Now click on the "Link New Sheet" button to link a Google Sheet with Formbricks and a modal will open up.
![Link Formbricks with a Google Sheet](/images/xm-and-surveys/core-features/integrations/google-sheets/link-survey-with-sheet.webp)
6. Enter the spreadsheet URL for the Google Sheet you want to link with Formbricks and the Survey. On doing so, you will be asked with what questions' responses you want to feed in the Google Sheet. Select the questions and click on the "Link Sheet" button.
1. Enter the spreadsheet URL for the Google Sheet you want to link with Formbricks and the Survey. On doing so, you will be asked with what questions' responses you want to feed in the Google Sheet. Select the questions and click on the "Link Sheet" button.
![Select question to link with Google Sheet](/images/xm-and-surveys/core-features/integrations/google-sheets/link-with-questions.webp)
7. On submitting, the modal will close and you will see the linked Google Sheet in the list of linked Google Sheets.
1. On submitting, the modal will close and you will see the linked Google Sheet in the list of linked Google Sheets.
![List of linked Google Sheets](/images/xm-and-surveys/core-features/integrations/google-sheets/list-linked-surveys.webp)
@@ -58,23 +47,29 @@ Congratulations! You have successfully linked a Google Sheet with Formbricks. No
To remove the integration with Google Account,
1. Visit the Integrations tab in your Formbricks Cloud dashboard.
2. Select **Manage Sheets** button in the Google Sheets card.
3. Click on the **Delete Integration** button.
4. It will now ask for a confirmation to remove the integration. Click on the **Delete** button to remove the integration. You can always come back and connect again with the same Google Account.
![Delete Google Integration with Formbricks](/images/xm-and-surveys/core-features/integrations/google-sheets/delete-connection.webp)
## What info do you need?
- Your **Email ID** for authentication (We use this to identify you)
- Your **Google Sheets Names and IDs** (We fetch this to list and show you the options of choosing a sheet to integrate with)
- Write access to **selected Google Sheet** (The google sheet you choose to integrate it with, we write survey responses to it)
* Your **Email ID** for authentication (We use this to identify you)
* Your **Google Sheets Names and IDs** (We fetch this to list and show you the options of choosing a sheet to integrate with)
* Write access to **selected Google Sheet** (The google sheet you choose to integrate it with, we write survey responses to it)
For the above, we ask for:
1. **User Email**: To identify you (that's it, nothing else, we're opensource, see this in our codebase [here](https://github.com/formbricks/formbricks/blob/main/apps/web/app/api/google-sheet/callback/route.ts#L47C17-L47C25))
1. **Google Spreadsheet API**: To write to the spreadsheet you select (that's it, nothing else, we're opensource, see this method in our codebase [here](https://github.com/formbricks/formbricks/blob/main/packages/lib/googleSheet/service.ts#L70))
2. **Google Spreadsheet API**: To write to the spreadsheet you select (that's it, nothing else, we're opensource, see this method in our codebase [here](https://github.com/formbricks/formbricks/blob/main/packages/lib/googleSheet/service.ts#L70))
<Note>We store as little personal information as possible.</Note>
Still struggling or something not working as expected? [Join our Github Discussions](https://github.com/formbricks/formbricks/discussions) and we'd be glad to assist you!
Still struggling or something not working as expected? [Join our Github Discussions](https://github.com/formbricks/formbricks/discussions) and we'd be glad to assist you!

View File

@@ -4,16 +4,10 @@ description:
"Discover how to seamlessly integrate Formbricks with Make.com. Dive into our comprehensive guide to set up scenarios, connect with a plethora of apps, and send your survey data to more than 1000 platforms."
---
#### Integrations
# Make.com Setup
Make is a powerful tool to send information between Formbricks and thousands of apps. Here's how to set it up.
<Note>
Nailed down your survey?? Any changes in the survey cause additional work in
the _Scenario_. It makes sense to first settle on the survey you want to run
and then get to setting up Make.
Nailed down your survey?? Any changes in the survey cause additional work in the *Scenario*. It makes sense to first settle on the survey you want to run and then get to setting up Make.
</Note>
## Step 1: Setup your survey incl. `questionId` for every question
@@ -22,13 +16,12 @@ Set up the `questionId`s of your survey questions before publishing.
![Update Question ID](/images/xm-and-surveys/core-features/integrations/make/update-question-id.webp)
_Update the Question ID field in every question card under Advanced Settings._
*Update the Question ID field in every question card under Advanced Settings.*
<Note>
Already published? Duplicate survey You can only update the questionId
before publishing the survey. If already published, simply duplicate it.
![Duplicate Survey](/images/xm-and-surveys/core-features/integrations/make/duplicate-survey.webp)
</Note>
## Step 2: Setup Make.com
@@ -51,7 +44,7 @@ Click "Create a webhook":
![Create Webhook](/images/xm-and-surveys/core-features/integrations/make/create-webhook.webp)
Enter the Formbricks API Host and API Key. API Host is by default set to https://app.formbricks.com but can be modified for self hosting instances. Learn how to get an API Key from the [API Key tutorial](/api-reference/rest-api#how-to-generate-an-api-key).
Enter the Formbricks API Host and API Key. API Host is by default set to [https://app.formbricks.com](https://app.formbricks.com) but can be modified for self hosting instances. Learn how to get an API Key from the [API Key tutorial](/api-reference/rest-api#how-to-generate-an-api-key).
![Enter API Key](/images/xm-and-surveys/core-features/integrations/make/enter-api-key-and-host.webp)
@@ -83,4 +76,4 @@ Specify the spreadsheet details and match the Formbricks data:
A new row gets added to the spreadsheet for every response:
![Result](/images/xm-and-surveys/core-features/integrations/make/result.webp)
![Result](/images/xm-and-surveys/core-features/integrations/make/result.webp)

View File

@@ -3,11 +3,6 @@ title: "n8n"
description: "Integrate Formbricks with n8n for a streamlined workflow experience."
---
#### Integrations
# n8n Setup
<Note>
The Formbricks n8n node is currently only available in the n8n self-hosted
version as a community node. To install it go to "Settings" -> "Community
@@ -28,7 +23,7 @@ When setting up the node your life will be easier when you change the `questionI
![Update Question ID](/images/xm-and-surveys/core-features/integrations/n8n/update-question-id.webp)
_In every question card in the Advanced Settings you find the Question ID field. Update it so that you'll recognize the response tied to this question._
*In every question card in the Advanced Settings you find the Question ID field. Update it so that you'll recognize the response tied to this question.*
<Note>
Already published? Duplicate survey You can only update the questionId
@@ -79,7 +74,7 @@ Here, we are selecting two surveys.
## Step 6: Test your trigger
In order to set up n8n you'll need a test response in the selected survey. This allows you to select the individual values of each response in your workflow.
In order to set up n8n you'll need a test response in the selected survey. This allows you to select the individual values of each response in your workflow.
![Submit Test Response](/images/xm-and-surveys/core-features/integrations/n8n/submit-test-response.webp)
@@ -105,4 +100,4 @@ Fill in the `Webhook URL` and the `Content` that you want to receive in the resp
Once the execution is successful, you'll receive the content in the discord channel.
![Discord Response](/images/xm-and-surveys/core-features/integrations/n8n/discord-response.webp)
![Discord Response](/images/xm-and-surveys/core-features/integrations/n8n/discord-response.webp)

View File

@@ -4,13 +4,8 @@ description:
"The notion integration allows you to automatically send responses to a Notion database of your choice."
---
The notion integration allows you to automatically send responses to a Notion database of your choice.
<Note>
If you are on a self-hosted instance, you will need to configure this
integration separately. Please follow the guides
[here](/self-hosting/configuration/integrations) to configure integrations on your
self-hosted instance.
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow the guides [here](/self-hosting/configuration/integrations) to configure integrations on your self-hosted instance.
</Note>
## Formbricks Cloud
@@ -19,13 +14,13 @@ The notion integration allows you to automatically send responses to a Notion da
![Formbricks Integrations Tab](/images/xm-and-surveys/core-features/integrations/notion/integrations-tab.webp)
2. Now click on the "Connect with Notion" button to authenticate yourself with Notion.
1. Now click on the "Connect with Notion" button to authenticate yourself with Notion.
![Connect Formbricks with your Notion account](/images/xm-and-surveys/core-features/integrations/notion/connect-with-notion.webp)
3. You will now be taken to the Notion OAuth page where you can select the Notion account you want to use for the integration
1. You will now be taken to the Notion OAuth page where you can select the Notion account you want to use for the integration
4. Once you have selected the account and databases and completed the authentication and authorization process, you will be taken back to Formbricks Cloud and see the connected status as below:
2. Once you have selected the account and databases and completed the authentication and authorization process, you will be taken back to Formbricks Cloud and see the connected status as below:
![Formbricks is now connected with Notion](/images/xm-and-surveys/core-features/integrations/notion/notion-connected.webp)
@@ -34,15 +29,15 @@ The notion integration allows you to automatically send responses to a Notion da
least one question and a Notion database in the Notion account you integrated.
</Note>
5. Now click on the "Link New Database" button to link a Notion database with Formbricks and a modal will open up.
1. Now click on the "Link New Database" button to link a Notion database with Formbricks and a modal will open up.
![Link Formbricks with a Notion database](/images/xm-and-surveys/core-features/integrations/notion/link-survey-with-database.webp)
6. Select the Notion database you want to link with Formbricks and the Survey. On doing so, you will be asked to map formbricks' survey questions with selected databases' column. Complete the mapping and click on the "Link Database" button.
1. Select the Notion database you want to link with Formbricks and the Survey. On doing so, you will be asked to map formbricks' survey questions with selected databases' column. Complete the mapping and click on the "Link Database" button.
![Question to notion database column mapping](/images/xm-and-surveys/core-features/integrations/notion/link-with-databases.webp)
7. On submitting, the modal will close and you will see the linked Notion database in the list of linked Notion databases.
1. On submitting, the modal will close and you will see the linked Notion database in the list of linked Notion databases.
![List of linked notion databases](/images/xm-and-surveys/core-features/integrations/notion/list-linked-databases.webp)
@@ -53,16 +48,26 @@ Congratulations! You have successfully linked a Notion database with Formbricks.
Enabling the Notion Integration in a self-hosted environment requires a setup using Notion account and changing the environment variables of your Formbricks instance.
1. Sign up for a [Notion](https://www.notion.so/) account, if you don't have one already.
2. Go to the [my integrations](https://www.notion.so/my-integrations) page and click on **New integration**.
3. Fill up the basic information like **Name**, **Logo** and click on **Submit**.
4. Now, click on **Distribution** tab on the sidebar. A text will appear which will ask you to make the integration public. Click on that toggle button. A form will appear below the text.
5. Now provide it the details such as requested. Under **Redirect URIs** field:
- If you are running formbricks locally, you can enter `http://localhost:3000/api/v1/integrations/notion/callback`.
- Or, you can enter `https://<your-public-facing-url>/api/v1/integrations/notion/callback`
* If you are running formbricks locally, you can enter `http://localhost:3000/api/v1/integrations/notion/callback`.
* Or, you can enter `https://<your-public-facing-url>/api/v1/integrations/notion/callback`
6. Once you've filled all the necessary details, click on **Submit**.
7. A screen will appear which will have **Client ID** and **Client secret**. Copy them and set them as the environment variables in your Formbricks instance as:
- `NOTION_OAUTH_CLIENT_ID` - OAuth Client ID
- `NOTION_OAUTH_CLIENT_SECRET` - OAuth Client Secret
* `NOTION_OAUTH_CLIENT_ID` - OAuth Client ID
* `NOTION_OAUTH_CLIENT_SECRET` - OAuth Client Secret
Voila! You have successfully enabled the Notion integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Formbricks Cloud](#formbricks-cloud) section to link a Notion database with Formbricks.
@@ -71,10 +76,13 @@ Voila! You have successfully enabled the Notion integration in your self-hosted
To remove the integration with Slack Workspace,
1. Visit the Integrations tab in your Formbricks Cloud dashboard.
2. Select "Manage" button in the Slack card.
3. Click on the "Delete Integration" button.
4. It will now ask for a confirmation to remove the integration. Click on the "Delete" button to remove the integration. You can always come back and connect again with the same Notion Account.
![Delete Notion Integration with Formbricks](/images/xm-and-surveys/core-features/integrations/notion/delete-connection.webp)
Still struggling or something not working as expected? [Join our Github Discussions](https://github.com/formbricks/formbricks/discussions) and we'd be glad to assist you!
Still struggling or something not working as expected? [Join our Github Discussions](https://github.com/formbricks/formbricks/discussions) and we'd be glad to assist you!

View File

@@ -1,27 +1,32 @@
---
title: "Overview"
description: "Configure third-party integrations with a Formbricks instance."
description: "Configure third-party integrations with Formbricks Cloud."
---
At Formbricks, we understand the importance of integrating with third-party applications. We have step-by-step guides to configure our third-party integrations with a your Formbricks instance. We currently support the below integrations, click on them to see their individual guides:
At Formbricks, we understand the importance of integrating with third-party applications. We have step-by-step guides to configure our third-party integrations with Formbricks Cloud.&#x20;
<Note>
If you are on a self-hosted instance, you will need to configure these
integrations manually. Please follow the guides
[here](/self-hosting/configuration/integrations) to configure integrations on your
self-hosted instance.
If you are on a self-hosted instance, you will need to configure these integrations manually. Please follow the guides [here](/self-hosting/configuration/integrations) to configure integrations on your self-hosted instance.
</Note>
- [ActivePieces](/xm-and-surveys/core-features/integrations/activepieces) (Open Source): Automate workflows with ActivePieces no-code automation tool
- [Airtable](/xm-and-surveys/core-features/integrations/airtable): Automatically send responses to an Airtable of your choice.
- [Google Sheets](/xm-and-surveys/core-features/integrations/google-sheets): Automatically send responses to a Google Sheet of your choice.
- [Make](/xm-and-surveys/core-features/integrations/make): Leverage Make's powerful automation capabilities to automate your workflows.
- [n8n](/xm-and-surveys/core-features/integrations/n8n)(Open Source): Automate workflows with n8n's no-code automation tool
- [Notion](/xm-and-surveys/core-features/integrations/notion): Automatically send responses to a Notion database of your choice.
- [Slack](/xm-and-surveys/core-features/integrations/slack): Automatically send responses to a Slack channel of your choice on response events.
- [Wordpress](/xm-and-surveys/core-features/integrations/wordpress)(Open Source): Automatically integrate your Formbricks surveys with your Wordpress website.
- [Zapier](/xm-and-surveys/core-features/integrations/zapier): Connect Formbricks with 2000+ apps on Zapier.
* [ActivePieces](/xm-and-surveys/core-features/integrations/activepieces) (Open Source): Automate workflows with ActivePieces no-code automation tool
---
* [Airtable](/xm-and-surveys/core-features/integrations/airtable): Automatically send responses to an Airtable of your choice.
If you have any questions or need help with any of the integrations or even want a new integration, please reach out to us on [Github Discussions](https://github.com/formbricks/formbricks/discussions).
* [Google Sheets](/xm-and-surveys/core-features/integrations/google-sheets): Automatically send responses to a Google Sheet of your choice.
* [Make](/xm-and-surveys/core-features/integrations/make): Leverage Make's powerful automation capabilities to automate your workflows.
* [n8n](/xm-and-surveys/core-features/integrations/n8n)(Open Source): Automate workflows with n8n's no-code automation tool
* [Notion](/xm-and-surveys/core-features/integrations/notion): Automatically send responses to a Notion database of your choice.
* [Slack](/xm-and-surveys/core-features/integrations/slack): Automatically send responses to a Slack channel of your choice on response events.
* [Wordpress](/xm-and-surveys/core-features/integrations/wordpress)(Open Source): Automatically integrate your Formbricks surveys with your Wordpress website.
* [Zapier](/xm-and-surveys/core-features/integrations/zapier): Connect Formbricks with 2000+ apps on Zapier.
***
If you have any questions or need help with any of the integrations or even want a new integration, please reach out to us on [Github Discussions](https://github.com/formbricks/formbricks/discussions).

View File

@@ -4,13 +4,8 @@ description:
"The slack integration allows you to automatically send responses to a Slack channel of your choice."
---
The slack integration allows you to automatically send responses to a Slack channel of your choice.
<Note>
If you are on a self-hosted instance, you will need to configure this
integration separately. Please follow the guides
[here](/self-hosting/configuration/integrations) to configure integrations on your
self-hosted instance.
If you are on a self-hosted instance, you will need to configure this integration separately. Please follow the guides [here](/self-hosting/configuration/integrations) to configure integrations on your self-hosted instance.
</Note>
## Formbricks Cloud
@@ -19,15 +14,15 @@ The slack integration allows you to automatically send responses to a Slack chan
![Formbricks Integrations Tab](/images/xm-and-surveys/core-features/integrations/slack/integrations-tab.webp)
2. Now click on the "Connect with Slack" button to authenticate yourself with Slack.
1. Now click on the "Connect with Slack" button to authenticate yourself with Slack.
![Connect Formbricks with your Slack Workspace](/images/xm-and-surveys/core-features/integrations/slack/connect-with-slack.webp)
3. You will now be taken to the Slack OAuth page where you can select the Slack channel you want to link with Formbricks and click on the "Allow" button.
1. You will now be taken to the Slack OAuth page where you can select the Slack channel you want to link with Formbricks and click on the "Allow" button.
![Slack OAuth Page](/images/xm-and-surveys/core-features/integrations/slack/slack-auth.webp)
4. Once you have selected the account and completed the authentication process, you will be taken back to Formbricks Cloud and see the connected status as below:
1. Once you have selected the account and completed the authentication process, you will be taken back to Formbricks Cloud and see the connected status as below:
![Formbricks is now connected with Slack](/images/xm-and-surveys/core-features/integrations/slack/slack-connected.webp)
@@ -36,7 +31,7 @@ The slack integration allows you to automatically send responses to a Slack chan
least one question and a Slack channel in the Slack workspace you integrated.
</Note>
5. In order to make your channel available in channel dropdown, you need to add formbricks integration bot to the channel you want to link. You can do this by going to channel settings -> Integrations -> Add apps -> Search for "Formbricks" -> Select the bot -> Add.
1. In order to make your channel available in channel dropdown, you need to add formbricks integration bot to the channel you want to link. You can do this by going to channel settings -> Integrations -> Add apps -> Search for "Formbricks" -> Select the bot -> Add.
![Click on three dot at top right of the channel](/images/xm-and-surveys/core-features/integrations/slack/add-slack-bot-1.webp)
@@ -46,20 +41,18 @@ The slack integration allows you to automatically send responses to a Slack chan
![Add Formbricks Bot](/images/xm-and-surveys/core-features/integrations/slack/add-slack-bot-4.webp)
6. Now click on the "Link channel" button to link a Slack channel with Formbricks and a modal will open up.
1. Now click on the "Link channel" button to link a Slack channel with Formbricks and a modal will open up.
![Link Formbricks with a Slack Channel](/images/xm-and-surveys/core-features/integrations/slack/link-survey-with-channel.webp)
7. Select the channel you want to link with Formbricks and the Survey. On doing so, you will be asked to select the questions' responses you want to feed in the Slack channel. Select the questions and click on the "Link Channel" button.
1. Select the channel you want to link with Formbricks and the Survey. On doing so, you will be asked to select the questions' responses you want to feed in the Slack channel. Select the questions and click on the "Link Channel" button.
![Select question to link with Slack Channel](/images/xm-and-surveys/core-features/integrations/slack/link-with-questions.webp)
8. On submitting, the modal will close and you will see the linked Slack channel in the list of linked Slack channels.
1. On submitting, the modal will close and you will see the linked Slack channel in the list of linked Slack channels.
![List of linked Slack Channels](/images/xm-and-surveys/core-features/integrations/slack/list-linked-surveys.webp)
Congratulations! You have successfully linked a Slack channel with Formbricks. Now whenever a response is submitted for the linked survey, it will be automatically sent to the linked Slack channel.
## Setup in self-hosted Formbricks
@@ -68,49 +61,62 @@ Enabling the Slack Integration in a self-hosted environment requires a setup usi
<Note>
If you are running Formbricks locally:
You need to use `https` instead of `http` for the redirect URI.
- You can update the `go` script in your `apps/web/package.json` to include the `--experimental-https` flag. The
command will look like: <br />
You need to use `https` instead of `http` for the redirect URI.
* You can update the `go` script in your `apps/web/package.json` to include the `--experimental-https` flag. The
command will look like: <br />
```bash
"go": next dev --experimental-https -p 3000
```
- You also need to update the .env file in the `apps/web` directory to include the `WEBAPP_URL` as `https://localhost:3000` instead of `http://localhost:3000`.
- You also need to run the terminal in admin mode to run the `go` script(to acquire the SSL certificate). You can do this by running the terminal as an administrator or using the `sudo` command in Unix-based systems.
* You also need to update the .env file in the `apps/web` directory to include the `WEBAPP_URL` as `https://localhost:3000` instead of `http://localhost:3000`.
* You also need to run the terminal in admin mode to run the `go` script(to acquire the SSL certificate). You can do this by running the terminal as an administrator or using the `sudo` command in Unix-based systems.
</Note>
1. Create a Slack workspace if you don't have one already.
2. Go to the [Your apps](https://api.slack.com/apps) page and **Create New App**.
3. Click on **From Scratch** and provide the **App Name** and select your workspace in **Pick a workspace to develop your app in:** dropdown. Click on **Create App**.
4. Go to the **OAuth & Permissions** tab on the sidebar and add the following **Bot Token Scopes**:
- `channels:read`
- `groups:read`
- `chat:write`
- `chat:write.public`
- `chat:write.customize`
* `channels:read`
* `groups:read`
* `chat:write`
* `chat:write.public`
* `chat:write.customize`
5. Add the **Redirect URLs** under **OAuth & Permissions** tab. You can add the following URLs:
- If you are running formbricks locally, you can enter `https://localhost:3000/api/v1/integrations/slack/callback`.
- Or, you can enter `https://<your-public-facing-url>/api/v1/integrations/slack/callback`
* If you are running formbricks locally, you can enter `https://localhost:3000/api/v1/integrations/slack/callback`.
* Or, you can enter `https://<your-public-facing-url>/api/v1/integrations/slack/callback`
6. Now, click on **Install to Workspace** and **Allow** the permissions.
7. Go to the **Basic Information** tab on the sidebar and copy the **Client ID** and **Client Secret**. Copy them and set them as the environment variables in your Formbricks instance as:
- `SLACK_CLIENT_ID` - OAuth Client ID
- `SLACK_CLIENT_SECRET` - OAuth Client Secret
* `SLACK_CLIENT_ID` - OAuth Client ID
8. Now, you need to enable the public distribution of your app. Go to the **Basic Information** tab and click on the **Manage distribution** button and click on the "Distribute App".
9. Scroll down to the **Share your app with other workspaces** section, complete the checklist and click on the **Activate public distribution** button.
* `SLACK_CLIENT_SECRET` - OAuth Client Secret
1. Now, you need to enable the public distribution of your app. Go to the **Basic Information** tab and click on the **Manage distribution** button and click on the "Distribute App".
2. Scroll down to the **Share your app with other workspaces** section, complete the checklist and click on the **Activate public distribution** button.
### By now, your environment variables should include the below ones:
- `SLACK_CLIENT_ID`
- `SLACK_CLIENT_SECRET`
* `SLACK_CLIENT_ID`
* `SLACK_CLIENT_SECRET`
Voila! You have successfully enabled the Slack integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Formbricks Cloud](#formbricks-cloud) section to link a Slack workspace with Formbricks.
@@ -119,10 +125,13 @@ Voila! You have successfully enabled the Slack integration in your self-hosted F
To remove the integration with Slack Workspace,
1. Visit the Integrations tab in your Formbricks Cloud dashboard.
2. Select "Manage" button in the Slack card.
3. Click on the "Delete Integration" button.
4. It will now ask for a confirmation to remove the integration. Click on the "Delete" button to remove the integration. You can always come back and connect again with the same Slack Workspace.
![Delete Slack Integration with Formbricks](/images/xm-and-surveys/core-features/integrations/slack/delete-connection.webp)
Still struggling or something not working as expected? [Join our Github Discussions](https://github.com/formbricks/formbricks/discussions) and we'd be glad to assist you!
Still struggling or something not working as expected? [Join our Github Discussions](https://github.com/formbricks/formbricks/discussions) and we'd be glad to assist you!

View File

@@ -1,9 +1,8 @@
---
title: "Webhooks"
description: "With webhooks, you can receive real-time HTTP notifications when specific objects change in your Formbricks environment. This allows you to stay updated and trigger automated actions based on these events."
---
With webhooks, you can receive real-time HTTP notifications when specific objects change in your Formbricks environment. This allows you to stay updated and trigger automated actions based on these events.
### **Webhook Triggers**
Webhooks are configured to send notifications based on trigger events. The available triggers include:

View File

@@ -4,16 +4,20 @@ description:
"Target specific visitors with a survey on your WordPress page using Formbricks for free. Show survey on specific page or on button click."
---
# Connect Formbricks with your WordPress page
To run a targeted survey on your WordPress website, Formbricks is the way to go!&#x20;
If you want to run a targeted survey on your WordPress website, Formbricks is the way to go! With our generous free plan and open source tech, you get everything you need to get started and keep full control over your data.
With our generous free plan and open source tech, you get everything you need to get started and keep full control over your data.
## TLDR
1. Install the Formbricks WordPress plugin
2. Create a [free Formbricks account](https://app.formbricks.com/auth/signup)
3. Find and copy the `environment id`
4. Copy the environment id into the right field in the plugin settings
5. Create survey on trigger “New Session” to test it
## Step 1: Install the Formbricks WordPress plugin
@@ -30,7 +34,6 @@ When you see this screen, youre there:
![Free HotJar survey alternative open source](/images/xm-and-surveys/core-features/integrations/wordpress/2-run-website-survey-wordpress-targeted-for-free.webp)
## Step 3: Find and copy the environmentId
Go to Settings > Setup Checklist where youll find your environmentId:
@@ -53,30 +56,28 @@ Great!
Now that all is setup, we create a survey to display an example survey. Create a survey and open survey editor.
Keep the content for now, click on the Settings tab:
![Free and open source HotJar survey on WordPress page](/images/xm-and-surveys/core-features/integrations/wordpress/4-wordpress-website-survey-target-visitor-free.webp)
Here we do three things:
1. Change survey type to **App Survey** or **Website Survey**(for public facing)
2. Select trigger “New Session”
3. Publish
![Open Source survey on targeted website wordpress](/images/xm-and-surveys/core-features/integrations/wordpress/6-targeted-survey-on-wordpress-website-for-free.webp)
When you see this page, you did it!
![Run free an open source targeted survey on any page](/images/xm-and-surveys/core-features/integrations/wordpress/7-wordpress-free-hotjar-survey-open-source-website-survey-hotjar.webp)
## Step 6: Reload your page to check out your survey 🤓
You did it! Reload the WordPress page and your survey should appear!
## Doesn't work?
If you have any questions or need help, feel free to reach out to us on **[Github Discussions](https://github.com/formbricks/formbricks/discussions)**
If you have any questions or need help, feel free to reach out to us on [Github Discussions](https://github.com/formbricks/formbricks/discussions)

View File

@@ -1,15 +1,10 @@
---
title: "Zapier"
description:
"Master the integration of Formbricks with Zapier using our detailed guide. Seamlessly connect your surveys to 5000+ apps, automate data transfers, and enhance feedback management. Start optimizing your workflow today."
description: "Master the integration of Formbricks with Zapier using our detailed guide. Seamlessly connect your surveys to 5000+ apps, automate data transfers, and enhance feedback management. Start optimizing your workflow today."
---
Zapier is a powerful ally. Hook up Formbricks with Zapier and you can send your data to 5000+ other apps. Here is how to do it.
<Note>
### Nail down your survey first? Any changes in the survey cause additional
work in the Zap. It makes sense to first settle on the survey you want to run
and then get to setting up Zapier.
Nail down your survey first? Any changes in the survey cause additional work in the Zap. It makes sense to first settle on the survey you want to run and then get to setting up Zapier.
</Note>
## Step 1: Setup your survey incl. `questionId` for every question
@@ -18,7 +13,7 @@ When setting up the Zap your life will be easier when you change the `questionId
![Update Question ID](/images/xm-and-surveys/core-features/integrations/zapier/update-question-id.webp)
_In every question card in the Advanced Settings you find the Question ID field. Update it so that youll recognize the response tied to this question._
*In every question card in the Advanced Settings you find the Question ID field. Update it so that youll recognize the response tied to this question.*
<Note>
Already published? Duplicate survey You can only update the questionId
@@ -29,7 +24,7 @@ _In every question card in the Advanced Settings you find the Question ID field.
## Step 2: Send a test response
In order to set up Zapier youll need a test response. This allows you to select the individual values of each response in your Zap.
In order to set up Zapier youll need a test response. This allows you to select the individual values of each response in your Zap.
![Submit Test Response](/images/xm-and-surveys/core-features/integrations/zapier/submit-test-response.webp)
@@ -51,7 +46,6 @@ Now, you have to connect Zapier with Formbricks via an API Key:
![Connect with Formbricks - 2](/images/xm-and-surveys/core-features/integrations/zapier/connect-with-formbricks-2.webp)
Now you need an API key. Please refer to the [API Key Setup](/api-reference/rest-api#how-to-generate-an-api-key) page to learn how to create one.
Once you copied it in the newly opened Zapier window, you will be connected:
@@ -70,7 +64,7 @@ Once you hit “Test” you will see the three most recent submissions for this
![Test Submission](/images/xm-and-surveys/core-features/integrations/zapier/test-submission.webp)
_Now you're happy that you updated the questionId's_
*Now you're happy that you updated the questionId's*
## Step 7: Set up your Zap
@@ -84,5 +78,4 @@ In the action itself we can determine the data and layout of the message. Here,
We now receive a notifcation in our Slack channel whenever a Churn survey is completed:
![Zapier Message](/images/xm-and-surveys/core-features/integrations/zapier/zapier-message.webp)
![Zapier Message](/images/xm-and-surveys/core-features/integrations/zapier/zapier-message.webp)

View File

@@ -0,0 +1,42 @@
---
title: "SAML SSO"
icon: "user-shield"
description: "How to set up SAML SSO for Formbricks"
---
<Note>This feature is only available with the Formbricks Enterprise plan having a SAML SSO add-on.</Note>
## Overview
Formbricks supports Security Assertion Markup Language (SAML) SSO. We prioritize your ease of access and security by providing robust Single Sign-On (SSO) capabilities.
### Setting up SAML login
<Steps>
<Step title='Create a SAML application with your Identity Provider (IdP)'>
Follow the instructions here - [SAML Setup](/development/guides/auth-and-provision/setup-saml-with-identity-providers)
</Step>
<Step title='Configure access to the IdP SAML app'>
Ensure that all users who need access to Formbricks have access to the IdP SAML
app.
</Step>
<Step title='Retrieve XML metadata from your IdP'>
Keep the XML metadata from your IdP accessible, as you will need it later.
</Step>
<Step title='Log in to your Organization Admin account'>
Visit `environments/<ENVIRONMENT_ID>/settings/sso`.
<img src='/images/xm-and-surveys/core-features/saml-sso/sso-settings.webp' />
</Step>
<Step title='Configure SSO with SAML'>
Click on the `Configure` button for `SSO with SAML`.
<img src='/images/xm-and-surveys/core-features/saml-sso/sso-settings-configure.webp' />
</Step>
<Step title='Paste the XML metadata and Save'>
In the SAML configuration section, copy and paste the XML metadata from step
3 and click on Save.
<img src='/images/xm-and-surveys/core-features/saml-sso/sso-settings-modal.webp' />
</Step>
<Step title='Your users can now log into Formbricks using SAML'>
Once setup is complete, provisioned users can log into Formbricks using SAML.
</Step>
</Steps>

View File

@@ -8,17 +8,11 @@ Experience Management is the practice of measuring and managing how a stakeholde
Historically, Experience Management has three steps:
1. **Gather**
1. **Gather** data
data
2. **Analyze** and report on the data
2. **Analyze**
and report on the data
3. **Integrate**
and automate to measure experiences at scale
3. **Integrate** and automate to measure experiences at scale
## Gather data
@@ -32,4 +26,4 @@ We're working on a fully compliant way to leverage AI to harvest insights from u
## Integrate & Automate
Experience Management scales best, when it is automated. Webhooks and the comprehensive REST API make it fast and easy to build integrations into your existing tech stack. Formbricks also powers integrations for n8n, ActivePieces, Zapier and Make.com to build any flow that you need.
Experience Management scales best, when it is automated. Webhooks and the comprehensive REST API make it fast and easy to build integrations into your existing tech stack. Formbricks also powers integrations for n8n, ActivePieces, Zapier and Make.com to build any flow that you need.

View File

@@ -123,7 +123,6 @@
"are_you_sure": "Bist Du sicher?",
"are_you_sure_this_action_cannot_be_undone": "Bist Du sicher? Diese Aktion kann nicht rückgängig gemacht werden.",
"attributes": "Attribute",
"automatic": "Automatisch",
"avatar": "Avatar",
"back": "Zurück",
"billing": "Abrechnung",
@@ -180,7 +179,6 @@
"edit": "Bearbeiten",
"email": "E-Mail",
"embed": "Einbetten",
"enable": "Aktivieren",
"enterprise_license": "Enterprise Lizenz",
"environment_not_found": "Umgebung nicht gefunden",
"environment_notice": "Du befindest dich derzeit in der {environment}-Umgebung.",
@@ -1835,8 +1833,7 @@
"multiple_industries": "Mehrere Branchen",
"use_this_template": "Vorlage verwenden",
"uses_branching_logic": "Diese Umfrage verwendet Logik."
},
"this_is_a_new_key": "Das ist ein neuer Schlüssel "
}
},
"xm-templates": {
"ces": "CES",

View File

@@ -123,7 +123,6 @@
"are_you_sure": "Are you sure?",
"are_you_sure_this_action_cannot_be_undone": "Are you sure? This action cannot be undone.",
"attributes": "Attributes",
"automatic": "Automatic",
"avatar": "Avatar",
"back": "Back",
"billing": "Billing",
@@ -180,7 +179,6 @@
"edit": "Edit",
"email": "Email",
"embed": "Embed",
"enable": "Enable",
"enterprise_license": "Enterprise License",
"environment_not_found": "Environment not found",
"environment_notice": "You're currently in the {environment} environment.",
@@ -1835,8 +1833,7 @@
"multiple_industries": "Multiple industries",
"use_this_template": "Use this template",
"uses_branching_logic": "This survey uses branching logic."
},
"this_is_a_new_key": "This is a updated key"
}
},
"xm-templates": {
"ces": "CES",

View File

@@ -123,7 +123,6 @@
"are_you_sure": "Es-tu sûr ?",
"are_you_sure_this_action_cannot_be_undone": "Êtes-vous sûr ? Cette action ne peut pas être annulée.",
"attributes": "Attributs",
"automatic": "Automatique",
"avatar": "Avatar",
"back": "Retour",
"billing": "Facturation",
@@ -180,7 +179,6 @@
"edit": "Modifier",
"email": "Email",
"embed": "Intégrer",
"enable": "Activer",
"enterprise_license": "Licence d'entreprise",
"environment_not_found": "Environnement non trouvé",
"environment_notice": "Vous êtes actuellement dans l'environnement {environment}.",
@@ -1835,8 +1833,7 @@
"multiple_industries": "Plusieurs secteurs",
"use_this_template": "Utilisez ce modèle",
"uses_branching_logic": "Cette enquête utilise une logique de branchement."
},
"this_is_a_new_key": "Ceci est une clé mise à jour"
}
},
"xm-templates": {
"ces": "CES",

View File

@@ -123,7 +123,6 @@
"are_you_sure": "Certeza?",
"are_you_sure_this_action_cannot_be_undone": "Tem certeza? Essa ação não pode ser desfeita.",
"attributes": "atributos",
"automatic": "Automático",
"avatar": "Avatar",
"back": "Voltar",
"billing": "Faturamento",
@@ -180,7 +179,6 @@
"edit": "Editar",
"email": "Email",
"embed": "incorporar",
"enable": "habilitar",
"enterprise_license": "Licença Empresarial",
"environment_not_found": "Ambiente não encontrado",
"environment_notice": "Você está atualmente no ambiente {environment}.",
@@ -1835,8 +1833,7 @@
"multiple_industries": "várias indústrias",
"use_this_template": "Use esse modelo",
"uses_branching_logic": "Essa pesquisa usa lógica de ramificação."
},
"this_is_a_new_key": "Esta é uma chave atualizada"
}
},
"xm-templates": {
"ces": "CES",

View File

@@ -123,7 +123,6 @@
"are_you_sure": "您確定嗎?",
"are_you_sure_this_action_cannot_be_undone": "您確定嗎?此操作無法復原。",
"attributes": "屬性",
"automatic": "自動",
"avatar": "頭像",
"back": "返回",
"billing": "帳單",
@@ -180,7 +179,6 @@
"edit": "編輯",
"email": "電子郵件",
"embed": "嵌入",
"enable": "啟用",
"enterprise_license": "企業授權",
"environment_not_found": "找不到環境",
"environment_notice": "您目前在 '{'environment'}' 環境中。",
@@ -1835,8 +1833,7 @@
"multiple_industries": "多個產業",
"use_this_template": "使用此範本",
"uses_branching_logic": "此問卷使用分支邏輯。"
},
"this_is_a_new_key": "這是一個更新的 key"
}
},
"xm-templates": {
"ces": "CES",

View File

@@ -19,6 +19,7 @@ export const ZPlacement = z.enum(["bottomLeft", "bottomRight", "topLeft", "topRi
export type TPlacement = z.infer<typeof ZPlacement>;
export const ZAllowedFileExtension = z.enum([
"heic",
"png",
"jpeg",
"jpg",

86
pnpm-lock.yaml generated
View File

@@ -387,6 +387,9 @@ importers:
googleapis:
specifier: 144.0.0
version: 144.0.0(encoding@0.1.13)
heic-convert:
specifier: 2.1.0
version: 2.1.0
https-proxy-agent:
specifier: 7.0.6
version: 7.0.6
@@ -520,6 +523,9 @@ importers:
'@types/bcryptjs':
specifier: 2.4.6
version: 2.4.6
'@types/heic-convert':
specifier: 2.1.0
version: 2.1.0
'@types/lodash':
specifier: 4.17.13
version: 4.17.13
@@ -591,7 +597,7 @@ importers:
version: 8.18.0(eslint@8.57.0)(typescript@5.7.2)
'@vercel/style-guide':
specifier: 6.0.0
version: 6.0.0(@next/eslint-plugin-next@15.1.0)(eslint@8.57.0)(prettier@3.4.2)(typescript@5.7.2)(vitest@3.0.5(tsx@4.19.2))
version: 6.0.0(@next/eslint-plugin-next@15.1.0)(eslint@8.57.0)(prettier@3.4.2)(typescript@5.7.2)(vitest@3.0.5(@types/debug@4.1.12)(@types/node@22.10.2)(jiti@2.4.1)(jsdom@25.0.1)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))
eslint-config-next:
specifier: 15.1.0
version: 15.1.0(eslint@8.57.0)(typescript@5.7.2)
@@ -5467,6 +5473,9 @@ packages:
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
'@types/heic-convert@2.1.0':
resolution: {integrity: sha512-Cf5Sdc2Gm2pfZ0uN1zjj35wcf3mF1lJCMIzws5OdJynrdMJRTIRUGa5LegbVg0hatzOPkH2uAf2JRjPYgl9apg==}
'@types/istanbul-lib-coverage@2.0.6':
resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
@@ -8359,8 +8368,8 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
hast-util-to-jsx-runtime@2.3.2:
resolution: {integrity: sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==}
hast-util-to-jsx-runtime@2.3.3:
resolution: {integrity: sha512-pdpkP8YD4v+qMKn2lnKSiJvZvb3FunDmFYQvVOsoO08+eTNWdaWKPMrC5wwNICtU3dQWHhElj5Sf5jPEnv4qJg==}
hast-util-whitespace@3.0.0:
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
@@ -8369,6 +8378,14 @@ packages:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
heic-convert@2.1.0:
resolution: {integrity: sha512-1qDuRvEHifTVAj3pFIgkqGgJIr0M3X7cxEPjEp0oG4mo8GFjq99DpCo8Eg3kg17Cy0MTjxpFdoBHOatj7ZVKtg==}
engines: {node: '>=12.0.0'}
heic-decode@2.0.0:
resolution: {integrity: sha512-NU+zsiDvdL+EebyTjrEqjkO2XYI7FgLhQzsbmO8dnnYce3S0PBSDm/ZyI4KpcGPXYEdb5W72vp/AQFuc4F8ASg==}
engines: {node: '>=8.0.0'}
help-me@3.0.0:
resolution: {integrity: sha512-hx73jClhyk910sidBB7ERlnhMlFsJJIBqSVMFDwPN8o2v9nmp5KgLq1Xz1Bf1fCMMZ6mPrX159iG0VLy/fPMtQ==}
@@ -8944,6 +8961,9 @@ packages:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
jpeg-js@0.4.4:
resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==}
js-cookie@2.2.1:
resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==}
@@ -9133,6 +9153,10 @@ packages:
engines: {node: '>=16'}
hasBin: true
libheif-js@1.18.2:
resolution: {integrity: sha512-4Nk0dKhhRfVS4mECcX2jSDpNU6gcHQLneJjkGQq61N8COGtjSpSA3CI+1Q3kUYv5Vf+SwIqUtaDSdU6JO37c6w==}
engines: {node: '>=8.0.0'}
lighthouse-logger@1.4.2:
resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==}
@@ -10478,6 +10502,10 @@ packages:
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
engines: {node: '>=10.13.0'}
pngjs@6.0.0:
resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==}
engines: {node: '>=12.13.0'}
polished@4.3.1:
resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==}
engines: {node: '>=10'}
@@ -10747,8 +10775,8 @@ packages:
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
property-information@6.5.0:
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
property-information@7.0.0:
resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
@@ -18841,6 +18869,8 @@ snapshots:
dependencies:
'@types/unist': 3.0.3
'@types/heic-convert@2.1.0': {}
'@types/istanbul-lib-coverage@2.0.6': {}
'@types/istanbul-lib-report@3.0.3':
@@ -19259,7 +19289,7 @@ snapshots:
next: 15.1.2(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
'@vercel/style-guide@6.0.0(@next/eslint-plugin-next@15.1.0)(eslint@8.57.0)(prettier@3.4.2)(typescript@5.7.2)(vitest@3.0.5(tsx@4.19.2))':
'@vercel/style-guide@6.0.0(@next/eslint-plugin-next@15.1.0)(eslint@8.57.0)(prettier@3.4.2)(typescript@5.7.2)(vitest@3.0.5(@types/debug@4.1.12)(@types/node@22.10.2)(jiti@2.4.1)(jsdom@25.0.1)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.26.0
'@babel/eslint-parser': 7.26.5(@babel/core@7.26.0)(eslint@8.57.0)
@@ -19267,7 +19297,7 @@ snapshots:
'@typescript-eslint/eslint-plugin': 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2)
'@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.7.2)
eslint-config-prettier: 9.1.0(eslint@8.57.0)
eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0))
eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.31.0)
eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0)
eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0)
@@ -19279,7 +19309,7 @@ snapshots:
eslint-plugin-testing-library: 6.5.0(eslint@8.57.0)(typescript@5.7.2)
eslint-plugin-tsdoc: 0.2.17
eslint-plugin-unicorn: 51.0.1(eslint@8.57.0)
eslint-plugin-vitest: 0.3.26(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2)(vitest@3.0.5(tsx@4.19.2))
eslint-plugin-vitest: 0.3.26(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2)(vitest@3.0.5(@types/debug@4.1.12)(@types/node@22.10.2)(jiti@2.4.1)(jsdom@25.0.1)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))
prettier-plugin-packagejson: 2.5.8(prettier@3.4.2)
optionalDependencies:
'@next/eslint-plugin-next': 15.1.0
@@ -19369,7 +19399,7 @@ snapshots:
optionalDependencies:
vite: 5.4.14(@types/node@22.10.2)(lightningcss@1.27.0)(terser@5.37.0)
'@vitest/mocker@3.0.5(vite@6.0.9(tsx@4.19.2))':
'@vitest/mocker@3.0.5(vite@6.0.9(@types/node@22.10.2)(jiti@2.4.1)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))':
dependencies:
'@vitest/spy': 3.0.5
estree-walker: 3.0.3
@@ -21378,9 +21408,9 @@ snapshots:
eslint: 8.57.0
eslint-plugin-turbo: 2.3.3(eslint@8.57.0)
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0)):
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0):
dependencies:
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0)
eslint-import-resolver-node@0.3.9:
dependencies:
@@ -21402,11 +21432,11 @@ snapshots:
is-glob: 4.0.3
stable-hash: 0.0.4
optionalDependencies:
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0)
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0):
eslint-module-utils@2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -21461,7 +21491,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0)
eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.0)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -21628,7 +21658,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-plugin-vitest@0.3.26(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2)(vitest@3.0.5(tsx@4.19.2)):
eslint-plugin-vitest@0.3.26(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2)(vitest@3.0.5(@types/debug@4.1.12)(@types/node@22.10.2)(jiti@2.4.1)(jsdom@25.0.1)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)):
dependencies:
'@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.7.2)
eslint: 8.57.0
@@ -22399,7 +22429,7 @@ snapshots:
dependencies:
function-bind: 1.1.2
hast-util-to-jsx-runtime@2.3.2:
hast-util-to-jsx-runtime@2.3.3:
dependencies:
'@types/estree': 1.0.6
'@types/hast': 3.0.4
@@ -22411,7 +22441,7 @@ snapshots:
mdast-util-mdx-expression: 2.0.1
mdast-util-mdx-jsx: 3.2.0
mdast-util-mdxjs-esm: 2.0.1
property-information: 6.5.0
property-information: 7.0.0
space-separated-tokens: 2.0.2
style-to-object: 1.0.8
unist-util-position: 5.0.0
@@ -22425,6 +22455,16 @@ snapshots:
he@1.2.0: {}
heic-convert@2.1.0:
dependencies:
heic-decode: 2.0.0
jpeg-js: 0.4.4
pngjs: 6.0.0
heic-decode@2.0.0:
dependencies:
libheif-js: 1.18.2
help-me@3.0.0:
dependencies:
glob: 7.2.3
@@ -23028,6 +23068,8 @@ snapshots:
joycon@3.1.1: {}
jpeg-js@0.4.4: {}
js-cookie@2.2.1: {}
js-sdsl@4.3.0: {}
@@ -23245,6 +23287,8 @@ snapshots:
dependencies:
isomorphic.js: 0.2.5
libheif-js@1.18.2: {}
lighthouse-logger@1.4.2:
dependencies:
debug: 2.6.9
@@ -24933,6 +24977,8 @@ snapshots:
pngjs@5.0.0: {}
pngjs@6.0.0: {}
polished@4.3.1:
dependencies:
'@babel/runtime': 7.26.7
@@ -25137,7 +25183,7 @@ snapshots:
object-assign: 4.1.1
react-is: 16.13.1
property-information@6.5.0: {}
property-information@7.0.0: {}
proxy-from-env@1.1.0: {}
@@ -25325,7 +25371,7 @@ snapshots:
'@types/hast': 3.0.4
'@types/react': 19.0.1
devlop: 1.1.0
hast-util-to-jsx-runtime: 2.3.2
hast-util-to-jsx-runtime: 2.3.3
html-url-attributes: 3.0.1
mdast-util-to-hast: 13.2.0
react: 19.0.0
@@ -27274,7 +27320,7 @@ snapshots:
vitest@3.0.5(@types/debug@4.1.12)(@types/node@22.10.2)(jiti@2.4.1)(jsdom@25.0.1)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0):
dependencies:
'@vitest/expect': 3.0.5
'@vitest/mocker': 3.0.5(vite@6.0.9(tsx@4.19.2))
'@vitest/mocker': 3.0.5(vite@6.0.9(@types/node@22.10.2)(jiti@2.4.1)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))
'@vitest/pretty-format': 3.0.5
'@vitest/runner': 3.0.5
'@vitest/snapshot': 3.0.5