Skip to content

Administration

Admin HTTP reference

API version

Administration API: 1.30.16

Every route below is mounted under /admin/api/v1 and requires the administrator API key. The Admin application coordinates privileged workflows; entity, matching and chatbot business logic stays in the owning source package.

Background operations

Index reconciliation with apply=true, RAG reindexing, skill embedding regeneration, all five entity imports, matching batches, client imports, matching recalculation and full processing, MongoDB skill inference, opportunity synchronization with check_only=false, JPM job-score publication, configuration normalization, PwC exports and PostgreSQL migrations return HTTP 202 Accepted after authentication and preflight validation:

{
  "task_id": "2e43f9d9-1d80-4a20-9c4d-4f47182fabdd",
  "status": "accepted",
  "message": "Operation accepted. The completion report will be sent by email."
}

Index reconciliation with apply=false and opportunity synchronization with check_only=true (their defaults) instead wait for the read-only result and return it directly with HTTP 200, without a task or email.

Client creation instead waits for resource reconciliation and registration, then returns HTTP 200; only its optional initial import remains in the background. See client creation for its response and failure contract.

Acceptance means the task was scheduled, not that processing succeeded. Keep task_id to correlate the final email with application logs and query GET /admin/api/v1/operations/{task_id} with the administrator API key.

HTTP Status Meaning
200 running Accepted and waiting, or currently executing
200 success Processing succeeded and its outcome is still in worker memory
200 fail Processing failed, partially failed or was cancelled; the outcome is still in memory
404 — Unknown task: not present in the workers
503 — Worker lookup is unavailable or a worker did not answer within the local timeout

For example, a completed lookup returns:

{
  "task_id": "2e43f9d9-1d80-4a20-9c4d-4f47182fabdd",
  "status": "success"
}

The registry retains active tasks and the latest 1,000 completed outcomes per worker, evicting the oldest completions first. Reads do not extend retention. There is no database write, saved history, heartbeat or automatic retry. Outcomes change when processing finishes, independently of email delivery. Responses use Cache-Control: no-store; malformed task UUIDs return 422. This endpoint does not return workflow payloads or exception details.

Sibling workers under the same server parent query one another through private Unix sockets in the container's temporary directory. Socket entries are transport endpoints, not saved task records. Lookup is limited to the current container/server instance; other replicas are not searched. Restarting a worker loses its task states, and a 404 does not establish whether the task succeeded, failed or never existed. Durable PostgreSQL job_id values keep their existing job-status endpoints.

The final email includes the operation, tenant, environment, duration, result and existing per-batch counters/failed IDs, with a JSON report attached as operation-<task_id>.json.txt (unchanged JSON content). Its status is succeeded, partial_failure, failed or cancelled. Nested import/matching reports are normally consolidated into one final report per request and recipient. Client creation, the four entity import endpoints (jobs, opportunities, trainings and users), the three matching batch endpoints, and the three client batch workflows use the same per-stage reports. Multi-stage workflows await each report before starting the next stage, as described below. The full workflow also sends a consolidated final report, even on success. An error before the first entity batch also produces a failure report. Exceptions stay in logs; emails carry a stable failure code and the task ID. Delivery is attempted independently for every configured recipient through the shared asynchronous connector; delivery failures are logged separately and do not turn successful processing into a processing failure. Brevo is used when BREVO_API_KEY is configured; otherwise SMTP is used if all its required variables are configured. Without either configuration, delivery is skipped with a warning and processing continues. See outgoing email configuration.

Tenant operations use their configuration's report_mail_addresses, including PostgreSQL-backed matching/RAG. Client creation, index reconciliation with apply=true and skill operations without tenant scope, global MongoDB configuration normalization and PostgreSQL migrations use src/templates/config_file.json. PwC exports use client 1000's configuration (or the PostgreSQL global configuration). Recipients are resolved before scheduling. Missing/empty recipient configuration returns 422; an unknown tenant returns 404; preparation timeout or unavailable task capacity returns 503. Preflight rejections do not start work or send a completion email. Client resource failures after admission return an HTTP error and retain their failure notification; completed resources remain available for a retry.

The application owns a bounded in-process task manager. ADMIN_TASK_WORKERS (default 2) limits running operations; ADMIN_TASK_MAX_PENDING (default 8) limits waiting operations per process. Client resource preparation uses the same admission and worker limits while the HTTP request waits; its reservation transfers to the import task without admitting an extra operation. Existing per-entity concurrency limits still apply. Capacity exhaustion returns 503 with Retry-After: 10. There is no deduplication: submitting the same operation twice schedules two independent runs.

