Core Concepts

This document explains the purpose and structure of the Inventory Management API from a conceptual point of view. It is intended for any stakeholder — business users, content managers, and developers alike — who needs to understand how the system works before using or extending it.

Table of Contents

  1. TOC

What is this system?

The Inventory Management API is the backbone of the Museum With No Frontiers (MWNF) digital infrastructure. Its primary purpose is to store and serve the inventory of museum artifacts, monuments, and related content managed by partner institutions around the world.

The system is designed around two key ideas:

  1. One record, many representations. The same artifact can be described differently depending on the language of the visitor and the audience context (general public, academic, educational, etc.).
  2. Flexible organization. Items can be grouped, cross-referenced, and organized in multiple ways — by collection, exhibition, thematic trail, and more — without duplicating the underlying data.

Core Entities

Item

The Item is the central entity of the system. It represents a single piece of content in the inventory — an artifact, a monument, a detail of an artifact, or a photograph.

Item types

Type Description
object A museum object or artifact (e.g., a vase, a statue)
monument An architectural monument or archaeological site
detail A close-up detail or specific part of another item
picture A photograph or image resource

Item key attributes

Item content

The descriptive content of an item is not stored directly on the item record. Instead, it is stored in translations (see below), allowing the same item to be described in multiple languages and for multiple audiences.

Item linking

Items can be explicitly linked to other items via ItemItemLink records. A link connects a source item to a target item within a given context (see Context). Links can carry their own translations (descriptions of the relationship type in multiple languages). The link is directed: the source item has an outgoing link to the target item. Both directions are accessible from either item.

Note: The nature of the relationship expressed by a link (e.g., “is a part of”, “is related to”) is conveyed through the link’s translations, not through a fixed enumerated type. The schema of these descriptions is not constrained — the meaning is carried entirely by the translated text.


Partner

A Partner is an institution, museum, or individual who contributes content to the inventory. Every item in the system is owned by a partner.

Partner types

Type Description
museum A museum or gallery
institution A non-museum cultural or academic institution
individual An individual contributor

Partner key attributes

Partner participation in collections

Partners can be associated with collections at different levels of contribution (see Collection → Partner levels).


Collection

A Collection is a virtual grouping of items. Collections are the primary mechanism for organising and publishing content, whether as an exhibition, a thematic gallery, an itinerary, or another form of curated set.

Collection types

Type Description
collection A general-purpose grouping of items
exhibition A curated set of items presented as an exhibition
gallery A set of items presented as a gallery
theme A thematic grouping
exhibition trail A guided itinerary through an exhibition
itinerary A geographic or thematic tour
location A grouping based on a physical location

Collection hierarchy

Collections can have a parent collection, creating a tree structure of unlimited depth. For example, an exhibition might contain several sub-galleries, each of which is itself a collection.

How items are added to a collection

There are two distinct relationships between items and collections:

  1. Primary membership — An item has a collection_id foreign key pointing to its primary collection. This is a straightforward one-to-many relationship: one collection owns many items directly.
  2. Secondary (attached) membership — Items can additionally be attached to other collections through a pivot table (collection_item). This many-to-many relationship allows the same item to appear in multiple collections without duplicating data.

Both types of membership can coexist. An item may have a primary collection and also be attached to several other collections.

Collection default language and context

Each collection records a default language and a default context. These specify which language and audience context should be used as the primary mode of presentation for this collection. They do not restrict what translations can be created; they express an editorial preference.

Partner levels

Partners can be associated with a collection at one of three contribution levels:

Level Description
partner Primary partner providing content directly to the collection
associated_partner Partner contributing indirectly or in a supporting role
minor_contributor Partner with a minor or peripheral contribution

Project

A Project represents a campaign or initiative under which content (items and collections) is created and published. It provides a way to group content that was produced as part of a specific effort and to control its public availability.

Project visibility

A project is publicly visible only when all three of the following conditions are met:

  1. is_enabled is true — the project has been administratively enabled.
  2. is_launched is true — the project has been explicitly launched by an editor.
  3. launch_date is in the past — the scheduled launch date has been reached.

This three-condition model allows content to be prepared in advance and released on a scheduled date, while also allowing emergency disabling at any time.

Project association

Every project has:


Context

A Context defines a specific audience or purpose for which content is written. It is a key part of the multi-language, multi-audience content model.

Examples of contexts might be: “General public”, “Academic”, “Educational”, “Children”. (The actual names are defined by the administrators of the system.)

One context is marked as the default context (is_default = true). The default context is used as a fallback when a translation in the requested context does not exist (see Translation fallback logic).


Language

A Language identifies a supported language in the system using its ISO 639-1 code (e.g., en, fr, ar). Languages use their ISO code as their primary key rather than a UUID.

One language is designated as the default language (is_default = true / english() scope). The default language participates in translation fallback logic.

Language names are stored in a LanguageTranslation model which maps a language to its name as displayed in another language (e.g., “English” displayed as “Anglais” in French). This uses a display_language_id rather than a context — it is a simpler, context-free translation compared to entity translations.


Country

A Country identifies a geographic country using its ISO 3166-1 alpha-3 code (e.g., EGY, FRA, MAR). Countries use their ISO code as their primary key rather than a UUID.

Countries are used to associate items and partners with a geographic origin or location. They are reference data and do not carry complex business logic.

Country names are stored in a CountryTranslation model which maps a country to its name in a given language. Unlike entity translations, country translations use only a language_id and have no context dimension — a country’s name does not vary by audience.


Translations and Multilingual Content

