---
title: "Marketplace"
description: "The obop marketplace: 22 bundled packages you can install in a click, and how to publish your own catalog as a static host with an index.json file and obop.toml packages."
canonical: "https://obop.dev/marketplace/"
lang: "en"
---

# Marketplace

## The bundled catalog

These 22 packages ship with obop (the `packages/` directory of the repository, compiled into the program). Administrators install them from _Customize_, then _Marketplace_, or with `obop modules install-from ID`. The five built-in apps (Contacts, Products, CRM, Sales and Invoicing) are not listed here because they are always present. Each name links to its app page.

| App | Package id | Version | Description |
|---|---|---|---|
| [Project](/apps/projects/) | `projects` | 0.4.0 | Projects, milestones and tasks with assignees, deadlines and status flows. A project shows its progress, the share of its tasks that are done, and the time estimated for them. |
| [Helpdesk](/apps/helpdesk/) | `helpdesk` | 0.4.0 | Support tickets with priority, severity, service-level targets and an open, in progress, resolved and closed flow. Targets are recorded, not enforced or timed automatically. Every ticket gets a number from a series when it is created. |
| [Fleet](/apps/fleet/) | `fleet` | 0.3.0 | Vehicles, drivers and service history for a small fleet. Tracks status and service records; it does not compute running costs or fuel use. |
| [Inventory](/apps/inventory/) | `inventory` | 0.3.0 | Warehouses, stock locations, stock levels and stock moves. Validating a move takes the quantity out of the stock item at the source location and adds it to the item at the destination, in one step; an item that does not exist yet is created. There is one item per product, location and lot. Negative quantities are allowed, as for virtual locations such as suppliers. |
| [Purchase](/apps/purchase/) | `purchase` | 0.3.0 | Vendors, purchase orders and order lines with a draft, sent, confirmed, received and cancelled flow. An order has a number from a series, its total is the sum of its lines, and receiving the goods creates a draft stock move per line at the receiving location (the warehouse validates them). |
| [Manufacturing](/apps/manufacturing/) | `manufacturing` | 0.2.0 | Bills of materials and manufacturing orders with a draft, confirmed, in progress and done flow. Component stock is not consumed automatically. |
| [HR](/apps/hr/) | `hr` | 0.3.0 | Employees, departments and leave requests. Personal data is classified strictly: pay, bank and national id are visible to managers only, and health and union data to the special reader group. An employee sees and files only their own leave requests; hr.manager sees all of them. |
| [Timesheets](/apps/timesheets/) | `timesheets` | 0.3.0 | Time spent on project tasks, entered in minutes, with a billable flag and an approval step. Needs the Projects package. A worker sees and edits only their own entries; timesheets.manager sees all. |
| [Planning](/apps/planning/) | `planning` | 0.2.0 | Shifts for employees, with roles and reusable templates. A shift has a day and a start and end in minutes since midnight (0 to 1439; 540 is 09:00). A shift with no employee is an open shift. Workflow: open, published, confirmed by the employee. Needs the Human Resources package. |
| [Field Service](/apps/field-service/) | `field_service` | 0.2.0 | On-site jobs for customers, done by a technician: scheduled, en route, in progress, done or cancelled. A job records the customer, the site, the technician, the planned day and start (minutes since midnight), the parts used and whether the customer must sign off. Site address and contact details are personal data. Needs the Human Resources and Products packages. |
| [Point of Sale](/apps/pos/) | `pos` | 0.3.0 | Shop tills: a point-of-sale configuration, cash-controlled sessions that are opened and closed, orders with lines, and payment lines per method. A refund and the closing of a session need a human approval from a manager; agents may only propose them. Line subtotals and the order total are computed from the lines, receipts get a gapless yearly number, and paying is refused until the payments cover the total; change and cash differences are still entered. Paying also creates a draft stock move per line from the order's stock location, for the warehouse to validate. Card numbers must never be stored; keep only the payment provider's reference. Needs the Products package. |
| [eCommerce](/apps/ecommerce/) | `ecommerce` | 0.5.0 | An online shop: categories, product listings with translations, shipping methods, discount codes, web orders with lines and a fulfilment flow of pending, paid, shipped, delivered, cancelled and refunded. When the instance runs with the public site enabled, visitors browse the published listings and place orders without an account; the server prices every order from the published listing and never trusts the browser. Orders take stock off the listing at checkout, apply discount codes and tax rates on the server, and are paid by bank transfer, by card through Stripe Checkout or in a local demo mode; the payment record, the provider reference and refunds are kept with the order. Refunds need a human approval from a manager; agents may only propose them. Customer name, email and addresses are personal data and are never public. Needs the Products package. |
| [Website](/apps/website/) | `website` | 0.4.0 | Content for a public website: pages with a slug and a draft, published, archived flow, navigation menu items, blog posts with a byline and a publish date, translations of both, and the form submissions visitors send in. When the instance runs with the public site enabled it serves the published content to visitors as a server-rendered website with SEO and no login; only the fields marked public are ever visible to them. Publishing makes content public and needs a human approval, agents may only propose it. Senders are personal data and are never public. |
| [Email Marketing](/apps/email-marketing/) | `email_marketing` | 0.2.0 | Mailing lists, the contacts on them with their consent status and date, and campaigns with a draft, scheduled, sent flow. Sending is irreversible and reaches real people, so it needs a human approval from a manager; agents may only propose it. Campaign statistics are numbers entered or imported, not computed. Contacts are personal data: keep consent_status and consent_date accurate and never mail a contact that is not opted_in. |
| [Documents](/apps/documents/) | `documents` | 0.3.0 | A register of business documents: folders, document records with kind, owner, expiry and confidentiality, and a draft, published and archived flow. It stores references and, when you upload one, the file itself. Confidentiality is enforced: confidential and restricted documents are visible only to their owner and to documents.manager; public and internal ones to everyone who may read documents. |
| [Sign](/apps/sign/) | `sign` | 0.2.0 | Document templates and signature requests with a draft, sent, signed, declined, expired flow. A request names the signer (personal data) and keeps the signature evidence as references. A signed request is immutable by convention only: the platform cannot yet lock a record, so nobody should edit a request once it is signed, and the document_hash records what was signed. Sending and recording a signature need a human approval; agents may only propose them. |
| [Subscriptions](/apps/subscriptions/) | `subscriptions` | 0.2.0 | Recurring plans and customer subscriptions with a trial, active, past due and cancelled flow. It records the next invoice date; it does not create invoices on its own. |
| [Dashboards](/apps/dashboards/) | `dashboards` | 0.3.0 | Dashboards and their widgets stored as data, for a UI to render. A dashboard has a title and an owner and is private to them (and to dashboards.manager) unless it is shared; its tiles follow it. A widget describes one tile with these fields: kind (kpi, bar, line, pie or table), model_name (the model to read, for example sale_order), measure_field (the field to aggregate; empty for count), aggregate (count or sum; sum needs a number or money measure_field), group_by (field to split by, for bar, line, pie and table; empty for a single kpi value), filter (a JSON object of field names to exact values, for example {"state":"paid"}; empty means all records) and position (order on the dashboard, lowest first). The package only stores the definition; it does not check that the model or fields exist and it computes nothing. |
| [Accounting](/apps/accounting/) | `accounting` | 0.3.0 | Chart of accounts, journals, tax rates, journal entries with debit and credit lines, fiscal years and periods, and bank statement lines. Amounts are money fields in minor currency units and tax rates are numbers in basis points (2000 means 20.00 percent). An entry shows its total debit and total credit, and posting is refused unless they are equal; a posted entry gets the next number of a gapless yearly series. Tax amounts are still entered by whoever books the entry. Account and journal codes are unique. Posting an entry and closing a period or fiscal year need a human approval and the stricter accounting.approver group; agents may only propose them. |
| [Knowledge](/apps/knowledge/) | `knowledge` | 0.2.0 | A wiki: articles arranged in a tree through a parent article, with a draft, published, archived flow, a visibility setting and tags. Visibility is a label for the UI and for people to respect; the platform has no row-level permissions yet, so everyone with the Knowledge groups can read every article. |
| [Appointments](/apps/appointments/) | `appointments` | 0.2.0 | Bookable resources (people, rooms, equipment) and appointments with a date, start and end time and a status flow. Overlaps are not prevented automatically. |
| [Expenses](/apps/expenses/) | `expenses` | 0.3.0 | Employee expense claims with a draft, submitted, approved and paid flow. Paying is a separate permission and needs a human approval; receipts are referenced by note, not stored. A claim has a number from a yearly series, and an employee sees and edits only their own claims; managers and finance see all. |

