# learninglocker/xapi-service architecture

> Architecture diagram of the GitHub repository learninglocker/xapi-service, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-13). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/learninglocker/xapi-service
- Repository: https://github.com/learninglocker/xapi-service

## Overview

#### Purpose and runtime entry points
This TypeScript/Node.js service implements an xAPI Learning Record Store API. It exposes four API domains: Statements, Agent Profiles, Activity Profiles, and State. The process is started through `src/server.ts`; application composition is centered in `src/apps/app.ts`, with domain Express apps in `src/apps/statements/app.ts`, `src/apps/agents/app.ts`, `src/apps/activities/app.ts`, and `src/apps/states/app.ts`. `src/conformanceServer.ts` appears to provide a separate conformance-oriented server entry point.

#### HTTP presentation boundary
Each domain has an Express presenter that parses xAPI HTTP requests, validates protocol headers/content types, invokes services, and maps domain errors to HTTP responses. Statements support GET/POST/PUT, multipart statement/attachment handling, About, and full-activity routes in `src/apps/statements/expressPresenter/index.ts` and `src/apps/statements/expressPresenter/postStatements/index.ts`. Profile/state endpoints use analogous presenters, e.g. `src/apps/agents/expressPresenter/index.ts`, `src/apps/activities/expressPresenter/index.ts`, and `src/apps/states/expressPresenter/index.ts`.

#### Statement ingestion pipeline
Statement writes follow a staged service pipeline: normalize incoming models, validate statements and signatures, resolve duplicate/voiding/reference rules, persist attachments and statements, derive queryable indexes, update full activities, and emit events. The orchestration is `src/apps/statements/service/storeStatements/index.ts`; its validation/setup stages live under `src/apps/statements/service/storeStatements/preValidationSetup/` and `src/apps/statements/service/storeStatements/postValidationSetup/`; persistence/reference updates are under `src/apps/statements/service/storeStatements/createStatements.ts` and `src/apps/statements/service/storeStatements/updateReferences/`.

#### Statement query and representation flow
Read services retrieve statements, references, activities, and attachments, then apply xAPI result formatting (canonical or IDs formats) and pagination/multipart response assembly. Key boundaries are `src/apps/statements/service/getStatements.ts`, `src/apps/statements/repo/modelsRepo/getStatements/mongo/index.ts`, and `src/apps/statements/service/utils/getStatementsResult.ts`. The presenter owns request parameter parsing and HTTP/multipart streaming in `src/apps/statements/expressPresenter/utils/getStatements/`.

#### Profiles and state domains
Agents and activities each manage profile documents plus externally stored profile content; states manage activity-agent-registration scoped state content. Their services enforce client trust, organization/store isolation, read/write scopes, content semantics, conditional ETag updates where applicable, and patch/overwrite/delete behavior. Representative orchestration paths are `src/apps/agents/service/index.ts`, `src/apps/activities/service/index.ts`, and `src/apps/states/service/index.ts`. These domains share a repeated layered pattern: presenter → service → repository contracts/factories → Mongo metadata and blob storage.

#### Repository abstraction and infrastructure
Factories decouple domain logic from backing providers. Statements compose auth, Mongo models, attachments storage, and event repositories via `src/apps/statements/repo/factory.ts` and `src/apps/statements/repo/facade.ts`. Profile/state domains expose equivalent contracts and select implementations through paths such as `src/apps/agents/repo/factory.ts`, `src/apps/activities/repoFactory/index.ts`, and `src/apps/states/repo/factory.ts`.

MongoDB is the primary metadata/statement store; Redis supports statement event/queue behavior. Attachments and profile/state bodies can use local disk, AWS S3, Google Cloud Storage, or Azure Blob Storage. Statement events can use Redis or AWS SQS, as indicated by `src/apps/statements/repo/eventsRepo/emitNewStatements/redis.ts`, `src/apps/statements/repo/eventsRepo/emitNewStatements/sqs.ts`, and `src/utils/connectToSQS.ts`.

#### Deployment and operational boundaries
Runtime configuration is centralized in `src/config.ts`, with logging and telemetry-related modules at `src/logger.ts` and `src/tracker.ts`. Local development infrastructure is MongoDB and Redis via `docker-compose.yml`; production packaging is provided by `Dockerfile` and PM2 configuration under `pm2/xapi.json`.

