Comprehensive technical documentation covering: - System overview and container architecture - OAuth2 authentication flow (sequence diagram) - Mock vs live mode data flow - GraphQL query structure and Dalim response format - Entity dependency chain - Distribution architecture (17 MMS platforms) - Client-side React Query cache model - API route map with service function mapping - File structure reference - Going-live migration checklist - Docker deployment diagram Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
43 KiB
Dalim DAM — Architecture & Integration Guide
How this application connects to the Dalim ES FUSiON API, how data flows from the GraphQL endpoint to the browser, and how each layer works.
System Overview
┌─────────────────────────────────────┐
│ DALIM ES FUSiON SERVER │
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ OAuth2 │ │ GraphQL │ │
│ │ Token │ │ Endpoint │ │
│ │ /api/oauth │ │ /api/graphql│ │
│ └──────┬──────┘ └──────┬───────┘ │
│ │ │ │
│ │ ┌──────────┤ │
│ │ │ DAM │ │
│ │ │ Engine │ │
│ │ │ │ │
│ │ │ Projects │ │
│ │ │ Assets │ │
│ │ │ Folders │ │
│ │ │ Workflows│ │
│ │ │ Approvals│ │
│ │ └──────────┘ │
└─────────┼───────────┼──────────────┘
│ │
┌────────────┘ │
│ HTTPS/TLS │
│ │
┌─────────────────────────────┼────────────────────────┼──────────────────┐
│ DOCKER CONTAINER (port 3100) │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ NEXT.JS APPLICATION │ │
│ │ │ │
│ │ ┌──────────────────┐ ┌──────────────────────────────────┐ │ │
│ │ │ API ROUTES │ │ REACT PAGES (Browser) │ │ │
│ │ │ (Server-side) │ │ │ │ │
│ │ │ │◄────│ Dashboard Projects Assets │ │ │
│ │ │ /api/projects │ │ Search Workflows Procs │ │ │
│ │ │ /api/assets │ │ Collections Detail pages │ │ │
│ │ │ /api/search │ │ │ │ │
│ │ │ /api/workflows │ │ ┌──────────────────────────┐ │ │ │
│ │ │ /api/approvals │ │ │ React Query (TanStack) │ │ │ │
│ │ │ /api/channels │ │ │ Client-side cache & │ │ │ │
│ │ │ /api/distribute │ │ │ state management │ │ │ │
│ │ │ /api/processes │ │ └──────────────────────────┘ │ │ │
│ │ │ /api/folders │ └──────────────────────────────────┘ │ │
│ │ │ /api/collections│ │ │
│ │ └────────┬─────────┘ │ │
│ │ │ │ │
│ │ ┌────────▼──────────────────────────────────────────────────┐ │ │
│ │ │ SERVICE LAYER (dalim-service.ts) │ │ │
│ │ │ │ │ │
│ │ │ if (DALIM_MOCK_MODE === "true") │ │ │
│ │ │ └── return mock data from lib/mock/data.ts │ │ │
│ │ │ else │ │ │
│ │ │ └── call dalimQuery() → real Dalim GraphQL API │ │ │
│ │ └────────┬──────────────────────────────┬───────────────────┘ │ │
│ │ │ │ │ │
│ │ ┌────────▼─────────┐ ┌─────────▼──────────┐ │ │
│ │ │ MOCK DATA │ │ DALIM CLIENT │ │ │
│ │ │ (mock/data.ts) │ │ (dalim-client.ts) │ │ │
│ │ │ │ │ │ │ │
│ │ │ 5 Projects │ │ OAuth2 token mgmt │ │ │
│ │ │ 10 Folders │ │ GraphQL client │ │ │
│ │ │ 8 Assets │ │ Token caching │ │ │
│ │ │ 17 Channels │ │ Auto-refresh │ │ │
│ │ │ 10 Workflows │ │ │ │ │
│ │ │ 8 Dist. Jobs │ │ ────────────────► │ ──► Dalim │ │
│ │ └──────────────────┘ └─────────────────────┘ │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ POSTGRESQL (port 5490) │ │
│ │ │ │
│ │ Sessions │ User Preferences │ (Future: audit log, cache) │ │
│ └────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
Authentication Flow
The app uses OAuth2 Resource Owner Password Credentials flow with the Dalim ES FUSiON token endpoint. Credentials never reach the browser — they stay server-side in the Next.js API routes.
┌──────────┐ ┌──────────────────┐ ┌────────────────┐
│ BROWSER │ │ NEXT.JS SERVER │ │ DALIM ES API │
│ │ │ (API Routes) │ │ │
└────┬─────┘ └────────┬─────────┘ └───────┬────────┘
│ │ │
│ 1. GET /api/assets │ │
│ ─────────────────────────────────►│ │
│ │ │
│ │ 2. Check token cache │
│ │ Is token valid? │
│ │ │
│ │ ┌─── YES: skip to step 5 │
│ │ │ │
│ │ └─── NO: request new token │
│ │ │
│ │ 3. POST /api/oauth/token │
│ │ grant_type=password │
│ │ client_id=xxx │
│ │ client_secret=xxx │
│ │ username=xxx │
│ │ password=xxx │
│ │ ────────────────────────────────►│
│ │ │
│ │ 4. { access_token, expires_in } │
│ │ ◄────────────────────────────────│
│ │ │
│ │ Cache token (expires - 60s) │
│ │ │
│ │ 5. POST /api/graphql │
│ │ Authorization: Bearer xxx │
│ │ { query, variables } │
│ │ ────────────────────────────────►│
│ │ │
│ │ 6. { data: { assets: [...] } } │
│ │ ◄────────────────────────────────│
│ │ │
│ 7. JSON response │ │
│ ◄─────────────────────────────────│ │
│ │ │
Key security decisions:
- Client credentials (
DALIM_CLIENT_ID,DALIM_CLIENT_SECRET) stored in.env— never sent to browser - Token is cached server-side in memory with 60-second early expiry buffer
- API routes act as a proxy — browser only talks to Next.js, never directly to Dalim
Data Flow: Mock Mode vs Live Mode
The service layer (dalim-service.ts) is the single decision point.
Every API route calls a service function which checks DALIM_MOCK_MODE:
┌──────────────────────────┐
│ API ROUTE │
│ e.g. /api/assets │
└────────────┬─────────────┘
│
▼
┌──────────────────────────┐
│ SERVICE FUNCTION │
│ getAssets(limit, cursor) │
└────────────┬─────────────┘
│
┌──────────┴──────────┐
│ │
DALIM_MOCK_MODE DALIM_MOCK_MODE
=== "true" !== "true"
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────────┐
│ MOCK DATA │ │ dalimQuery() │
│ │ │ │
│ Return static │ │ 1. Get OAuth token │
│ arrays from │ │ 2. Build GraphQL │
│ mock/data.ts │ │ request │
│ │ │ 3. POST to Dalim │
│ No network │ │ 4. Parse response │
│ calls needed │ │ 5. Return typed │
│ │ │ data │
└────────┬────────┘ └──────────┬──────────┘
│ │
└───────────┬───────────┘
│
▼
┌────────────────────┐
│ Same TypeScript │
│ interface returned │
│ │
│ PagingResponse<T> │
│ { items, cursor, │
│ totalCount } │
└────────────────────┘
Switching from mock to live:
# In .env — change this one line:
DALIM_MOCK_MODE=false
# Then provide real credentials:
DALIM_GRAPHQL_URL=https://your-server.es-cloud.com/ES/api/graphql
DALIM_TOKEN_URL=https://your-server.es-cloud.com/ES/api/oauth/token
DALIM_CLIENT_ID=your_real_client_id
DALIM_CLIENT_SECRET=your_real_secret
DALIM_USERNAME=admin
DALIM_PASSWORD=your_password
No code changes needed. The service layer handles everything.
GraphQL Query Architecture
Each service function maps to a predefined GraphQL query in dalim-queries.ts.
The queries use Dalim's standard pagination pattern:
┌─────────────────────────────────────────────────────────┐
│ QUERY STRUCTURE │
│ │
│ dalim-queries.ts dalim-types.ts │
│ ┌───────────────┐ ┌──────────────────┐ │
│ │ │ │ │ │
│ │ QUERIES = { │ │ interface Asset {│ │
│ │ assets: ` │ │ id: string │ │
│ │ query { │ │ name: string │ │
│ │ assets(│◄──────►│ mimeType │ │
│ │ ...)│ │ fileSize │ │
│ │ { │ │ status │ │
│ │ items│ │ folder │ │
│ │ cursor │ project │ │
│ │ totalCount │ } │ │
│ │ } │ │ │ │
│ │ } │ │ PagingResponse │ │
│ │ `, │ │ <T> { │ │
│ │ ... │ │ items: T[] │ │
│ │ } │ │ cursor │ │
│ │ │ │ totalCount │ │
│ └───────────────┘ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
Dalim GraphQL Request:
┌─────────────────────────────────────────────────┐
│ POST https://{HOST}/ES/api/graphql │
│ │
│ Headers: │
│ Authorization: Bearer {token} │
│ Content-Type: application/json │
│ │
│ Body: │
│ { │
│ "query": "query assets($limit: Int) { │
│ assets(limit: $limit) { │
│ items { id name mimeType ... } │
│ cursor │
│ totalCount │
│ } │
│ }", │
│ "variables": { "limit": 24 } │
│ } │
└─────────────────────────────────────────────────┘
Dalim GraphQL Response:
┌─────────────────────────────────────────────────┐
│ { │
│ "data": { │
│ "assets": { │
│ "items": [ │
│ { "id": "123", "name": "file.pdf" ... } │
│ ], │
│ "cursor": "abc123", │
│ "totalCount": 142 │
│ } │
│ } │
│ } │
└─────────────────────────────────────────────────┘
Dalim Entity Dependency Chain
Dalim ES FUSiON requires entities to be created in a specific order. Parent entities must exist before children can reference them:
┌─────────────────────┐
│ Security Profiles │ ◄── Must exist first
│ (permissions, │
│ access control) │
└─────────┬───────────┘
│
│ assigned to
▼
┌─────────────────────┐
│ Users │ ◄── Need a security profile
│ (login, roles) │
└─────────┬───────────┘
│
│ owns / manages
▼
┌─────────────────────┐
│ Customers │ ◄── Organization that owns projects
└─────────┬───────────┘
│
│ contains
▼
┌─────────────────────┐ ┌─────────────────────┐
│ Projects │─────►│ Workflows │
│ (campaigns, jobs) │ │ (approval chains, │
└─────────┬───────────┘ │ distribution) │
│ └─────────────────────┘
│ contains
▼
┌─────────────────────┐
│ Folders │ ◄── Organize assets within a project
│ (directory tree) │
└─────────┬───────────┘
│
│ contains
▼
┌─────────────────────┐ ┌─────────────────────┐
│ Assets │─────►│ Approvals │
│ (files, revisions, │ │ (approve/reject │
│ metadata) │ │ at each level) │
└─────────┬───────────┘ └─────────────────────┘
│
│ tracked by
▼
┌─────────────────────┐
│ Processes │ ◄── Preflight, color conversion, export
│ (background jobs) │
└─────────────────────┘
Distribution Architecture (Send-To)
Assets flow from the DAM through the Production Engine to 17+ output platforms, matching the MMS tech architecture:
┌─────────────────┐
│ │
│ DALIM ES │
│ FUSiON │
│ │
│ Production │
│ Engine │
│ │
└────────┬────────┘
│
┌──────────────────────────┼──────────────────────────┐
│ │ │
┌─────────┴─────────┐ ┌──────────┴──────────┐ ┌─────────┴─────────┐
│ WEB & APP │ │ SOCIAL & ADS │ │ PHYSICAL │
│ │ │ │ │ │
│ Website │ │ Meta (FB/IG) │ │ ESL (Pricer) │
│ Mobile App │ │ TikTok │ │ In-Store TV │
│ E-Commerce │ │ LinkedIn │ │ In-Store Screen │
│ (Shop/PWA) │ │ Google Ads │ │ In-Store POP │
│ │ │ Performance Max │ │ Print/Flyers │
└───────────────────┘ │ YouTube │ │ │
│ DV360/Trade Desk │ └───────────────────┘
│ Customer Comms │
│ Retail Media │
└─────────────────────┘
Each "Send To" creates a distribution job:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ QUEUED │───►│PROCESSING│───►│COMPLETED │ │ FAILED │
│ │ │ │ │ │ │ │
│ Job │ │ Asset │ │ Asset │ │ Retry / │
│ created │ │ being │ │ live on │ │ alert │
│ │ │ sent │ │ platform│ │ │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
In the app, the Send-To dialog (accessible from any asset) shows all platforms grouped by category. When the user clicks a platform:
User clicks "Send To → Meta"
│
▼
POST /api/distribution
{ assetId: "A001", channelId: "CH05" }
│
▼
Service creates DistributionJob
{ status: "queued", channelName: "Meta (Facebook & Instagram)" }
│
▼
[MOCK MODE] Job stored in memory
[LIVE MODE] Would call Dalim workflow API to initiate distribution
│
▼
UI updates: badge shows "Sent" on the channel
Distribution History table shows the new job
Client-Side Architecture
The browser-side React app uses TanStack React Query for all data fetching, caching, and state management:
┌──────────────────────────────────────────────────────────────────┐
│ BROWSER │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ REACT QUERY CACHE │ │
│ │ │ │
│ │ ["projects", 20] ──► { items: [...], totalCount: 5 } │ │
│ │ ["project", "P001"] ──► { id: "P001", name: "..." } │ │
│ │ ["assets", 24] ──► { items: [...], totalCount: 8 } │ │
│ │ ["asset", "A001"] ──► { id: "A001", name: "..." } │ │
│ │ ["channels"] ──► [{ id: "CH01", name: "PIM" }, ...] │ │
│ │ ["distribution-jobs", "A001"] ──► [{ status: "done" }] │ │
│ │ │ │
│ └───────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ useProjects │ │ useAsset │ │ useChannels │ │
│ │ useProject │ │ useAssets │ │ useSendTo │ │
│ │ useProject │ │ useSearch │ │ useDistJobs │ │
│ │ Folders │ │ │ │ │ │
│ └──────┬───────┘ └──────┬──────┘ └──────┬───────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PAGES & COMPONENTS │ │
│ │ │ │
│ │ / Dashboard (KPIs, activity feed) │ │
│ │ /projects Project cards grid │ │
│ │ /projects/[id] Folder tree + asset grid │ │
│ │ /assets All assets grid │ │
│ │ /assets/[id] Detail + download + Send To │ │
│ │ /search Faceted search + list/grid toggle │ │
│ │ /collections Thumbnail mosaics │ │
│ │ /workflows Workflows + channels + approvals │ │
│ │ /processes Progress bars + status tracking │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
API Route Map
Every API route proxies to a dalim-service.ts function:
HTTP Request Service Function Dalim Query
───────────────────────────── ───────────────────────── ─────────────────
GET /api/health (built-in) none
GET /api/projects getProjects(limit, cursor) QUERIES.projects
GET /api/projects/:id getProjectById(id) QUERIES.projectById
GET /api/projects/:id/folders getFoldersByProject(id) QUERIES.folders
GET /api/projects/:id/assets getAssetsByProject(id, ...) QUERIES.assets
GET /api/assets getAssets(limit, cursor) QUERIES.assets
GET /api/assets/:id getAssetById(id) QUERIES.assetById
GET /api/folders/:id getFolderById(id) QUERIES.folderById
GET /api/folders/:id/assets getAssetsByFolder(id, ...) QUERIES.assets
GET /api/search searchAssets(query, facets) QUERIES.search
GET /api/workflows getWorkflows(limit, cursor) QUERIES.workflows
GET /api/approvals getApprovals(limit, cursor) QUERIES.approvals
GET /api/processes getProcesses(limit, cursor) QUERIES.processMonitoring
GET /api/collections getCollections(limit, ...) QUERIES.collections
GET /api/channels getChannels() (mock-only for now)
GET /api/distribution getDistributionJobs(assetId) (mock-only for now)
POST /api/distribution sendToChannel(asset, channel) (mock-only for now)
File Structure Map
DALIM-API/
│
├── CLAUDE.md # AI assistant project context
├── MM_logo_white.svg # MediaMarkt white logo
├── docs/
│ ├── dalim-api-index.md # All 466 operations (Tier 1)
│ ├── dalim-api-reference.md # 29 detailed endpoints (Tier 2)
│ ├── api_parsed.json # Parsed API data from HTML
│ └── ARCHITECTURE.md # ◄── YOU ARE HERE
│
├── parse_api.py # HTML → JSON parser for API docs
├── generate_docs.py # JSON → Markdown doc generator
│
└── dalim-app/ # ◄── NEXT.JS APPLICATION
├── Dockerfile # Multi-stage production build
├── docker-compose.yml # App + PostgreSQL
├── .env.example # Template for credentials
├── prisma/
│ └── schema.prisma # DB schema (sessions, prefs)
│
├── public/
│ ├── logo.svg # MM logo (sidebar)
│ └── placeholders/ # 8 dev placeholder images
│
└── src/
├── app/ # Next.js App Router pages
│ ├── page.tsx # Dashboard
│ ├── layout.tsx # Root layout (sidebar + header)
│ ├── not-found.tsx # 404 page
│ ├── globals.css # MediaMarkt theme (#DF0000)
│ ├── api/ # 15 API route handlers
│ ├── assets/ # Browse + [id] detail
│ ├── projects/ # Browse + [id] detail
│ ├── search/ # Faceted search
│ ├── collections/ # Collection mosaic grid
│ ├── workflows/ # Workflows + distribution
│ └── processes/ # Process monitor
│
├── components/
│ ├── assets/ # AssetCard, AssetGrid, AssetDetail
│ ├── distribution/ # SendToDialog
│ ├── folders/ # FolderTree
│ ├── layout/ # Sidebar, Header
│ ├── error-boundary # Error handling wrapper
│ └── ui/ # 12 shadcn/ui components
│
├── hooks/
│ └── use-dalim.ts # 15 React Query hooks
│
└── lib/
├── dalim-client.ts # OAuth2 + GraphQL client
├── dalim-service.ts # Service layer (mock/real switch)
├── dalim-queries.ts # 14 GraphQL query strings
├── dalim-types.ts # TypeScript interfaces
└── mock/data.ts # All mock data
Going Live: Migration Checklist
When Dalim ES FUSiON credentials become available:
STEP 1: Configure credentials
┌────────────────────────────────────────┐
│ .env │
│ │
│ DALIM_MOCK_MODE=false ◄── flip this │
│ DALIM_GRAPHQL_URL=https://real.server │
│ DALIM_TOKEN_URL=https://real.server │
│ DALIM_CLIENT_ID=real_id │
│ DALIM_CLIENT_SECRET=real_secret │
│ DALIM_USERNAME=real_user │
│ DALIM_PASSWORD=real_pass │
└────────────────────────────────────────┘
STEP 2: Verify connectivity
┌────────────────────────────────────────┐
│ curl http://localhost:3100/api/health │
│ │
│ Expected: { "mockMode": false } │
│ │
│ Then check: /api/projects │
│ Should return real project data │
└────────────────────────────────────────┘
STEP 3: Validate field mapping
┌────────────────────────────────────────┐
│ Compare real API responses against │
│ TypeScript interfaces in │
│ dalim-types.ts │
│ │
│ Fields may differ: │
│ - Additional fields → safe to ignore │
│ - Missing fields → add ? optional │
│ - Different names → update queries │
└────────────────────────────────────────┘
STEP 4: Connect distribution channels
┌────────────────────────────────────────┐
│ Replace mock channel/job logic in │
│ dalim-service.ts with real API calls: │
│ │
│ - getChannels() → query real channels │
│ - sendToChannel() → trigger workflow │
│ via Dalim mutation API │
└────────────────────────────────────────┘
STEP 5: Set up auth flow (future)
┌────────────────────────────────────────┐
│ Add login page │
│ Use PostgreSQL sessions (Prisma) │
│ Per-user OAuth tokens │
│ Role-based access control │
└────────────────────────────────────────┘
Docker Deployment
docker compose up --build -d
┌───────────────────────────────────────────────┐
│ docker-compose.yml │
│ │
│ ┌─────────────────────┐ ┌────────────────┐ │
│ │ app │ │ db │ │
│ │ │ │ │ │
│ │ Node.js 20 Alpine │ │ PostgreSQL 16 │ │
│ │ Next.js standalone │ │ Alpine │ │
│ │ │ │ │ │
│ │ Port: 3100 → 3000 │ │ Port: 5490 │ │
│ │ │ │ │ │
│ │ Depends on: db │ │ Volume: │ │
│ │ Env: .env file │ │ dalim_pgdata │ │
│ │ │ │ │ │
│ └─────────────────────┘ └────────────────┘ │
│ │
└───────────────────────────────────────────────┘
Build stages (Dockerfile):
┌──────────┐ ┌──────────┐ ┌──────────┐
│ deps │────►│ builder │────►│ runner │
│ │ │ │ │ │
│ npm ci │ │ prisma │ │ Minimal │
│ │ │ generate │ │ Alpine │
│ │ │ next │ │ image │
│ │ │ build │ │ │
│ ~400MB │ │ ~800MB │ │ ~150MB │
└──────────┘ └──────────┘ └──────────┘
(shipped)
Dalim API Coverage
The application references 29 of 466 available Dalim ES FUSiON operations.
The full API index is documented in docs/dalim-api-index.md.
466 Total Operations
┌──────────────────────────────────────────────────────┐
│████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ 6% Active (29)
│ │
│ Queries Used (12): │
│ projects, projectById, folders, folderById, │
│ assets, assetById, search, workflows, │
│ approvals, collections, collectionById, │
│ processMonitoring │
│ │
│ Ready to Add: │
│ downloadAsset, createAsset, deleteAsset, │
│ createProject, approve, workflowsByEntity, │
│ users, createUser, customers, ... │
│ │
│ Full Index: docs/dalim-api-index.md │
└──────────────────────────────────────────────────────┘