During graceful shutdown, ADMIN_TASK_SHUTDOWN_SECONDS (default 30) allows tasks to finish before remaining tasks are cancelled and awaited, while shared resources remain open. Notification attempts have a 20-second timeout per recipient. Blocking MongoDB provisioning/index work runs in the managed executor; already-running synchronous calls cannot be forcibly stopped. Tasks and results are not persisted: a process crash or forced container termination can interrupt work without sending email, and does not resume it automatically after restart. PostgreSQL initialization runs keep their separate durable job mechanism.

PostgreSQL user skill inference also retains its existing durable job and HTTP 200/job-status contract; it is not wrapped in the in-process email task manager. Migration cancellation waits for the actual Alembic thread to finish before releasing its lock and reporting cancellation. Forced termination can still interrupt the process. Existing SFTP/Datalake best-effort export failures and RabbitMQ publication failures produce a partial_failure report when processing continues. Disabled JPM job streaming is recorded as an incomplete publication.

Client and configuration

GET /clients/exists

Checks whether common_data.ClientConfig contains the exact identity (clientId, dataSource, environment). This read-only endpoint uses the administrator API key and is available in MongoDB mode, like client creation. It does not check whether the physical tenant database exists or whether imports have completed. It does not create a client, database or index.

Query parameter Required Default and behavior
client_id Yes Nonblank client identifier, for example 725.
environment No Application environment shown in Swagger: trimmed APP_IDENTIFIER_SHORT, falling back to trimmed ENV when unset, blank or mutu (case-insensitive). A supplied nonblank value must match the application's environment.
data_source No smartmobility; explicit nonblank values are matched in lowercase.

For this lookup, omitted, empty and whitespace-only optional parameters use their defaults. HTTP query strings cannot represent JSON null: omit a null optional value or serialize it as an empty query value, rather than the literal text null.

GET /admin/api/v1/clients/exists?client_id=725
GET /admin/api/v1/clients/exists?client_id=725&environment=&data_source=
GET /admin/api/v1/clients/exists?client_id=725&data_source=pwc

Both a match ({"exists": true}) and no match ({"exists": false}) return 200. Missing, blank or unsafe client IDs and unsafe optional inputs return 422. Invalid administrator credentials return 403; a different environment or PostgreSQL mode returns 400. Database failures remain errors, not a false absence result. The query uses the existing client_config_identity_unique compound index on the three identity fields and projects only _id.

POST /clients/indexes

Inventories managed MongoDB indexes. With apply=false (the default), the request waits for the read-only plan and returns HTTP 200 with db_name, apply, error_count, counts and actions. No administrative task is created and no email is sent; report recipients and task-manager capacity are not prerequisites. With apply=true, the endpoint returns HTTP 202 with a task ID, then creates, updates or removes indexes allowed by the catalog in the background and emails the completed report. A supplied db_name targets one database. When it is omitted, databases registered in ClientConfig.clientDB and reference_data are processed once each, with independent results and errors per database. Reference skill collections use the same catalog as an explicit db_name=reference_data request, in both dry-run and apply modes.

For a supplied tenant database, ClientConfig is read before selecting the catalog. Registrations with dataSource=pwc (case-insensitive) receive the shared tenant catalog and PwC compatibility score indexes; the database name does not determine its source. PwC is included in global runs too. reference_data always keeps its dedicated catalog, regardless of registrations. Both modes operate on the instance's connected MongoDB cluster, without switching PwC environments. On PwC databases, indexes outside the catalog are preserved. External classic index conflicts appear as errors requiring manual review without deleting those indexes. Independently repairable indexes continue.

For each database in apply mode, the endpoint submits Search and Vector Search changes before building classic indexes on up to three collections concurrently. Index operations within one collection remain ordered. Logs identify the phase, collection X/Y, index, operation and elapsed time; failures are logged immediately with the request correlation and, for background execution, task ID. Search builds continue inside MongoDB after command acceptance. Dry runs remain sequential and execute MongoDB inspection outside the event loop while the HTTP request awaits the result. An index failure does not abort the run: it appears in the report and subsequent independent indexes continue, including those in the same collection. Inspect error_count even on HTTP 200: resource-level errors remain in the completed report. Unexpected failures that escape reconciliation use the normal HTTP error response in dry-run mode.

