An AI-powered dashboard to analyze customer feedback sentiment, group themes, and generate reports. Built with NestJS for scalability and Mistral AI for NLP.
- Backend: NestJS (TypeScript)
- Database: PostgreSQL (Drizzle ORM)
- Auth: JWT + Redis (sessions/rate-limiting)
- AI: Mistral API (Sentiment Analysis + Topic Clustering)
- Validation: Zod + NestJS-Zod
- API Docs: Swagger
- Testing: Jest + Supertest
- Linting/Formatting: Biome
- File Processing: Multer (uploads), PapaParse (CSV)
- Monitoring: Prometheus + Grafana + Loki
- Deployment: Docker + Docker Compose
- CI/CD: GitHub Actions
- PDF Generation: PDF-lib
- CSV Export: JSON2CSV
- Real-time: Socket.IO
git clone https://github.com/Xayrulloh/Feedback-Sentiment.git && cd Feedback-SentimentDATABASE_URL='postgresql://<user>:<password>@localhost:5432/<database>'
PORT=XXXX
# JWT
JWT_SECRET=
# AI
OPENAI_API_KEY
# POSTGRES
POSTGRES_USER
POSTGRES_PASSWORD
POSTGRES_DB
POSTGRES_PORT
# Redis
REDIS_HOST
REDIS_PORTdocker compose up -d # Starts PostgreSQL + Redis
npx drizzle-kit push:pg # Apply DB schemapnpm run start:dev- http://localhost:${PORT}/${GLOBAL_PREFIX} server address
- http://localhost:${PORT}/${GLOBAL_PREFIX}/docs swagger docs
- CSV/text feedbacks input โ AI Processing โ Stored in PostgreSQL.
- Mistral API tags sentiment โ Groups similar feedback via NLP -> Tells confidence
- Filter by sentiment, group themes, download reports, bar charts.
- Get users -> Disable users -> Suspend users ->
- Get suspicious activity (Registration/Upload/Download/API)
- Rate limit (API/Upload/Download/Login)
Path: POST /auth/(register|login)
Flow Register/Login:
sequenceDiagram
Frontend->>+Backend: POST /auth/register {email, password}
Backend->>+UserStatusGuard: Check suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>+Websocket: Active users
Backend->>+Backend: Zod Validation
Backend->>+DB: Checking email and password
alt Not valid
DB-->>-Backend: Error (Incorrect password or Email exist)
Backend-->>-Frontend: 409 | 401
else Valid
Backend->>DB: Hash password, save user (role=user)
Backend->>Frontend: 201 + JWT
end
Path: POST /auth/(register|login)/admin
Flow Register/Login:
sequenceDiagram
Frontend->>+Backend: POST /auth/register {email, password}
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>+Websocket: Active users
Backend->>+Backend: Zod Validation
Backend->>+DB: Checking email and password
alt Not valid
DB-->>-Backend: Error (Incorrect password or Email exist)
Backend-->>-Frontend: 409 | 401
else Valid
Backend->>DB: Hash password, save user (role=user)
Backend->>Frontend: 201 + JWT
end
Path: POST /feedback/manual
Flow:
sequenceDiagram
Frontend->>+Backend: POST /feedback/manual (array of feedbacks)
Backend->>+UserStatusGuard: Check suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>DB: Check whether it's already exist or not
alt Exist
DB-->>-Backend: Get that feedbacks
Backend-->>-Frontend: 201
else Create
Backend->>+AIService: Analyze (confidence/sentiment/group)
AIService->>+DB: Create new one and return
DB-->>-AIService: Success
AIService-->>-Backend: Processed
Backend-->>-Frontend: 201
end
Path: POST /feedback/upload
Flow:
sequenceDiagram
Frontend->>+Backend: POST /feedback/upload (file which has array of feedbacks)
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Parsing and Zod Validation
Backend->>+FeedbackManual: Same happens with manual with the rest
Backend-->>-Frontend: 201 Created with results
Path: GET /feedback/:id
Flow:
sequenceDiagram
Frontend->>+Backend: GET /feedback/:id
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+DB: Get feedback by id
DB-->>-Backend: Feedback
Backend-->>-Frontend: 200
Path: GET /feedback
Flow:
sequenceDiagram
Frontend->>+Backend: GET /feedback?sentiment=positive,negative
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+DB: Query with Sentiment Filters
DB-->>-Backend: Filtered Results
Backend-->>-Frontend: 200 (Paginated Data)
Path: GET /feedback/sentiment-summary
Flow:
sequenceDiagram
Frontend->>+Backend: GET /feedback/sentiment-summary
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+DB: Query with userId
DB-->>-Backend: Grouped Results
Backend-->>-Frontend: 200
Path: GET /feedback/grouped
Flow:
sequenceDiagram
Frontend->>+Backend: GET /feedback/grouped
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+DB: Query with userId
DB-->>-Backend: Grouped by summary
Backend-->>-Frontend: 200
Path: GET /feedback/report
Flow:
sequenceDiagram
Frontend->>+Backend: GET /feedback/report
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+DB: Fetch all feedback
DB-->>-Backend: Raw data
alt PDF Format
Backend->>+PDF-lib: Generate PDF
PDF-lib-->>-Backend: PDF buffer
else CSV Format
Backend->>+json2csv: Convert to CSV
json2csv-->>-Backend: CSV string
end
Backend-->>-Frontend: File download
Path: GET /files
Flow:
sequenceDiagram
Frontend->>+Backend: GET /files
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+DB: Fetch all user files (Paginated)
DB-->>-Backend: Files
Backend-->>-Frontend: 200
Path: DELETE /files/:id
Flow:
sequenceDiagram
Frontend->>+Backend: DELETE /files/:id
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+DB: Delete file
DB-->>-Backend: Deleted
Backend-->>-Frontend: 200
Path: GET /users
Flow:
sequenceDiagram
Frontend->>+Backend: GET /users
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+DB: Fetch all users (Paginated)
DB-->>-Backend: Users
Backend-->>-Frontend: 200
Path: GET /users/search
Flow:
sequenceDiagram
Frontend->>+Backend: GET /users/search?email=example
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+DB: Search users by email
DB-->>-Backend: Users (limit 5)
Backend-->>-Frontend: 200
Path: POST /admin/disable/:userId
Flow:
sequenceDiagram
Frontend->>+Backend: POST /admin/disable/:userId
Backend->>+Backend: Check the user is admin
Backend->>+DB: Disable user
DB-->>-Backend: Disabled
Backend-->>-Frontend: 200
Path: POST /admin/suspend/:userId
Flow:
sequenceDiagram
Frontend->>+Backend: POST /admin/suspend/:userId
Backend->>+Backend: Check the user is admin
Backend->>+DB: Suspend user | Enable user
DB-->>-Backend: Suspended | Enabled
Backend-->>-Frontend: 200
Path: GET /admin/metrics
Flow:
sequenceDiagram
Frontend->>+Backend: GET /admin/metrics
Backend->>+Backend: Check the user is admin
Backend->>+DB: Take metrics (uploads, api usage, error rates)
DB-->>-Backend: Metrics
Backend-->>-Frontend: 200
Path: GET /admin/rate-limit
Flow:
sequenceDiagram
Frontend->>+Backend: GET /admin/rate-limit
Backend->>+Backend: Check the user is admin
Backend->>+DB: Take rate limits (api, upload, download, login)
DB-->>-Backend: RateLimits
Backend-->>-Frontend: 200
Path: PATCH /admin/rate-limit
Flow:
sequenceDiagram
Frontend->>+Backend: PATCH /admin/rate-limit
Backend->>+Backend: Check the user is admin
Backend->>+DB: Path rate limits (api, upload, download, login)
DB-->>-Backend: RateLimits
Backend-->>-Frontend: 200
Path: GET /admin/suspicious-activities
Flow:
sequenceDiagram
Frontend->>+Backend: GET /admin/suspicious-activities
Backend->>+Backend: Check the user is admin
Backend->>+DB: Take suspicious activities
DB-->>-Backend: SuspiciousActivities
Backend-->>-Frontend: 200
Path: POST /sample/feedback/manual
Flow:
sequenceDiagram
Frontend->>+Backend: POST /sample/feedback-manual (array of feedbacks)
Backend->>+UserStatusGuard: Check suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>MockData: Mock feedbacks
Backend-->>-Frontend: 201
Path: GET /sample/feedback/:id
Flow:
sequenceDiagram
Frontend->>+Backend: GET /sample/feedback-:id
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+MockData: Mock Feedback
Backend-->>-Frontend: 200
Path: GET /feedback
Flow:
sequenceDiagram
Frontend->>+Backend: GET /feedback?sentiment=positive,negative
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+MockData: Mock Feedback
Backend-->>-Frontend: 200 (Paginated Data)
Path: GET /sample/feedback-sentiment-summary
Flow:
sequenceDiagram
Frontend->>+Backend: GET /sample/feedback-sentiment-summary
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+MockData: Mock Feedback
Backend-->>-Frontend: 200
Path: GET /sample/feedback-grouped
Flow:
sequenceDiagram
Frontend->>+Backend: GET /sample/feedback-grouped
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+MockData: Mock Feedback
Backend-->>-Frontend: 200
Path: GET /sample/feedback-report
Flow:
sequenceDiagram
Frontend->>+Backend: GET /sample/feedback-report
Backend->>+UserStatusGuard: Check if user suspended/disabled
Backend->>+RateLimitGuard: Check user rate limits and increment (create activity in suspicious table)
RateLimitGuard->>+Websocket: Send admins if user hits limits
Backend->>+MetricsMiddleware: (Api Usage, Error Rates, Uploads)
Backend->>Backend: Zod Validation
Backend->>+MockData: Mock Feedback
Backend-->>-Frontend: File download
erDiagram
users ||--o{ users_feedbacks : "1:N"
users ||--o{ files : "1:N"
users ||--o{ suspicious_activity : "1:N"
feedbacks ||--o{ users_feedbacks : "1:N"
files ||--o{ users_feedbacks : "1:N"
users {
string id PK "uuid"
string email "unique"
string password_hash
enum role "user|admin"
boolean is_suspended
timestamp created_at
timestamp updated_at
timestamp deleted_at "nullable"
}
feedbacks {
string id PK "uuid"
string content_hash "unique, sha256"
text content
enum sentiment "positive|neutral|negative|unknown"
integer confidence "0-100"
text summary "AI-generated"
timestamp created_at
timestamp updated_at
timestamp deleted_at "nullable"
}
users_feedbacks {
string user_id FK,PK
string feedback_id FK,PK
string file_id FK "nullable"
timestamp created_at
}
files {
string id PK "uuid"
string user_id FK
string name
string mime_type
bigint size "bytes"
integer row_count "nullable"
string extension
timestamp created_at
timestamp updated_at
timestamp deleted_at "nullable"
}
rate_limits {
string id PK "uuid"
enum target "api|upload|download|login"
integer limit
timestamp created_at
timestamp updated_at
timestamp deleted_at "nullable"
}
suspicious_activity {
string id PK "uuid"
string user_id FK "nullable"
string email "nullable"
string ip "nullable"
enum action "api|upload|download|login"
enum error "too_many_*"
text details "nullable"
timestamp created_at
timestamp updated_at
timestamp deleted_at "nullable"
}