Monorepo with a Next.js 14 (App Router) frontend and Express + MongoDB backend: JWT authentication, multi-file uploads with optional webhook notification, a dashboard with upload + Artemis records search (saved screening/case data), and a hidden internal page for Artemis CRUD (any signed-in user).
- Node.js 18+
- MongoDB (local or Atlas)
-
Install dependencies
npm install npm install --prefix backend npm install --prefix frontend
-
Environment files
- Copy
backend/.env.example→backend/.envand set variables (see below). - Copy
frontend/.env.example→frontend/.env.localand setNEXT_PUBLIC_API_URL(defaulthttp://localhost:4000).
- Copy
-
Run MongoDB and ensure
MONGODB_URIinbackend/.envpoints to your database. -
Seed default user + sample Artemis rows (optional but recommended for demos):
npm run seed --prefix backend
Creates
user@artemis.com/user123and two sample Artemis records (one individual, one corporate). Re-running replaces those rows if the samecaseIdvalues already exist. -
Start both apps from the repository root:
npm run dev
- Frontend: http://localhost:3000
- API: http://localhost:4000
npm run dev:backend
npm run dev:frontend| Variable | Description |
|---|---|
PORT |
API port (default 4000) |
MONGODB_URI |
MongoDB connection string |
JWT_SECRET |
Secret for signing JWTs |
JWT_EXPIRES_IN |
JWT lifetime (e.g. 7d) |
WEBHOOK_URL |
URL for POST webhook after file upload (optional; skipped if empty) |
CORS_ORIGIN |
Allowed browser origin (e.g. http://localhost:3000) |
| Variable | Description |
|---|---|
NEXT_PUBLIC_API_URL |
API base URL without /api suffix (e.g. http://localhost:4000) |
- Register and login; passwords hashed with bcrypt.
- JWT stored in
localStorageand sent asAuthorization: Bearer <token>. - Protected API routes use JWT middleware; the app redirects unauthenticated users to
/login. Failed authenticated calls clear the session and return to login.
Protected endpoints under /api/users (requires JWT):
GET /api/users/me— current user profileGET /api/users— list usersGET /api/users/:id— get userPOST /api/users— create user (with password)PATCH /api/users/:id— update user (optionalpasswordin body)DELETE /api/users/:id— delete user
Two tabs:
-
File upload — PDF and
.xlsxonly; drag-and-drop or browse. Users enter a recipient email (where the screening outcome should go); the API includes it in the upload payload and, if configured, in the optionalWEBHOOK_URLPOST. Multipart fields:notificationEmail,files. Files land underbackend/public/uploads/{userId}/. -
Artemis viewer — Debounced search across the entire document: every nested key name and value (metadata, entity blocks, risk JSON, approval lines, etc.) is flattened into
_searchText. After upgrading, runnpm run reindex-search --prefix backendonce so existing rows pick up the new index. Sortable table with many columns, horizontal scroll, pagination; row click still opens the drawer for full JSON.
Hidden Artemis CRUD (internal)
- Frontend URL (not in navigation):
/internal/artemis-admin - API base path:
/api/internal/artemis— same JWT as the rest of the app (no separate admin secret). - Endpoints:
GET /(list),GET /:id,POST /,PUT /:id,DELETE /:id.
Anyone who can sign in can open the hidden URL; “hidden” only means it is not linked in the UI.
Mongoose model matches the specified structure: metadata (including entityType CORPORATE | INDIVIDUAL), general entity details, either corporate-specific or individual-specific (the other block is stripped on create/update), screening summary + match details, risk assessment (five risk groups), approval history, modification details. _searchText is rebuilt on save for fast substring search.
| Area | Base path | Auth |
|---|---|---|
| Auth | /api/auth |
Public (register/login) |
| Users | /api/users |
JWT |
| Upload | /api/upload |
JWT |
| Artemis (read/search) | /api/artemis |
JWT |
| Artemis (internal CRUD) | /api/internal/artemis |
JWT |
- Set a strong
JWT_SECRET. - Serve the frontend (
next build/next start) and API behind HTTPS. - Restrict CORS to your real origin.
- Back up MongoDB and uploaded files under
public/uploads.