POST /clients

Creates the tenant database/configuration and optional RabbitMQ, provider and model settings, including the tenant's collections and indexes. Creation uses the same reconciliation engine as POST /clients/indexes: keep conforming resources, create missing ones, update Search/Vector definitions of the same type and eligible TTL settings, and replace incompatible definitions. Obsolete and duplicate indexes in catalog-managed collections are dropped; _id_ is retained. PwC uses the external-index preservation policy described above. Failed same-type Search builds receive a definition update. Failed operations remain errors and prevent client registration until repaired. Search and Vector Search commands run first, followed by classic indexes on up to three collections.

The client is registered in common_data.ClientConfig only after all collection and index commands succeed. Atlas Search builds may still be running at that point; command acceptance does not mean the index is queryable. On failure, completed resources remain in place. Call the endpoint again with the same client_id, data_source and environment to complete missing resources, even if an older attempt already registered the client. Existing tenant configuration and registration values are preserved; this endpoint does not update settings. No provisioning progress record is stored.

The HTTP request awaits this entire resource phase, including the resource confirmation email attempt, before returning 200. MongoDB work remains in the managed blocking executor and does not block the event loop. Resource errors return a sanitized 500, and no import is scheduled. Capacity is checked before resource writes. If shutdown prevents scheduling after resources were created, the request returns 503; retry with the same client identity. Completed resources are never rolled back automatically.

Immediately after registration, a client.created email confirms that the resources are ready, before any entity import starts. A repeated call reports client.resources_verified when the registration already exists. After each completed publication stage, the batch email reports confirmed queued messages, failed publication IDs, duration and task ID under Queue import messages. An SQL read, queue or publication failure is logged and reported for its family; the next family is still attempted. A terminal partial_failure report lists failed stages. The report does not track consumer completion or consumer failures.

A fully successful creation with imports sends five emails per recipient: resource confirmation, jobs, opportunities, trainings and users. Resource-only creation sends one. There is no extra final success summary. Partial failures, exceptions and cancellation still produce the terminal administrative report with accumulated counters. The returned import task stays running until publication attempts finish; its success does not establish consumer completion. Notifications use the template recipients captured before admission; each delivery is bounded and isolated from processing failures. A missing BREVO_API_KEY selects SMTP; incomplete SMTP configuration then logs a warning and skips delivery. Retries resend the milestones they complete; no durable notification checkpoint is stored.

initialisation_import defaults to true. The background task reads active source IDs and publishes import messages, in the order jobs, opportunities, trainings, then users. Consumers can process all four families in parallel. It does not deactivate existing entities, remove scores, or calculate matchings. Pass initialisation_import=false to reconcile only client resources. JOM and JPM remain enabled in the new tenant configuration for later matching operations (use_matching.jom=true, use_matching.jpm=true).

Queued imports support SmartMobility in MongoDB mode. Other data sources return HTTP 422 when initialization is requested; resource-only creation remains available. Every initialization call republishes the active IDs. There is no publication checkpoint or automatic resume: after interruption, relaunch manually. Repeated messages re-import the same source entity; enrichment may run again. Published messages survive application restarts, subject to the existing broker retention policy. See queued imports.

All inputs are query parameters. environment is optional and defaults to the deployment environment shown in Swagger: trimmed APP_IDENTIFIER_SHORT, falling back to trimmed ENV when the identifier is unset, blank or mutu (case-insensitive). An explicit environment must match that deployment; a different value or an explicit empty value returns 400.

database_name_import_data is optional. It defaults to trimmed SM_DATABASE, or smartmobility_io when that variable is unset or blank. Swagger displays the resolved default. An explicit query value takes priority and is stored as ClientConfig.databaseSource without rewriting it. This selects the source database/schema for imports, not the new tenant database name. An empty query value remains an explicit override; query text null is a literal string, not JSON null.

rabbitmq_prefix defaults to sm_{APP_IDENTIFIER_SHORT}_legacy when omitted, empty or whitespace-only. The identifier is trimmed; an unset or blank APP_IDENTIFIER_SHORT causes an error, with no fallback to ENV. For example, mutu produces sm_mutu_legacy. A nonblank explicit prefix is preserved.

For example, to use the deployment defaults:

POST /admin/api/v1/clients?client_id=725&client_name=Example%20Company

