# Custom content with Objects

The Objects module lets you model content that isn't a product: services, bookings, projects, team members, landing pages, anything your storefront needs. You define an **object type** (the model: its name and its properties), then create **records** of that type (the actual entries). Each type gets its own entry in the sidebar under **Content** → **Objects**, listed by its plural name, and your storefront can read the records through the [Objects API](/api/objects/records).

Objects appears in the sidebar under the **Content** group when the module is enabled for the active business. Every member of the business sees the same screens and actions.

## Create an object type

1. Open **Content** → **Objects** in the sidebar.
2. Click **New type**. A dialog titled **New object type** opens with a single name field (placeholder: **Name (e.g. Service)**). The **Create** button stays disabled until you type a name.
3. Click **Create**. You land directly on the new type's builder page, where you define its properties.

The Objects index lists all your types in a table:

| Column | Description |
| --- | --- |
| Name | The type's plural name. Click the row to open its records list. |
| Key | The type's identifier. Set at creation and cannot be changed afterwards. |
| Properties | Count of the type's active (non-archived) properties. |
| Records | Count of records of this type. |

The gear icon at the end of each row opens the type builder.

## Edit a type in the type builder

The type builder is where you shape a type after creating it. Open it from the gear icon on the Objects index, or via the **Type** button on the type's records list. From the builder, **View records** takes you the other way, to the records list.

You can edit the type's **Name** and **Plural name** and click **Save** (a brief "Saved." confirms). The key cannot be changed; the builder shows **Key: {key} (cannot change)**.

### Add a property

1. Click **Add property**.
2. Fill in the **Label** (placeholder: **Label (e.g. Budget)**). The **Key** field auto-fills from the label as you type, until you edit the key yourself.
3. Pick a **Type** (see the table below) and fill any type-specific fields.
4. Optionally tick **Required**.
5. Click **Add**. The button stays disabled until both Label and Key are filled.

Property keys, like type keys, are permanent once created.

| Property type | What it stores | Notes |
| --- | --- | --- |
| Text | A short line of text | |
| Long text | Multi-line text | Cannot be used as a sort column or list filter. |
| Number | A number | |
| Money | An amount | Entered with a dot decimal (e.g. `4950.00`), shown as a EUR-formatted amount in lists. |
| Yes/no | A checkbox | Shown as Yes or No in lists. |
| Select | One choice from a fixed list | Enter the options in the dialog's textarea, one option per line. |
| Date | A date | |
| Customer | A link to a customer | Only offered when the Customers module is enabled. Lists show the customer's name. |
| Sections | A page built from content sections | See [Sections properties](#sections-properties) below. |

### Sections properties

A Sections property turns part of a record into a small page builder. When adding one, the dialog asks **Which sections can this page use?** with a checkbox list of section shapes; you must pick at least one. You also set **Minimum** (0-100) and **Maximum** (1-100) item counts; the maximum must be greater than or equal to the minimum.

Section shapes themselves are not managed on these screens. If none exist yet, the dialog says **No section shapes exist yet. Create one before adding a sections property.**

Sections properties never appear as columns in the records list.

### The built-in name property

Every type has a `name` property. It cannot be archived, and its required flag cannot be toggled; when required it simply shows a `required` badge. The record's name is used as its title on the detail page and renders bold in the records list.

### Reorder, require, and archive properties

- **Reorder** properties with the drag handle (grip icon) or the per-row up/down arrows. The change applies immediately and reverts if it fails to save.
- **Required** is an inline checkbox on each property row.
- **Archive** a property with the per-row archive icon. Archiving is reversible: the property disappears from forms and list columns, but the data it holds on existing records is preserved. Archived properties appear in an **Archived** section of the builder, from which you can unarchive them with the restore icon. Properties are never hard-deleted individually.

### Delete a type

Click **Delete type** in the builder. The confirmation reads: **Delete "{plural name}" and its {count} record(s)? This cannot be undone.** Unlike archiving a property, deleting a type is permanent and removes all its records with it.

## Work with records

Click a type on the Objects index (or its sidebar entry) to open its records list. Columns are generated from the type's active properties (Sections properties excluded), with empty values shown as `-`.

From the list you can:

- **Search** the table.
- **Filter** using the auto-generated filters: a dropdown per Select property (with that property's options) and a date-range filter per Date property.
- **Sort** on any column except Long text and Customer properties.
- **Bulk delete**: select rows with the checkboxes, then use the bulk **Delete** action (asks for confirmation).
- Click **New {type name}** to create a record, or click any row to open the record.

### Create a record

1. Click **New {type name}** on the records list.
2. Fill the form. It is generated from the type's properties; required fields show a red asterisk. Notable inputs:
   - **Money**: type the amount with a dot for decimals, e.g. `4950.00`. Invalid input blocks submission with **Invalid price "{price}". Use a dot for decimals: 4950.00**.
   - **Select**: a dropdown with a **Choose...** placeholder, plus a **None** option when the property is not required.
   - **Customer**: search-as-you-type (minimum 2 characters), showing name and email; click **Change** to pick a different customer.
   - **Sections**: a section canvas. Click **Add section** to open the **Add a section** picker of shape and look tiles; reorder sections by dragging or with the arrow buttons; duplicate, delete, or hide/show each section; expand a section card to edit its fields. When more than one content locale is enabled, a locale switcher lets you edit each language's content.
3. Click **Create**. On success you land on the new record's detail page. Validation errors from a failed save appear under the fields concerned; an invalid section gets a **Has an error** badge and expands automatically.

### Edit or delete a record

The record detail page shows the same generated form. Edit any field and click **Save** (a brief "Saved." confirms). **Delete** asks: **Delete "{title}"? This cannot be undone.**

If archived properties still hold a value on the record, they are listed read-only in an **Archived properties** panel (archived Sections properties are not shown).

## Import and export records

Each records list has **Export CSV** and **Import CSV** buttons. Export downloads the list as a CSV file named after the type's key. Import opens a dialog titled **Import {plural name}**: upload one `.csv` file with a header row. Rows are processed independently: valid rows import even when others fail, and the result shows counts of created, updated, and failed rows plus an error per failed row number. The list refreshes after a successful import.