Every major entity in the system supports multilingual, multi-audience content through a translation model. The pattern is consistent across all entities.

How translations work

For every entity (Item, Partner, Collection, etc.), there is a corresponding translation table (e.g., item_translations, partner_translations). Each translation record combines:

A single entity can therefore have many translations: one per language-context combination. For example, an item might have:

Item translation fields

The ItemTranslation model is the richest translation model. In addition to the basic name and description, it stores museum-specific scholarly metadata:

Translation fallback logic

When requesting content for a specific language and context, the system uses the following fallback chain:

  1. Look for a translation matching exactly the requested language and the requested context.
  2. If not found, look for a translation matching the requested language and the default context.
  3. If still not found, return null (no content available).

This means it is sufficient to create a single “default context” translation for an entity to ensure it is always reachable, while more specific context translations can be added progressively.


Tags

A Tag is a free-form label that can be attached to any number of items. Tags allow flexible, ad-hoc categorisation of content that does not fit into the formal collection structure.

Tags have:

The API supports querying items by tags in two modes:


Artists and Workshops

Artists and Workshops describe the creation of an item.

Both are linked to items through many-to-many relationships. An item can have multiple artists and multiple workshops.


Glossary

The Glossary is a structured dictionary of specialised terms used in the inventory and its descriptions. Each glossary entry has:

The glossary is designed to support editorial annotation: editors can link a glossary spelling to the text of an item translation to flag that a term is defined in the glossary.


Image Management

The image workflow

Images in the system follow a two-stage workflow:

  1. Upload stage — A file is uploaded and tracked as an ImageUpload record (raw file metadata: path, name, extension, MIME type, size). This is purely a tracking mechanism for the upload process.

  2. Available stage — Once processed, the image becomes an AvailableImage record. This represents a pool of images that are ready to be attached to content but have not yet been assigned.

  3. Attachment stage — An available image is attached to a specific entity (Item, Partner, or Collection), creating a typed image record:

    • ItemImage — attached to an Item.
    • PartnerImage — attached to a Partner.
    • PartnerLogo — a logo attached to a Partner.
    • PartnerTranslationImage — an image attached to a specific partner translation (language-specific partner imagery).
    • CollectionImage — attached to a Collection.

Display ordering

All attached image records carry a display_order field. Images associated with the same entity are sorted by this value. The system provides moveUp() and moveDown() operations, and a reorderItemImages() method that normalises the ordering to eliminate gaps when images are removed.


Authentication and Permissions

The API uses Laravel Sanctum for token-based authentication. All endpoints require a valid bearer token, except for a small number of informational endpoints (/api/info, /api/health, /api/version).

Access to operations is controlled by the following permissions:

Permission Scope
view data Read any data
create data Create new records
update data Modify existing records
delete data Delete records
manage users Create, edit, and delete user accounts
assign roles Assign roles to users
manage roles Create and modify roles
manage settings Change system configuration

Permissions are assigned to users through roles (powered by Spatie Laravel Permission).


Key Design Decisions

UUID primary keys

All entities use UUIDs as primary keys, with two exceptions: Language uses its ISO 639-1 code as the primary key, and Country uses its ISO 3166-1 alpha-3 code. This makes IDs self-describing and stable across systems.

The User model uses the Laravel default integer key for compatibility with the authentication framework.

internal_name and backward_compatibility

Every entity has an internal_name field. This is a human-readable identifier used internally by editors and administrators. It is not the public-facing name (which is stored in translations) but rather a stable label for use within the management interface.

The backward_compatibility field is a critical migration aid. Because this API merges and replaces several legacy systems, each new record may correspond to a row that existed in one of those systems under a different identifier. The backward_compatibility field stores a string representation of the primary key from the originating legacy system, allowing a direct mapping between new records and the legacy rows they replace. This is essential for data import scripts and for cross-referencing the new model against legacy databases during and after migration. This field is populated during data import; new records created directly in this system will typically leave it empty.

Atomic deletion

Several models (Item, Glossary, PartnerTranslation) implement custom delete() methods that perform cascading deletions within a database transaction. This ensures referential integrity is always maintained even for complex, cross-table relationships that cannot be handled entirely by foreign key constraints.


Relationships at a Glance

The following diagram summarises the main relationships between core entities:

Country ◄─── Item ◄─── ItemTranslation (language × context)
              │              └── Author × 4 roles
              │              └── GlossarySpelling (many-to-many)
              ├── Partner ◄── PartnerTranslation (language × context)
              ├── Collection (primary, via FK)
              ├── Collection (secondary, via pivot)
              ├── Project
              ├── Parent Item (self-referential)
              ├── Children Items (self-referential)
              ├── Tags (many-to-many)
              ├── Artists (many-to-many)
              ├── Workshops (many-to-many)
              └── ItemItemLink (source → target, with context)

Collection ◄── CollectionTranslation (language × context)
            ├── Items (primary, HasMany via FK)
            ├── Items (secondary, BelongsToMany via pivot)
            ├── Partners (many-to-many, with level)
            ├── Parent Collection (self-referential)
            └── Children Collections (self-referential)

Project ──► Context
        ──► Language

Partner ──► Country
        ──► Project
        ──► Monument Item (BelongsTo Item)

Language ──► LanguageTranslation (language × display_language)
Country  ──► CountryTranslation  (language only — no context dimension)

Glossary ──► GlossaryTranslation (language × context)
         ──► GlossarySpelling ──► ItemTranslation (many-to-many)
         ──► Synonyms (self-referential, many-to-many)