To override only the import source, append &database_name_import_data=customer_source. Supply the administrator API key through X-API-Key. Both import modes return HTTP 200 after resource commands and registration succeed, and send milestone reports by email. With initial imports enabled, the response is:

{
  "status": "ready",
  "task_id": "2e43f9d9-1d80-4a20-9c4d-4f47182fabdd",
  "message": "Client resources are ready. Initial imports were scheduled."
}

Use this task ID with GET /admin/api/v1/operations/{task_id} to follow the remaining import publication. The resource email and import reports share this identifier. With initialisation_import=false, task_id is null, no background task is created, and the message says that initial imports were not requested. The resource-only email retains an internal correlation ID. HTTP 200 does not guarantee that Atlas Search/Vector indexes have become queryable.

For a resource-only retry, use the same identity and append &initialisation_import=false. Logs identify the current MongoDB step, database, collection, index, process ID and duration, retaining request/client/task context. Provisioning and index reconciliation use native asynchronous MongoDB commands. Search changes are submitted before classic indexes, with at most three classic collection workers and stable report ordering. Cancellation stops and drains the owned workers; already accepted server-side builds can continue. Each provisioning command has a driver deadline controlled by MONGO_PROVISIONING_TIMEOUT_SECONDS (default 120 seconds). A timeout reports failure; it does not undo completed resources or guarantee cancellation of an index build already accepted by MongoDB.

PUT /configuration/clients/normalize

Normalizes the complete stored client configuration against src/templates/config_file.json. Missing fields receive template defaults; obsolete structural fields are removed recursively. Existing values and lists are preserved. Client-defined hard filters, rules, LLM profiles, skill-type weights and skill-inference reference mappings retain their full contents, including intentionally empty objects. See the configuration normalization policy.

In MongoDB mode, supply client_id to select one client with data_source and the deployment environment. Omitting client_id processes every registered client on the connected instance, across data sources and environments. An unknown explicit client returns 404; it never triggers a global operation. PostgreSQL mode normalizes its single database-wide configuration.

Database reads and writes use native asynchronous APIs. The template is loaded outside the event loop once per request. Changed MongoDB documents are replaced atomically without recreating collections, indexes or document identifiers; unchanged documents are not written. The response returns HTTP 202 with a task ID.

The final email's result reports normalized, unchanged and failed counts. Global MongoDB processing continues after a client failure and reports message: "partial_failure" when any client failed. An unknown selected client returns 404 before admission. A configuration removed after acceptance or an invalid structural section or SQL import identifier fails the background work without writing that configuration; the email contains a sanitized failure code.

PUT /admin/api/v1/configuration/clients/normalize?client_id=725&data_source=smartmobility

Example result in the completion email:

{"message": "success", "normalized": 1, "unchanged": 0, "failed": 0}

GET /configuration/client-databases

Returns registered client-to-database routing configuration, optionally filtered by client and data source. This is operational routing metadata, not a database-discovery endpoint.

GET /configuration/ai-providers-and-models

Returns the configured AI provider/model catalog after redacting credentials and connection secrets. It is used to audit server-side model availability.

GET /configuration/clients

Loads the effective business configuration for one client, data source and deployment environment. The response includes matching, standardization and chatbot settings consumed by runtime workflows.

PUT /configuration/clients

Validates and replaces the selected client configuration with the submitted document. Subsequent requests and workers resolve the updated settings through the normal configuration loader.

Runtime control and diagnostics

GET /consumers/stop, GET /consumers/start, GET /consumers/restart

Control the RabbitMQ consumer set used by MongoDB deployments. Start is idempotent when consumers are already running; restart performs the managed stop/start sequence through application lifespan state.

GET /consumers/postgres-listener/stop, GET /consumers/postgres-listener/start, GET /consumers/postgres-listener/restart

Control the PostgreSQL notification listener and all PostgreSQL job workers as one runtime unit. These endpoints apply only when relational resources are configured and preserve the worker shutdown/cleanup contract.

GET /diagnostics/environment

Returns sanitized flags describing active runtime configuration. Values such as credentials and connection strings are never included. Access requires an administrator API key.

GET /diagnostics/current-datetime

Returns the server's current timezone-aware UTC date and time for operational clock checks.

GET /diagnostics/postgres/jobs/summary

Counts every status in the PostgreSQL listener job tables. It provides queue backlog/health visibility without claiming or mutating jobs.

POST /diagnostics/postgres/migrations/run

