Crisp-DB is a full-stack application consisting of a React frontend and a Node.js/Express backend. The backend provides a RESTful API for managing companies, plans, conversations, messages, knowledge bases, and related entities in a MongoDB database. The frontend offers a user interface for interacting with the API.
- Authentication: JWT-based login for users.
- Company Management: Create companies, send invites to employees, and accept invites.
- Plan Management: Create, update, deactivate, and delete subscription plans; retrieve active plans and plan details.
- Super Admin Management: Manage companies, plans, and system-level operations.
- System Bootstrap: Create super admin and super company for initial setup.
- Database Models: Support for companies, users, conversations, messages, knowledge bases, plans, API keys, invites, token usage, and visitors (models defined, but not all routes implemented).
- Middleware: Authentication, file upload, and bootstrap secret verification.
- CORS Support: Cross-origin resource sharing enabled.
- File Uploads: Support for image and file uploads via Multer and Cloudinary.
- User Dashboard: Interactive dashboard for managing conversations and messages.
- Pricing Page: Display subscription plans and features.
- Authentication: Login and signup forms with Redux state management.
- Integration Showcase: Pages for app integrations and mediator apps.
- Help Center: FAQ and support articles.
- Responsive Design: Bootstrap-based responsive UI with animations using GSAP.
-
Navigate to the backend directory:
cd backend -
Install dependencies:
npm install -
Set up environment variables:
- Copy
.envand update the values as needed. - Ensure MongoDB URI, PORT, JWT_SECRET, and CORS_ORIGIN are configured.
- Copy
-
Start the development server:
npm run devOr format code:
npm run format
The server will run on the port specified in .env (default: 3000).
-
Navigate to the Frontend directory:
cd Frontend -
Install dependencies:
npm install -
Start the development server:
npm start
The frontend will run on http://localhost:3001 (React default port, or next available port).
To run both backend and frontend simultaneously:
-
Start the backend server in one terminal:
cd backend && npm run dev -
Start the frontend in another terminal:
cd Frontend && npm start
The API is structured around RESTful endpoints. Use tools like Postman or curl to interact with the endpoints.
http://localhost:3000
-
POST /api/v1/auth/login- User login- Request Body:
{ "email": "string", "password": "string" } - Response:
{ "success": boolean, "message": "string", "data": { "user": object, "accessToken": "string", "refreshToken": "string" } }
- Request Body:
-
POST /api/v1/auth/forget-password- Forget password- Request Body:
{ "email": "string" } - Response:
{ "success": boolean, "message": "string" }
- Request Body:
-
POST /api/v1/company/create-company- Create a new company- Request Body:
{ "companyName": "string", "adminEmail": "string", "adminPassword": "string", "phone": { "countryCode": "string", "number": "string" } } - Response:
{ "success": boolean, "message": "string", "data": { "company": object, "admin": object } }
- Request Body:
-
POST /api/v1/company/send-invite- Send invite to employee (requires authentication)- Headers:
Authorization: Bearer <token> - Request Body:
{ "email": "string", "role": "string" } - Response:
{ "success": boolean, "message": "string", "data": { "invite": object } }
- Headers:
-
GET /api/v1/company/plans/active- Get active plans (requires authentication)- Headers:
Authorization: Bearer <token> - Response:
{ "success": boolean, "message": "string", "data": { "plans": array } }
- Headers:
-
GET /api/v1/company/plans/by-id- Get plan by id (query param: ?id=)- Query Params:
id=<planId> - Response:
{ "success": boolean, "message": "string", "data": { "plan": object } }
- Query Params:
-
GET /api/v1/company/api-key- Get All Company ApiKey (requires authentication)- Headers:
Authorization: Bearer <token> - Response:
{ "success": boolean, "message": "string", "data": { "apiKeys": array } }
- Headers:
-
POST /api/v1/company/recharge-plans- Update plans (requires authentication)- Headers:
Authorization: Bearer <token> - Request Body:
{ "planId": "string" } - Response:
{ "success": boolean, "message": "string", "data": { "updatedCompany": object } }
- Headers:
-
GET /api/v1/company/employee-info- Get Employees Details (requires authentication)- Headers:
Authorization: Bearer <token> - Response:
{ "success": boolean, "message": "string", "data": { "employees": array } }
- Headers:
POST /api/v1/employee/accept-invite- Accept invite and sign up employee- Request Body:
{ "token": "string", "password": "string", "username": "string", "phone": { "countryCode": "string", "number": "string" } } - Response:
{ "success": boolean, "message": "string", "data": { "user": object, "accessToken": "string", "refreshToken": "string" } }
- Request Body:
-
POST /api/v1/superadmin/plans- Create new plan (requires authentication)- Headers:
Authorization: Bearer <token> - Request Body:
{ "name": "string", "description": "string", "price": number, "features": array } - Response:
{ "success": boolean, "message": "string", "data": { "plan": object } }
- Headers:
-
PUT /api/v1/superadmin/plans/:planId- Update existing plan (requires authentication)- Headers:
Authorization: Bearer <token> - Request Body:
{ "name": "string", "description": "string", "price": number, "features": array } - Response:
{ "success": boolean, "message": "string", "data": { "plan": object } }
- Headers:
-
PATCH /api/v1/superadmin/plans/:planId/deactivate- Deactivate a plan (requires authentication)- Headers:
Authorization: Bearer <token> - Response:
{ "success": boolean, "message": "string", "data": { "plan": object } }
- Headers:
-
DELETE /api/v1/superadmin/plans/:planId- Delete plan (requires authentication)- Headers:
Authorization: Bearer <token> - Response:
{ "success": boolean, "message": "string" }
- Headers:
-
GET /api/v1/superadmin/plans/active- Get all active plans (requires authentication)- Headers:
Authorization: Bearer <token> - Response:
{ "success": boolean, "message": "string", "data": { "plans": array } }
- Headers:
-
GET /api/v1/superadmin/plans/by-id- Get plan by id (query param: ?id=)- Query Params:
id=<planId> - Response:
{ "success": boolean, "message": "string", "data": { "plan": object } }
- Query Params:
-
GET /api/v1/superadmin/view-all-companies- View all active companies (requires authentication)- Headers:
Authorization: Bearer <token> - Response:
{ "success": boolean, "message": "string", "data": { "companies": array } }
- Headers:
-
POST /api/v1/system/create-super-company- Create super company (requires bootstrap secret)- Headers:
x-bootstrap-secret: <secret> - Request Body:
{ "companyName": "string", "adminEmail": "string", "adminPassword": "string", "phone": { "countryCode": "string", "number": "string" } } - Response:
{ "success": boolean, "message": "string", "data": { "company": object, "admin": object } }
- Headers:
-
POST /api/v1/system/create-super-admin- Create super admin (requires bootstrap secret)- Headers:
x-bootstrap-secret: <secret> - Request Body:
{ "email": "string", "password": "string", "username": "string", "phone": { "countryCode": "string", "number": "string" } } - Response:
{ "success": boolean, "message": "string", "data": { "admin": object } }
- Headers:
-
DELETE /api/v1/system/delete-super-admin- Delete super admin (requires bootstrap secret)- Headers:
x-bootstrap-secret: <secret> - Response:
{ "success": boolean, "message": "string" }
- Headers:
crisp-db/
├── backend/
│ ├── src/
│ │ ├── config/ # Configuration files
│ │ ├── constants/ # Application constants
│ │ ├── controllers/ # Route controllers
│ │ │ ├── auth.controller.js
│ │ │ ├── bootstrap/
│ │ │ │ ├── superAdmin.service.js
│ │ │ │ └── SuperCompany.service.js
│ │ │ ├── Company/
│ │ │ │ └── create_company.controller.js
│ │ │ └── invite/
│ │ │ ├── acceptInvite.controller.js
│ │ │ └── inviteEmployee.controller.js
│ │ ├── db/ # Database connection
│ │ │ └── db.js
│ │ ├── middlewares/ # Custom middlewares
│ │ │ ├── Auth.middleware.js
│ │ │ ├── uploadFile.middleware.js
│ │ │ └── verifyBootstrapSecret.middleware.js
│ │ ├── models/ # Mongoose models
│ │ │ ├── ApiKey.model.js
│ │ │ ├── Company.model.js
│ │ │ ├── CompanyUser.model.js
│ │ │ ├── Conversation.model.js
│ │ │ ├── Invite.model.js
│ │ │ ├── KnowledgeBase.model.js
│ │ │ ├── Message.model.js
│ │ │ ├── Plan.model.js
│ │ │ ├── PlanFeature.model.js
│ │ │ ├── TokenUsage.model.js
│ │ │ └── Visitors.model.js
│ │ ├── routes/ # API routes
│ │ │ ├── auth.route.js
│ │ │ ├── company.route.js
│ │ │ └── system.route.js
│ │ ├── utils/ # Utility functions
│ │ │ ├── ApiError.util.js
│ │ │ ├── ApiResponse.util.js
│ │ │ ├── AsyncHandler.util.js
│ │ │ └── Cloudinary.util.js
│ │ ├── app.js # Express app setup
│ │ └── index.js # Main entry point
│ ├── public/ # Static files
│ ├── .gitignore
│ ├── .prettierignore
│ ├── .prettierrc
│ ├── package.json
│ ├── package-lock.json
│ └── README.md # Backend README
├── Frontend/
│ ├── public/
│ │ ├── index.html # Main HTML file
│ │ ├── manifest.json # PWA manifest
│ │ ├── robots.txt # SEO robots file
│ ├── src/
│ │ ├── assets/ # Static assets (images, icons)
│ │ │ ├── app/ # App-related images
│ │ │ ├── footer/ # Footer images
│ │ │ ├── form/ # Form-related assets
│ │ │ ├── furtherMenu/ # Menu assets
│ │ │ ├── help/ # Help section images
│ │ │ ├── home/ # Home page images
│ │ │ ├── integration/ # Integration images
│ │ │ ├── mediatorApps/ # Mediator app icons
│ │ │ ├── pricing/ # Pricing page images
│ │ │ └── widgets/ # Widget images
│ │ ├── Components/ # React components
│ │ │ ├── apps/ # App-related components
│ │ │ ├── Dashboard/ # Dashboard components
│ │ │ ├── footer/ # Footer component
│ │ │ ├── furtherMenu/ # Additional menu components
│ │ │ ├── head/ # Header components
│ │ │ ├── help/ # Help center components
│ │ │ ├── integration/ # Integration components
│ │ │ ├── main-container/ # Main page components
│ │ │ ├── Pricing/ # Pricing components
│ │ │ └── signUp_Login/ # Authentication components
│ │ ├── routing/ # Routing configuration
│ │ │ └── routing.js # App routes
│ │ ├── store/ # Redux store
│ │ │ ├── authSlice.js # Authentication state
│ │ │ ├── loginSlice.js # Login state
│ │ │ └── store.js # Store configuration
│ │ ├── App.css # Main app styles
│ │ ├── App.js # Main app component
│ │ ├── index.css # Global styles
│ │ └── index.js # App entry point
│ ├── .gitignore
│ ├── package.json
│ ├── package-lock.json
│ └── README.md # Frontend README (Create React App default)
├── images/ # Shared images
└── README.md # Main project README
MONGODB_URI: MongoDB connection string (e.g.,mongodb://localhost:27017)PORT: Server port (default: 3000)ACCESS_TOKEN_SECRET: Secret key for JWT access tokensREFRESH_TOKEN_SECRET: Secret key for JWT refresh tokensACCESS_TOKEN_EXPIRY: Access token expiry (e.g.,15m)REFRESH_TOKEN_EXPIRY: Refresh token expiry (e.g.,7d)ACCESS_COOKIE_MAX_AGE: Access cookie max age in millisecondsREFRESH_COOKIE_MAX_AGE: Refresh cookie max age in millisecondsCORS_ORIGIN: Allowed CORS origins (e.g.,http://localhost:3001)EMAIL_USER: Email address for sending emailsEMAIL_PASS: Email password or app passwordCLOUDINARY_CLOUD_NAME: Cloudinary cloud name (for file uploads)CLOUDINARY_API_KEY: Cloudinary API keyCLOUDINARY_API_SECRET: Cloudinary API secret
REACT_APP_API_BASE_URL: Backend API base URL (default:http://localhost:3000)REACT_APP_SOCKET_URL: Socket.IO server URL (default:http://localhost:3000)
express: Web framework for Node.jsmongoose: MongoDB object modelingmongoose-aggregate-paginate-v2: Pagination plugin for Mongoosebcryptjs: Password hashingjsonwebtoken: JWT token handlingcookie-parser: Cookie parsing middlewarecors: Cross-origin resource sharingdotenv: Environment variable managementmulter: File upload handlingcloudinary: Cloud image storageaxios: HTTP clientmoment: Date manipulationsocket.io-client: WebSocket clientcrypto: Cryptographic functionsnodemon: Development server (dev dependency)prettier: Code formatter (dev dependency)
react: Frontend libraryreact-dom: React DOM renderingreact-router-dom: Routing for Reactredux: State management@reduxjs/toolkit: Redux toolkit for efficient Redux developmentaxios: HTTP client for API callsbootstrap: CSS frameworkreact-bootstrap: Bootstrap components for Reactreact-icons: Icon librarygsap: Animation libraryreact-scripts: Build scripts for Reactweb-vitals: Performance monitoring
The application uses Socket.IO for real-time communication between employees and visitors, similar to Crisp.
- Format:
company_<companyId> - Purpose: All employees of the same company join this room automatically when they connect
- Events:
employee:connected- When an employee connectsemployee:disconnected- When an employee disconnectsvisitor:connected- When a new visitor connects (notifies all employees)visitor:disconnected- When a visitor disconnects
- Format:
visitor_<visitorSessionId> - Purpose: Each visitor has their own room. Employees can join to chat with specific visitors
- Events:
visitor:connected- Visitor successfully connectedemployee:joined-room- Employee joined the visitor's roomemployee:left-room- Employee left the visitor's roommessage:received- New message in the room
Client → Server:
joinCompanyRoom- Join company room (automatic on connection)joinVisitorRoom- Join a specific visitor room to chatleaveVisitorRoom- Leave a visitor roomemployee:waiting- Request list of waiting visitorssendMessage- Send a message to a roomtyping- Indicate typing in a roomstopTyping- Stop typing indicator
Server → Client:
employee:connected- Employee successfully connectedemployee:disconnected- Employee disconnectedemployee:joined-room-success- Successfully joined visitor roomemployee:left-room-success- Successfully left visitor roomemployee:waiting-rooms- List of waiting visitorsvisitor:connected- New visitor connected (broadcast to company room)visitor:disconnected- Visitor disconnected (broadcast to company room)message:received- New message received
Client → Server:
frontend:verify-response- Send verification data (API key, session ID, etc.)visitor:hello- Reconnection attemptsendMessage- Send a messagetyping- Indicate typingstopTyping- Stop typing indicator
Server → Client:
backend:verify-request- Server requests verificationverify:failed- Verification failedvisitor:connected- Visitor successfully connectedemployee:joined-room- Employee joined the roomemployee:left-room- Employee left the roommessage:received- New message received
-
Visitor Connection:
- Visitor connects → Server requests verification
- Visitor sends API key and session ID
- Server validates, creates/finds visitor and chat room
- Visitor joins
visitor_<sessionId>room - Company room receives
visitor:connectedevent
-
Employee Connection:
- Employee connects with valid JWT token
- Automatically joins
company_<companyId>room - Company room receives
employee:connectedevent - Employee can request waiting visitors list
-
Employee → Visitor Chat:
- Employee clicks on a visitor
- Employee emits
joinVisitorRoomwithvisitorSessionId - Server verifies access and joins employee to visitor room
- Both can now exchange messages in that room
-
Message Flow:
- Either party emits
sendMessagewith{ roomId, message, sender } - Server validates access, saves to database
- Broadcasts
message:receivedto all in the room
- Either party emits
- Authentication: Employees authenticated via JWT tokens in cookies
- Authorization: Employees can only access visitors from their company
- Room Isolation: Messages are scoped to specific rooms, preventing cross-room leakage
- Visitor Verification: Visitors must provide valid API key matching their company
backend/src/socket/
├── index.js # Main socket initialization
├── rooms.js # Room utility functions
├── handlers/
│ ├── companyHandler.js # Employee/company room handlers
│ ├── visitorHandler.js # Visitor room handlers
│ └── messageHandler.js # Message handlers
├── agent.socket.js # Legacy employee handlers (for compatibility)
└── visitor.socket.js # Legacy visitor handlers (for compatibility)
- ✅ Fixed
react-scriptsversion (was^0.0.0, now5.0.1) - ✅ Fixed React version compatibility (downgraded from 19.0.0 to 18.3.1)
- ✅ Fixed
react-router-dombreaking changes (downgraded from v7 to v6) - ✅ Fixed hardcoded API URLs (now uses proxy and relative URLs)
- ✅ Fixed socket URL configuration (now uses environment variables)
- ✅ Added missing
startscript to package.json - ✅ Fixed CORS configuration (now uses environment variable with fallback)
- ✅ Fixed port configuration (default 3000, not 5000)
- ✅ Fixed socket authentication middleware
- ✅ Added missing OTP verification and reset password endpoints
- ✅ Fixed JWT field name inconsistencies (
companyIdvscompany_id)
- ✅ Implemented proper company room structure (
company_<companyId>) - ✅ Implemented proper visitor room structure (
visitor_<visitorSessionId>) - ✅ Created modular socket handler structure
- ✅ Fixed room joining logic for employees
- ✅ Fixed visitor verification flow
- ✅ Implemented proper message broadcasting
- ✅ Added typing indicators
- ✅ Fixed employee/visitor disconnection handling
- Fork the repository.
- Create a feature branch.
- Make your changes.
- Test thoroughly.
- Submit a pull request.
ISC License