Imported from xaverric/atlas-lab (
AGENTS.md). Install upstream withnpx skills add xaverric/atlas-lab. Copyright stays with the author.
AGENTS.md
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
Commands
# Development (individual services with hot reload via tsx watch)
npm run dev:core # port 4000
npm run dev:dms # port 4001
npm run dev:scheduler # port 4002
npm run dev:notify # port 4003
npm run dev:notes # port 4004
npm run dev:gui # Next.js dev server, port 3000
# Build & check (all workspaces)
npm run build
npm run typecheck
npm run lint
# Per-workspace
npm -w @atlas/server run dev
npm -w @atlas/dms run dev
npm -w @atlas/notes run dev
npm -w @atlas/gui run dev
# Docker startup modes (from root, wraps deployment/startup.sh)
npm run start:prod # Production: all services in Docker behind Traefik
npm run start:dev # Dev: all services in Docker with dev compose overrides
npm run start:local # Local: infra + backends in Docker, GUI runs locally (hot reload)
# Add --reset suffix to wipe volumes: npm run start:dev:reset
# Init data loader (Keycloak users/roles, MinIO buckets)
npm run init
Architecture
Monorepo with npm workspaces. Node >= 22.
Shared packages (no build step, consumed as raw TS via tsconfig paths)
packages/core(@atlas/core) —ApiError, TypeScript types (User,ApiResponse,PaginatedResponse), Zod validators (paginationSchema,objectIdSchema), constants (API_PREFIX = /api/v1)packages/server-common(@atlas/server-common) — Express middleware:createAuth(Keycloak JWT verification),validate(Zod),errorHandler,requireRole,connectDB(Mongoose),createLogger(pino)
Backend services
| Service | Package | Port | Purpose | External deps |
|---|---|---|---|---|
| atlas-core | @atlas/server |
4000 | User management, health | MongoDB |
| atlas-dms | @atlas/dms |
4001 | Document storage, folders, sharing | MongoDB, MinIO (S3) |
| atlas-scheduler | @atlas/scheduler |
4002 | Job scheduling (cron/interval/once), executors (http/webhook/shell/script/monitor) | MongoDB, Redis (BullMQ) |
| atlas-notify | @atlas/notify |
4003 | Multi-channel notifications (email/Telegram), templates, preferences | MongoDB, Redis (BullMQ), SMTP, Telegram API |
| atlas-notes | @atlas/notes |
4004 | Notes knowledge base, semantic search | MongoDB, Qdrant (vector DB), Ollama (embeddings) |
Frontend
apps/atlas-gui(@atlas/gui) — Next.js 15 (App Router), port 3000lib/api.tsroutes requests by path prefix:/api/v1/dms/*→ DMS_URL,/api/v1/scheduler/*→ SCHEDULER_URL,/api/v1/notes/*→ NOTES_URL, etc.- Auth via
oidc-client-ts→ Keycloak.AuthProvidercontext wraps app,lib/api.tsattaches JWT and handles silent refresh on 401. - Protected routes under
/(protected)/*layout with auth guard.
Infrastructure (Docker)
| Service | Purpose |
|---|---|
| Traefik | Reverse proxy, TLS (Let's Encrypt), subdomain routing |
| Keycloak | OIDC auth (realm: atlas, SSO 8h, access token 30min) |
| MongoDB | Primary DB (each service uses own database) |
| Redis | BullMQ job queues (scheduler + notify only) |
| MinIO | S3-compatible file storage (DMS) |
| Qdrant | Vector DB for semantic search (notes) |
| Ollama | Local LLM embeddings — nomic-embed-text, 768 dims (notes) |
Production subdomains (ATLAS_DOMAIN=xaverric.cz): xaverric.cz (gui), api. (core), dms. (dms), scheduler. (scheduler), notify. (notify), notes. (notes), auth. (keycloak), s3. (minio API), storage. (minio console)
Backend layering
Route → Controller → Service → DAO → Model
- Routes mount auth/validation middleware (Zod schemas inline), delegate to controllers
- Controllers extract request data, call services, format
{ data: T }responses. No business logic. - Services contain business logic, throw
ApiErrorfor error cases - DAOs wrap Mongoose queries. No business logic.
- Models define Mongoose schemas with
toJSONvirtual transform (_id→id, delete__v)
All routes under API_PREFIX (/api/v1), except GET /health.
Auth
No custom auth — Keycloak handles everything.
- Frontend
oidc-client-tsredirects to Keycloak → callback exchanges code for tokens lib/api.tsattaches access token, handles 401 withsigninSilent()- Backend
createAuth()verifies JWT against Keycloak JWKS endpoint req.auth= decoded token (sub, email, name, realm_access.roles)- Inter-service auth (scheduler → notify):
X-Internal-Keyheader - AI search (external → notes):
X-Api-Keyheader, no JWT
Key service interactions
- scheduler → notify: Job success/failure hooks send HTTP POST with
X-Internal-Keyto queue a notification - notes → ollama → qdrant: On note save, fire-and-forget generates embedding via Ollama, upserts to Qdrant. Search embeds query text → Qdrant vector similarity.
- dms → minio: Two S3 clients — internal (MINIO_ENDPOINT) for uploads, public (MINIO_PUBLIC_URL) for presigned download/preview URLs
Key conventions
- API responses:
{ data: T }for success,{ error: string, details?: {} }for errors - All inputs validated with Zod in
validate()middleware - Config from env vars with local defaults (
config/index.tsin each service) @atlas/coreand@atlas/server-commonimported as source TS — no dist, no build- Next.js uses
output: 'standalone'for Docker builds - Mongoose models use
toJSONtransform:_id→id, strip__v - Qdrant point IDs: MongoDB ObjectId converted to UUID format (zero-padded)
- Notes store markdown in MongoDB, TipTap editor works with HTML, convert on load/save via turndown/showdown