Schedules the configured Alembic migration chain and returns HTTP 202. Invalid PostgreSQL settings return 503 before scheduling. Recipients are loaded from the template, so admission does not require an initialized configuration table. The worker stops the PostgreSQL listener, runs migrations and restarts it only after success. It emails revision metadata or a sanitized failure. Process-local and database migration locks remain active; conflicts detected during execution are reported by email. Overlapping listener stop/migrate/start cycles are rejected.

Generic batch processing

All three endpoints use administrator authentication, take client_id and data_source as query parameters, and return HTTP 202 with one task_id after validating the client and its report_mail_addresses. The environment is resolved by authentication. Query task state through GET /operations/{task_id}.

POST /batch-processing/client/imports

Uses the same queued initialization service as POST /clients with initialisation_import=true. SQL selects only active entity IDs for the tenant, without loading profiles, descriptions or skills. IDs are streamed in bounded batches and published individually. Each family owns a RabbitMQ connection and channel, reused for its messages and closed before the next family starts. This keeps a missing queue or a closed channel from poisoning subsequent families. The full source queries run later in the corresponding consumers.

Entity Queue suffix ID field Default compute_matchings for existing messages
Users .user_profile userId true
Opportunities .job_offers jobOfferId false
Jobs .ds.jobResourceAction job_id false
Trainings .trainings id No matching workflow

The tenant prefix comes from ClientConfig.rabbitmqPrefix and must match an expanded consumer prefix. Actual queue names retain the existing sm_{rabbitmqPrefix}.{suffix} convention, including an additional sm_ when it is already part of the configured prefix. No existing queue is renamed. Each durable destination queue must already exist for its family to succeed, including the externally provisioned training queue. Start or restart the consumers after provisioning a missing training queue. Publication checks the current destination before reading its SQL IDs. A missing queue fails that family; other families continue. Invalid common tenant/source configuration still fails the operation before publication starts. No queue is recreated or reconfigured by this workflow.

Example user message (jobs use setting_id and action: "update"):

{
  "clientId": "725",
  "userId": "12345",
  "compute_matchings": false,
  "initialization_import": true
}

Both flags require JSON booleans. initialization_import=true requires compute_matchings=false and limits hydration to active records. An entity that has disappeared or become inactive is skipped without changing stored data. The regular import, standardization and enrichment logic is otherwise reused. No entities are deactivated and no scores are deleted. Each completed consumer attempt is acknowledged, whether it succeeds or fails. Import failures are logged without requesting requeue or dead-lettering; retrying a failed import requires manual republication. Optional enrichments retain their existing best-effort behavior. Cancellation leaves the message unacknowledged. If the connection closes before acknowledgement, RabbitMQ can redeliver the message.

Publication uses persistent messages, publisher confirmations and mandatory routing. A report is sent after each family's publication with confirmed queued counts, not completed imports. Empty stages report no_data. A family failure stops that family, sends its failed-stage report and continues with the next family. Confirmed counts are retained; a final partial_failure report contains stable failed-stage labels, even when failure occurred before the first message. The local task status is fail when any family failed. Cancellation still stops the workflow. A fully successful run sends four emails per recipient. Consumers run independently; task success means all publications finished.

After application interruption, confirmed messages remain in RabbitMQ; unfinished publication requires a manual relaunch. A lost confirmation can also leave a message on the broker, so duplicates are possible. Existing broker retention still applies: ResourceAction queues currently expire messages after 24 hours. Longer backlogs require a separately planned broker queue migration; this code never deletes or redeclares a queue with conflicting TTL arguments.

This endpoint is designed to initialize a new client. Use direct imports for source reconciliation, or /client/full for direct imports followed by matching.

POST /batch-processing/client/matchings

Recalculates enabled matchings in order: JOM users → JOM opportunities → JPM. It uses existing entities and performs no import. Separate positive worker counts control each phase; jom_only=true omits JPM. MongoDB and PostgreSQL matching remain supported, as does the existing pwc_staging_or_prod MongoDB selector.

Each phase sends its own report before the next begins. Reports identify JOM users, JOM opportunities or JPM, with phase-specific counts and failed IDs. Disabled phases report skipped; empty phases report no_data. Failures remain isolated between matching phases and cause a terminal partial-failure report. A successful default run sends three emails per recipient (two with jom_only=true), without an extra success summary.

POST /batch-processing/client/full