Every package is checked on install: every field needs a description, a data class and a permission group, and personal data cannot be class `none`. Packages contain no code.

## Install a package

In the web app: _Customize_, _Marketplace_, choose an app, _Install_. Installing needs the administrator group.

From the command line, against a database:

```bash
obop modules market                       # list what is available
obop modules install-from helpdesk        # install one
obop modules list                         # see what is installed
```

## Publish your own marketplace

A marketplace is any HTTP or HTTPS host that serves two things:

```text
index.json                 a list of the packages
packages/<id>.toml         the obop.toml of each package listed
```

`index.json` is an array of objects with `id`, `name`, `version`, `description` and an optional `author`:

```json
[
  {
    "id": "assets",
    "name": "Assets",
    "version": "0.1.0",
    "description": "A register of company equipment with a holder and a retire step that needs approval.",
    "author": "Example Ltd"
  }
]
```

Package ids may contain only lowercase letters, digits and `_`. Point an instance at your host with the environment variable `OBOP_MARKETPLACE_URL=https://example.com/market`. The instance shows the bundled catalog first and your host after it; if the same id exists in both, the bundled one wins. Every download is validated exactly like an upload, and responses are limited to 1 MiB.

Package signing and paid listings are not built. Treat a third-party marketplace like any other software source: read the `obop.toml` before you install it. A package cannot run code or reach the network, which limits what a bad one can do, but it can still declare misleading fields or permissions.

## Write a package

A package is one text file. The [module manifest reference](/docs/reference/module-manifest/) has a full tutorial, every key and every validation error. Test it without a database:

```bash
obop modules check my-package.toml
```

## Limits today

No signing, no ratings, no paid listings, no automatic updates, and no data migrations between versions. Uninstalling keeps the data.
