Data Layer¶
The Data Layer is where your Diagonal app gets its shape.
Before you build pages, automate work, or invite users, you define the things your app needs to know about: customers, orders, students, projects, invoices, tasks, locations, approvals, and anything else your business runs on.
In Diagonal, those things live in Resources.
Core idea
Resources describe your business. Records are the real data inside it.
Create a Resource for each kind of thing your app tracks. Add Fields to describe it. Add Records as the actual entries. Then connect, secure, and extend those Resources as your app grows.
Resources¶
A Resource is a type of thing your application manages.
If you were building a customer portal, you might create Resources for Customers, Contacts, Tickets, Invoices, and Payments. If you were building a school system, you might create Students, Teachers, Courses, Enrollments, and Assignments.
Resources appear in System Admin → Resources. Choose Create Resource to add one. When you open a Resource, Diagonal gives you a focused workspace for shaping that part of your app:
| Area | What it is for |
|---|---|
| Records | Open the Records stored by the Resource. |
| General | Edit the Resource name and display Field. Enable Capabilities that give the Resource platform behavior, and manage Shared Filters. |
| Fields | Add Fields and Relations that define the Resource structure. Configure record search, database indexes, and semantic search. |
| Access | Add Policies that control Record and Field access, and choose which Data API operations this Resource exposes. |
Start with nouns
A good Resource usually sounds like a business noun: Customer, Project, Order, Invoice, Employee, Student, Location, Asset, Appointment. If you can say “we need to track many of these,” it is probably a Resource.
Discover the API import format¶
Before you prepare an NDJSON import file, request the import record schema at /api/data/imports/resources/{resource}/schema on your workspace domain for each destination Resource. Replace {resource} with the Resource UUID. Send your workspace API key as a Bearer token. Your identity must have manage_data_imports permission.
The response is a JSON Schema document for one line of the file. It describes resource_id or resource_ref, source_id, optional timestamps, and writable values. System-managed fields can appear in values, but the import ignores them. Relations use source references such as {"id":"customer-1"}. They do not accept inline records. If you use resource_ref, map it to the destination Resource in the import session.
Use the schema to prepare your file. After upload, call POST /api/data/imports/{import}/validate. The server checks permissions, uniqueness, source references, field rules, and other constraints that need workspace data. You can also find the schema operation under Data Imports in your workspace's /docs/api reference.
An import file can also add historical email messages to the email history of your records. Give such a line "target":"email_message", a source_id, and values. Request its schema at /api/data/imports/targets/email-message/schema. The values hold the sender, recipients, subject, send time, and body. They can also list the records that show the message. The import writes email messages after all records, so a message can name a record from the same file. The import never sends these messages. If an earlier import already added a message with the same source_id, the import keeps that message and skips the line.
An import file can also add images to your Media Library. Give such a line "target":"media_library_item", a source_id, and values with a display_name, an optional folder, and a file that names an image asset of the import, such as {"$file":"images/logo.jpg"}. Request its schema at /api/data/imports/targets/media-library-item/schema. The import writes images before all records. A Markdown field of a record can then show an image as , link it as [](https://example.com), or name it by its asset as asset:<asset name>. The import replaces each asset: destination with the address of the image. A width written right after the image, such as {width=430}, stays. An asset:media: destination can also name an image that an earlier import added. If an earlier import already added an image with the same source_id, the import keeps that image and updates its name and folder. By default, the import does not generate search keywords for the images.
After an import finishes with completed_with_failures, call GET /api/data/imports/{import}/failures to find the lines that were not written. The response lists each line with its file id, line number, source_id, and Resource. A line with the outcome failed has its own error code, message, and Field errors. A line with the outcome rolled_back was not written because its batch failed. Its error code and message describe the batch failure. When one line caused that failure, caused_by_file_id and caused_by_line name it. Use page and per_page (up to 500) to read more lines.
Fields¶
Fields describe what each record stores.
A Customer Resource might have fields for name, email, phone number, company, status, owner, and signup date. An Invoice Resource might have invoice number, customer, due date, total, payment status, and PDF file.
When you add a Field, you choose the kind of value it should hold. The picker shows only types supported by Resource Fields, not every variable type used elsewhere in Diagonal. See the Field Types guide for the current catalog and per-type settings.
Useful Field settings include:
| Setting | Why it matters |
|---|---|
| Label | The human-friendly name people see in System Admin and app Pages. |
| Key | The stable identifier used by workflows and dynamic values. |
| Description | Helper text that explains what the field means. |
| Type | The kind of value the field accepts. |
| Rules | Validation that keeps record data clean and predictable. |
| Searchable | Makes the field useful when people search records. |
| Unique | Prevents duplicate values, such as duplicate emails or invoice numbers. |
Keep fields business-readable
A builder should be able to scan a Resource and understand the business object without reading workflow logic. Clear field names make the rest of the app easier to build.
Records¶
Records are the actual entries inside a Resource.
If Customers is the Resource, each customer is a Record. If Projects is the Resource, each project is a Record.
Records can be created and updated from System Admin, from Pages your users interact with, or from Workflows that automate business processes. Field rules are applied when Records are saved, so the structure you define with Fields becomes the foundation for clean data everywhere else.
Every Resource also has built-in system details that Diagonal manages for you, such as when a Record was created, updated, or archived. Normal deletion archives a Record so supported relation effects and restore behavior remain predictable.
Records on installed package Resources can be read-only or non-extensible. When New Record is disabled, inspect the Package's ownership policy rather than trying to bypass the Resource action.
Relations¶
Relations connect one Resource to another.
They are how your app understands that an Order belongs to a Customer, a Task belongs to a Project, a Student belongs to many Courses, or an Invoice has many Payments.
When you create a Relation, you are teaching Diagonal how two business objects fit together. That connection can then be used in pages, workflows, filters, and record views.
| Relation type | Best for | Example | | --- | --- | | Belongs to | A record points to one parent record. | An Order belongs to one Customer. | | Has many | A parent record owns a list of related records. | A Customer has many Orders. | | Has one | A record has exactly one related detail record. | An Employee has one Profile. | | Belongs to many | Records can connect to many records on both sides. | Students belong to many Courses. |
Belongs To¶
Use belongs to when each record should point back to one parent.
For example, if every Order is for one Customer, add a Customer relation on Orders. When someone opens an order, Diagonal can show which customer it belongs to. Workflows can also use that relation to send an email to the customer, update the customer account, or show customer details on an order page.
Has Many¶
Use has many when you want to look from the parent to the related records.
If Orders belong to Customers, then Customers can have many Orders. This makes it natural to build a customer detail page with a list of all orders for that customer, or a workflow that counts how many active orders a customer has.
Has One¶
Use has one when a record should have one related companion record.
For example, an Employee might have one Profile, one Emergency Contact, or one Payroll Setup. This keeps the main Employee Resource clean while still letting you store extra structured details in a separate Resource.
Belongs To Many¶
Use belongs to many when both sides can have multiple connections.
Students can enroll in many Courses, and each Course can have many Students. Products can belong to many Collections, and each Collection can contain many Products. Tags can apply to many Articles, and each Article can have many Tags.
If the connection itself needs details, create a separate Resource for it. For example, if an enrollment needs a status, start date, end date, or grade, create an Enrollments Resource that connects Students and Courses.
Relation modeling rule
If the relationship is just a connection, use a Relation. If the relationship has its own data, make it a Resource.
Policies¶
Policies control who can access records in a Resource.
Think of Policies as guardrails around the data itself. Roles and Permissions decide what a user is allowed to do across the app. Policies decide which records they can interact with for a specific Resource.
Capabilities¶
Capabilities let a Resource do more than store data.
They turn a Resource into something the platform can treat in a special way. For example, a Resource can become authenticatable, which means records in that Resource represent people who can log in. Another Resource might become payable, notifiable, scheduled, or connected to payment behavior.
Capabilities are configured from the General tab on a Resource. Each capability has its own settings, and Diagonal will show configuration issues when a required field or option is missing.
Files¶
File Fields store references to Diagonal Files. Keep them Private unless anonymous access is intentional; private Record Files inherit Resource Policy and Field-visibility checks. Use the Media Library for assets builders need to reuse across Pages and content.