Runs the existing direct four-entity batch import, without RabbitMQ, then the matching service used by /batch-processing/client/matchings. Matching starts only after every import has finished. A global import failure or cancellation prevents matching; per-entity import failures do not. JOM/JPM flags still control matching phases. Worker-count parameters apply to matching; imports use eight workers per family. These direct imports retain deactivation and score cleanup. MongoDB mode is required.

This workflow sends the four import reports, the three matching reports, and one consolidated final report: eight emails per recipient on a fully successful run. The final report aggregates all phase outcomes under the same task_id; partial failures are never presented as overall success.

For every workflow, each recipient is attempted independently with a bounded mail-delivery timeout. Delivery failure is logged and does not stop subsequent processing. Brevo or complete SMTP configuration is required for actual delivery.

The former GET /batch-processing/client and POST /batch-processing/initializations routes have been replaced by these three POST routes. Update manual requests or scripts to select imports, matchings or full processing explicitly.

Entity imports and maintenance

The jobs, opportunities, trainings and users import endpoints send the same Import email as the corresponding stage in client creation or full processing: phase-specific successes, failed IDs, duration, status and task_id, to the client's report_mail_addresses. There is no additional terminal email on success; partial/global failures also produce the terminal failure summary. Only reporting is shared: these individual imports retain their existing selection options and matching-feature requirements.

POST /entity-imports/users

Imports all users or the supplied IDs with bounded concurrency. It can restrict skill inference to a second ID list, deactivate entities absent from the source and clean scores of deactivated users. Each record uses the canonical user flow and checkpoint semantics.

POST /entity-imports/opportunities

Imports all or selected opportunities, optionally limiting skill inference. Source-missing entities can be deactivated and their scores cleaned before the batch result is returned.

POST /entity-imports/jobs

Imports all or selected jobs through the job flow with independent inference, deactivation, score-cleanup and concurrency controls. It is available only for the backend supported by that import flow.

POST /entity-imports/trainings

Imports all or selected trainings, optionally limits skill inference and deactivates source-missing records. Training search assets are refreshed by the same standardization workflow used for individual records.

POST /entity-imports/skills

Reads Smart Mobility skills in checkpoints and upserts each checkpoint. For the same external_id and client_id, an exactly unchanged title with an existing MongoDB title_en follows these rules:

  • If SQL has no English translation, keep the stored title_en and embedding.
  • If the SQL translation matches the stored title_en, reuse the embedding.
  • If the SQL translation differs, replace title_en with that translation and regenerate the embedding from it.

Missing embeddings are generated even when the English title is reused. New or incomplete records follow the existing translation and embedding workflow. When an import writes ada_002_vector, its atomic update also removes any obsolete stored embeddings field from that skill. Records outside the import scope are untouched. Regeneration similarly removes the transient field when writing the configured model vector, without creating indexes.

After every checkpoint has been saved, it deletes MongoDB skills missing from the SQL result within the explicit request scope:

Import filters MongoDB cleanup scope
reference_id only That reference_id, across clients
client_id only That client_id, across references
Both The intersection of that client and reference
Neither Upsert only; no stale-skill deletion

Reference-only imports also remove legacy documents whose client_id is absent or null within that reference, even if their external_id still exists in SQL. The current document with its client assignment is preserved. Client-scoped imports also remove unassigned legacy documents in the distinct referentiel_id values returned by the SQL skill query for that client. No separate reference ownership lookup is performed. With both filters supplied, this cleanup is restricted to the requested reference. Unassigned documents in references absent from the SQL result and documents assigned to other clients are preserved. Cleanup runs only after a successful source read and every checkpoint has been saved. An empty client-scoped SQL result removes stale client-assigned documents but leaves unassigned documents untouched because no reference IDs were returned.

For example, a client_id=720 import returns SQL skill 123 in reference 916, while MongoDB contains unassigned skills 123 and 456 in that reference. The import first writes the complete skill 123 with client_id=720, filling its English title and generating its embedding when needed. After all writes succeed, cleanup removes its old unassigned copy and skill 456, which is absent from SQL. Exactly one client-assigned skill 123 remains; unassigned documents in references absent from the SQL result are preserved.

MongoDB stores the reference as reference_id, even though the SQL source field is named referentiel_id. A successful empty SQL result deletes all skills in the explicit scope; other clients/references remain untouched. The SQL selection still limits imports without client_id to LIVE and DEMO settings.