Main entry points: [`src/apps/app.ts`](https://github.com/learninglocker/xapi-service/blob/master/src/apps/app.ts) (Application composition), [`src/apps/statements/repo/facade.ts`](https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/repo/facade.ts) (Statement repository facade), [`src/apps/states/repo/factory.ts`](https://github.com/learninglocker/xapi-service/blob/master/src/apps/states/repo/factory.ts) (Profile/state repositories), [`src/apps/statements/expressPresenter/index.ts`](https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/expressPresenter/index.ts) (Statements API)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_runtime["Runtime"]
  node_server["Main server<br/>Node entry point<br/>[server.ts]"]
  node_conformance["Conformance server<br/>Node entry point"]
  node_root_app["Application composition<br/>Express composition<br/>[app.ts]"]
end

subgraph group_http["HTTP domains"]
  node_statements_api["Statements API<br/>Express presenter<br/>[index.ts]"]
  node_agents_api["Agent Profiles API<br/>Express presenter<br/>[index.ts]"]
  node_activities_api["Activity Profiles API<br/>Express presenter<br/>[index.ts]"]
  node_states_api["State API<br/>Express presenter<br/>[index.ts]"]
end

subgraph group_statements["Statements pipeline"]
  node_store_statements["Store statements<br/>Write orchestrator<br/>[index.ts]"]
  node_statement_setup["Validation and setup<br/>Pipeline stages"]
  node_statement_persistence["Statement persistence<br/>Write stage"]
  node_get_statements["Get statements<br/>Read service<br/>[getStatements.ts]"]
  node_statement_repos{{"Statement repository facade<br/>Repository abstraction<br/>[facade.ts]"}}
end

subgraph group_profiles["Profiles and state"]
  node_profile_services["Profile services<br/>Domain services<br/>[index.ts]"]
  node_state_service["State service<br/>Domain service<br/>[index.ts]"]
  node_profile_state_repos{{"Profile/state repositories<br/>Repository factories<br/>[factory.ts]"}}
end

subgraph group_infra["Infrastructure"]
  node_mongodb[("MongoDB<br/>Metadata store<br/>[docker-compose.yml]")]
  node_object_storage[("Blob storage<br/>Content store")]
  node_statement_events["Statement events<br/>Event transport<br/>[redis.ts]"]
  node_redis[("Redis<br/>Queue backend<br/>[docker-compose.yml]")]
end

node_server -->|"starts"| node_root_app
node_conformance -->|"serves"| node_root_app
node_root_app -->|"mounts"| node_statements_api
node_root_app -->|"mounts"| node_agents_api
node_root_app -->|"mounts"| node_activities_api
node_root_app -->|"mounts"| node_states_api
node_statements_api -->|"writes"| node_store_statements
node_statements_api -->|"reads"| node_get_statements
node_store_statements -->|"validates"| node_statement_setup
node_statement_setup -->|"authorizes write"| node_statement_persistence
node_statement_persistence -->|"persists through"| node_statement_repos
node_get_statements -->|"queries through"| node_statement_repos
node_statement_repos -->|"stores statements and indexes"| node_mongodb
node_statement_repos -->|"stores attachments"| node_object_storage
node_statement_repos -->|"emits new statements"| node_statement_events
node_statement_events -.->|"Redis option"| node_redis
node_agents_api -->|"invokes"| node_profile_services
node_activities_api -->|"invokes"| node_profile_services
node_states_api -->|"invokes"| node_state_service
node_profile_services -->|"uses"| node_profile_state_repos
node_state_service -->|"uses"| node_profile_state_repos
node_profile_state_repos -->|"stores metadata"| node_mongodb
node_profile_state_repos -->|"stores bodies"| node_object_storage

click node_server "https://github.com/learninglocker/xapi-service/blob/master/src/server.ts"
click node_conformance "https://github.com/learninglocker/xapi-service/blob/master/src/conformanceServer.ts"
click node_root_app "https://github.com/learninglocker/xapi-service/blob/master/src/apps/app.ts"
click node_statements_api "https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/expressPresenter/index.ts"
click node_agents_api "https://github.com/learninglocker/xapi-service/blob/master/src/apps/agents/expressPresenter/index.ts"
click node_activities_api "https://github.com/learninglocker/xapi-service/blob/master/src/apps/activities/expressPresenter/index.ts"
click node_states_api "https://github.com/learninglocker/xapi-service/blob/master/src/apps/states/expressPresenter/index.ts"
click node_store_statements "https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/service/storeStatements/index.ts"
click node_statement_persistence "https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/service/storeStatements/createStatements.ts"
click node_get_statements "https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/service/getStatements.ts"
click node_statement_repos "https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/repo/facade.ts"
click node_profile_services "https://github.com/learninglocker/xapi-service/blob/master/src/apps/agents/service/index.ts"
click node_state_service "https://github.com/learninglocker/xapi-service/blob/master/src/apps/states/service/index.ts"
click node_profile_state_repos "https://github.com/learninglocker/xapi-service/blob/master/src/apps/states/repo/factory.ts"
click node_mongodb "https://github.com/learninglocker/xapi-service/blob/master/docker-compose.yml"
click node_statement_events "https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/repo/eventsRepo/emitNewStatements/redis.ts"
click node_redis "https://github.com/learninglocker/xapi-service/blob/master/docker-compose.yml"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_server,node_conformance,node_root_app toneBlue
class node_statements_api,node_agents_api,node_activities_api,node_states_api toneAmber
class node_store_statements,node_statement_setup,node_statement_persistence,node_get_statements,node_statement_repos toneMint
class node_profile_services,node_state_service,node_profile_state_repos toneRose
class node_mongodb,node_object_storage,node_statement_events,node_redis toneIndigo
```

## Components

### Runtime

- [Main server](https://github.com/learninglocker/xapi-service/blob/master/src/server.ts): Node entry point · `src/server.ts`
- [Conformance server](https://github.com/learninglocker/xapi-service/blob/master/src/conformanceServer.ts): Node entry point · Separate conformance-oriented runtime. · `src/conformanceServer.ts`
- [Application composition](https://github.com/learninglocker/xapi-service/blob/master/src/apps/app.ts): Express composition · `src/apps/app.ts`

### HTTP domains

- [Statements API](https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/expressPresenter/index.ts): Express presenter · Handles statement, About, and full-activity HTTP routes. · `src/apps/statements/expressPresenter/index.ts`
- [Agent Profiles API](https://github.com/learninglocker/xapi-service/blob/master/src/apps/agents/expressPresenter/index.ts): Express presenter · `src/apps/agents/expressPresenter/index.ts`
- [Activity Profiles API](https://github.com/learninglocker/xapi-service/blob/master/src/apps/activities/expressPresenter/index.ts): Express presenter · `src/apps/activities/expressPresenter/index.ts`
- [State API](https://github.com/learninglocker/xapi-service/blob/master/src/apps/states/expressPresenter/index.ts): Express presenter · `src/apps/states/expressPresenter/index.ts`

### Statements pipeline

- [Store statements](https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/service/storeStatements/index.ts): Write orchestrator · Coordinates normalization, validation, persistence, indexing, and events. · `src/apps/statements/service/storeStatements/index.ts`
- **Validation and setup**: Pipeline stages · Applies validation, signatures, duplicate, voiding, and reference rules.
- [Statement persistence](https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/service/storeStatements/createStatements.ts): Write stage · Creates statements and updates references. · `src/apps/statements/service/storeStatements/createStatements.ts`
- [Get statements](https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/service/getStatements.ts): Read service · Retrieves records and formats xAPI result representations. · `src/apps/statements/service/getStatements.ts`
- [Statement repository facade](https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/repo/facade.ts): Repository abstraction · Composes auth, models, attachments, and event providers. · `src/apps/statements/repo/facade.ts`

### Profiles and state

- [Profile services](https://github.com/learninglocker/xapi-service/blob/master/src/apps/agents/service/index.ts): Domain services · Agent and activity profiles enforce trust, scope, ETags, and content semantics. · `src/apps/agents/service/index.ts`
- [State service](https://github.com/learninglocker/xapi-service/blob/master/src/apps/states/service/index.ts): Domain service · Manages activity-agent-registration scoped state content. · `src/apps/states/service/index.ts`
- [Profile/state repositories](https://github.com/learninglocker/xapi-service/blob/master/src/apps/states/repo/factory.ts): Repository factories · Select metadata and content-storage implementations. · `src/apps/states/repo/factory.ts`

### Infrastructure

- [MongoDB](https://github.com/learninglocker/xapi-service/blob/master/docker-compose.yml): Metadata store · Primary statement and document metadata store. · `docker-compose.yml`
- **Blob storage**: Content store · Local disk or cloud storage for attachments and profile/state bodies.
- [Statement events](https://github.com/learninglocker/xapi-service/blob/master/src/apps/statements/repo/eventsRepo/emitNewStatements/redis.ts): Event transport · Redis or SQS publication for new statements. · `src/apps/statements/repo/eventsRepo/emitNewStatements/redis.ts`
- [Redis](https://github.com/learninglocker/xapi-service/blob/master/docker-compose.yml): Queue backend · Supports local statement event and queue behavior. · `docker-compose.yml`

## Connections

- Main server → Application composition: starts
- Conformance server → Application composition: serves
- Application composition → Statements API: mounts
- Application composition → Agent Profiles API: mounts
- Application composition → Activity Profiles API: mounts
- Application composition → State API: mounts
- Statements API → Store statements: writes
- Statements API → Get statements: reads
- Store statements → Validation and setup: validates
- Validation and setup → Statement persistence: authorizes write
- Statement persistence → Statement repository facade: persists through
- Get statements → Statement repository facade: queries through
- Statement repository facade → MongoDB: stores statements and indexes
- Statement repository facade → Blob storage: stores attachments
- Statement repository facade → Statement events: emits new statements
- Statement events → Redis: Redis option
- Agent Profiles API → Profile services: invokes
- Activity Profiles API → Profile services: invokes
- State API → State service: invokes
- Profile services → Profile/state repositories: uses
- State service → Profile/state repositories: uses
- Profile/state repositories → MongoDB: stores metadata
- Profile/state repositories → Blob storage: stores bodies
