Backend Overview
The Qlarr backend is a NestJS application providing REST APIs for survey management, execution, and data synchronization. It lives in the backend/ directory of the Qlarr monorepo.
Repository
qlarr-surveys/qlarr — the backend is the backend/ folder of the monorepo (alongside frontend/ and deploy/).
Role in the System
The backend is the central hub of the Qlarr ecosystem. It binds the same @qlarr/survey-engine build the web and Android renderers use, and exposes its capabilities via REST APIs. The Frontend communicates with it for both survey design and execution, and the Android app connects to it to download surveys and sync responses.
It is single-tenant: one database, one organization, with an admin seeded on first run.
Technology Stack
- NestJS 10 with TypeScript (Node.js 20+)
- TypeORM over PostgreSQL — survey settings, responses, user data (
synchronize: false; an in-process baseline migration owns the schema) @qlarr/survey-engine— the JavaScript build of the Survey Engine, run on Piscina worker threads so a runaway survey design can be timed out and killed without blocking the server- Passport JWT — stateless authentication (access + refresh tokens)
- Local-disk file storage (
LocalFileHelper) — survey resources, designs, and response files under{FILE_SYSTEM_ROOT_FOLDER}/{surveyId}/{folder}/{file}; theFileHelperinterface is the swap seam for other backends (e.g. object storage) - nodemailer — outbound email (leave
MAIL_HOSTempty to log instead of send)
Authentication
The backend uses stateless JWT-based authentication with refresh tokens.
Token Types
| Token | Expiration | Purpose |
|---|---|---|
| Access token | 1 hour | Sent in the Authorization: Bearer {token} header for API requests |
| Refresh token | 1 year | Stored in the database, used to obtain a new access token |
| Password reset token | 1 hour (30 days for new users) | Sent via email for password reset flow |
Expirations are configurable via JWT_ACTIVE_EXPIRATION_MS, JWT_REFRESH_EXPIRATION_MS, JWT_RESET_EXPIRATION_MS, and JWT_RESET_EXPIRATION_NEW_USERS_MS. Tokens are signed with HS256 (HMAC SHA-256) using the base64-decoded JWT_SECRET. The token contains the user email (sub), user ID, roles (authorities), and session ID as claims.
Auth Flow
- User logs in with email and password (
POST /user/login) - Backend validates credentials (bcrypt) and returns an access token + refresh token
- Client includes the access token in the
Authorization: Bearer {token}header for subsequent requests - When the access token expires, the client uses the refresh token to get a new one (
POST /user/refresh_token) — refresh tokens are not rotated - Logout (
POST /logout) invalidates the current session
Roles
- Super Admin — full system access, user management
- Survey Admin — survey management
- Surveyor — create and run surveys
- Analyst — analyze survey responses
Public Endpoints
The following endpoints do not require authentication:
- Survey execution (
/survey/{surveyId}/run/*) - Survey resources and attachments
- Login, password reset, and token refresh
A global JwtAuthGuard protects every route by default; the @Public() decorator opts a route out. Role-based access is enforced by a RolesGuard reading @Roles(...) metadata. Sensitive routes (login, forgot/confirm password) are additionally rate-limited.
API Endpoints
See the API Reference for the complete list of endpoints.