SQL errors and cancellation propagate instead of becoming empty results. Failed checkpoint writes preserve earlier saved checkpoints and skip cleanup. Scoped deletion requires an index beginning with reference_id when a reference is supplied, otherwise client_id. Client-only imports also require the reference_id index when cleaning unassigned legacy documents in returned references. The import only inspects existing indexes and never creates them. Provision missing indexes through POST /clients/indexes before importing. Missing scope indexes or cleanup failures are logged and leave cleanup incomplete without changing the successful upsert response. See MongoDB indexes.

GET /entity-maintenance/users/infer-skills

Starts user experience-based skill inference. In PostgreSQL mode it creates a durable paginated reconciliation run and returns its jobId; its existing HTTP 200/status contract is unchanged. MongoDB mode returns HTTP 202 and runs an async batch with at most eight concurrent entities. Individual failures are logged without stopping the remaining entities and included in the completion email. force_inferring and delete_inferring control refresh/removal behavior. MongoDB maintenance uses a separate standardized-input inference fingerprint; force_inferring=true bypasses reuse and deletion clears the cached state. Source imports retain their own pre-translation provenance, as described in Entities.

GET /entity-maintenance/users/infer-skills/jobs/{job_id}

Returns durable status, progress, heartbeat and child success/failure counts for a PostgreSQL user-inference run. Unknown jobs return 404.

GET /entity-maintenance/opportunities/infer-skills

Runs configured skill inference for opportunity content, either refreshing or removing inferred skills according to the flags. The request returns HTTP 202; the async batch retains at most eight concurrent entities and isolated per-entity failures, with success and failure counts in the final email. As with user maintenance, MongoDB inference reuse is scoped to standardized input, and removing inferred skills invalidates its cache.

POST /entity-maintenance/opportunities/synchronize

Compares an uploaded list of open PwC opportunities with the target environment. check_only=true (the default, equivalent to apply=false for indexes) waits for the read-only comparison and returns HTTP 200 with these counters:

{
  "opened_need_to_be_closed": 2,
  "closed_need_to_be_opened": 1,
  "correct_ones": 10,
  "missing_opportunities": 1
}

No task is created and no email is sent; recipients and task-manager capacity are not prerequisites. Unknown clients and invalid uploaded identifiers return their HTTP errors directly; unexpected failures use a sanitized HTTP 500 response. With check_only=false, synchronization targets the explicitly selected PwC staging/production database in the background: HTTP 202 returns a task ID and the completed counters arrive by email.

Applying the file closes currently open offers absent from it and reopens currently closed offers present in it only if they still exist in the database. Missing offers are reported, never inserted. The four counters describe the initial comparison: reopening an offer does not also add it to correct_ones. Identifier types are preserved; numeric 1042 and string "1042" remain distinct. Repeated missing IDs still count per uploaded row.

The comparison streams only jobOfferId and status and uses sets for lookup. Writes run sequentially in batches of at most 500 IDs. A status change updates timestamp and matchingUpdatedAt, preserving other fields and making earlier user matching runs eligible for recalculation. Already correct offers are not rewritten. The operation does not itself calculate matchings or call AI models.

Each closing batch removes its JOM scores in both directions and its JobOfferEmbeddings records before changing the offers. With delete_deactivated_data=false, offers remain stored with status=false. With true, they are physically deleted and never recreated; user JOM freshness states are invalidated once for the operation. Reopening updates only status and dates: it does not regenerate embeddings or scores previously removed by a closure. Use the existing import/standardization and matching workflows when those derived records need rebuilding.

Batches are not one atomic transaction. A failed cleanup stops the operation before closing that batch or processing later batches; completed batches remain applied. The administrative report records failure, and a new comparison can identify remaining work. An empty CSV containing only the jobOpportunityKey header represents no open offers and closes all currently active offers when applying changes.

Progress logs distinguish task acceptance from actual execution. The administrative worker logs its start after acquiring a worker slot, including its wait duration; the synchronization worker then logs configuration lookup and upload parsing. The inventory logs its start and progress every 500 scanned offers without adding a database count query. The comparison summary supplies the closure/reopening totals. Writes log each MongoDB step before and after it runs, with the collection, batch number and duration: score/embedding cleanup, offer deletion or status update, and user freshness invalidation when applicable. Each completed batch reports processed IDs against the phase total; these are processed input IDs, not the number of MongoDB documents modified. A failed step has no completion message. Request, client and task correlation remain available, including task=<id> in plain/console output. Uploaded identifiers, filenames and file contents are not logged. No periodic heartbeat is emitted during an individual blocked database call: its last step-start message identifies the operation being awaited. The normal terminal log and email still follow the operation outcome.

For PwC, the cleanup uses the UsersMatchingScore.jobOfferId index in the provisioning catalogue. Existing databases need the administrative index reconciliation workflow to install it; synchronization never creates indexes itself.

File extension and upload size checks run before processing in both modes. The bounded CSV/JSON bytes are copied before the HTTP upload is closed; parsing and synchronization run in the managed blocking executor with their own file handle.

Matching operations

The three matching batch endpoints below use the same phase-report mechanism as client matching and full processing: JOM users, JOM opportunities and JPM. Each sends one completion report with its own counts, failed IDs and task ID; empty and disabled phases remain visible. Failures also trigger a terminal summary. These endpoints do not import entities.

GET /matching/batches/jom/users

Streams active users through the bounded JOM user-to-opportunities pipeline. It shares one backend context and Datalake writer for the batch and records a success/error summary. Invalid concurrency or tenant input returns 422.

GET /matching/batches/jom/opportunities

Streams active opportunities through the JOM opportunity-to-users pipeline, using the requested worker bound and the selected MongoDB/PwC or PostgreSQL backend.

GET /matching/batches/jpm

Runs both user-to-jobs and job-to-users JPM batch processing for the tenant. The former legacy batch paths are not exposed.

POST /matching/jom/scores/users/publish and POST /matching/jom/scores/opportunities/publish

Load already persisted JOM scores for one supplied entity or the supported scope, format the outbound score contract and publish it through RabbitMQ. Publishing is MongoDB-only and never recomputes scores.

POST /matching/jpm/scores/users/publish and POST /matching/jpm/scores/jobs/publish

Publish persisted JPM scores for the selected side through RabbitMQ without recalculation. PostgreSQL mode rejects publishing because JPM scores are written directly to relational persistence.

The jobs endpoint accepts an optional job_id; omit it to publish all stored JPM scores. It reads the MongoDB cursor progressively and publishes batches of at most 10,000 score records, preserving job-side grouping and the streaming.jpm.job setting. The final partial batch is published too. The HTTP response returns 202 after admission; the worker emails the final outcome after all batches, including any RabbitMQ or disabled-streaming failures.

The algorithms behind these operations are documented under Matching.

PostgreSQL initialization

POST /postgres-initialization/skills

Creates a durable run that enqueues missing skill embeddings for one client or all eligible tenants.

POST /postgres-initialization/users

Initializes missing AIHub user profiles, skill gaps and inferred-skill work by keyset-paginated durable reconciliation.

POST /postgres-initialization/opportunities

Queues missing opportunity enrichment and embeddings for eligible relational opportunities.

POST /postgres-initialization/jobs

Queues missing job embeddings using the same eligibility rules as the live job projection.

POST /postgres-initialization/trainings

Queues missing training enrichments and embeddings required by relational training search.

POST /postgres-initialization/all

Runs the five entity initialization scopes sequentially under one durable parent run. One optional client_id limits every stage consistently.

GET /postgres-initialization/runs/{job_id}

Returns durable progress and failures for an initialization run. It never starts work and returns 404 for an unknown identifier.

RAG, reports and skill vectors

POST /rag/reindex-company

Synchronizes one company's configured knowledge sources into the active RAG backend. update processes changes incrementally; full rebuilds the managed company corpus.

GET /reports/pwc-matchings

Exports PwC matching data to the configured reporting destination. MongoDB can select the PwC target environment; PostgreSQL exports through its relational repository. Returns HTTP 202 before extraction. The worker performs extraction, Datalake storage and SFTP delivery, then sends one final email to configured recipients with an exported-score count and filename. The previous standalone success mail is suppressed for this background workflow. The existing production data scope and delivery destinations remain unchanged by the connection-target selector.

GET /reports/active-users, GET /reports/active-opportunities, GET /reports/active-jobs

Return active-entity counts for the selected tenant using the same backend-aware query services as the Main API.

POST /skills-library/embeddings/regenerate

Regenerates skill vectors from title_en in a MongoDB collection with the configured provider/model selection. update_embeddings=true selects only missing English titles or model vectors; false regenerates all vectors. Omitting collection_name processes every collection in reference_data sequentially, with collection names and progress counters in logs. Missing English titles use language detection and grouped DeepL/LLM translation. See Skills Library for batching and retry behavior.