Domains
Every project has at least one domain, and all code outside the root files lives in one. The folder's name is the domain's name. Nothing in the code declares it, so the two can't disagree. Domains are one level deep and never nest.
Name a domain after a business area (ordering, planning), not a plural
entity (orders, todos). Domain names appear in calls, so they must not
read like variables. Generic names (misc, common, utils, helpers,
core) are refused for domains and libraries alike.
Split a domain only along a seam the compiler shows has no references
across it ("these 12 entities never reference these 9"). A large domain
whose parts depend on each other stays large: size alone is not a reason
to split. jadpo domain rename, split and merge do the moves and update
every call.
A domain contains only these folders, each named after its declaration keyword, and only when they have files. There are no subfolders; that is to be revisited if a folder in a real application passes about 60 files.
| Folder | Holds | Notes |
|---|---|---|
entities/ |
One entity per file: its fields, unique rules, lifecycle, policy and record caches. The generated operations (Todo.get, create, update, delete) belong to it |
Queries, actions and failures each have their own folder (Failures, Data) |
types/ |
Types used by more than one file in the domain | A type one file uses lives beside its user |
failures/ |
One failure per file, every failure the domain raises | A failure two or more domains raise goes in shared/failures/ (Failures) |
actions/ |
Every action, one per file | Called by name (complete_todo(todo_id)); called by triggers or, if public, by other domains |
queries/ |
Every query, one per file, whatever it reads; a query's cache sits in its file | Data |
libraries/ |
Named groups of helper functions and constants, such as library rounding |
Called like the standard library: rounding.half_even(x), pricing.vat_rate (Constants) |
routes/ |
Named route groups with a prefix the compiler checks | The HTTP trigger: the URL is written in the source |
schedules/ |
Time triggers: when to run which action | |
events/ |
Event definitions | |
subscribers/ |
Event triggers, including long-running coordination | |
| (none) | Outside APIs are provider packages: connections in app.jadpo, installed packages in the root packages/, pinned in jadpo.lock, and the app's own in shared/providers/ |
Integrations; there is no integrations/ folder and no integration keyword |
emails/ |
Email types and their templates, one email per name (welcome_email.jadpo, welcome_email.html, welcome_email.txt), and the domain's own email partials, laid out the same way |
|
translations/ |
One type X = Message per file; one translations { } language file per locale, named after it (de_de.jadpo), wording the domain's messages, failures, enums and email subjects; and the generated, committed sources.jadpo_record (Records and manifest) |
Configuration and time; a message a second domain uses goes in shared/translations/. A language file is named after its locale, not after its translations { } |
prompts/ |
One type X = Prompt per file, each with its text in <name>.prompt beside it, in two sections, # Instructions and # Request |
Prompts as files; a prompt a second domain uses goes in shared/prompts/, as a message does |
documents/ |
Document types and their templates, one document per name (invoice_document.jadpo, invoice_document.html), rendered to HTML or PDF by the documents capability |
Documents |
fixtures/ |
Test data shared by several test files in the domain |
Not built yet: jadpo domain rename, split and merge; and the
documents capability, so until it is, a file in documents/ is
layout.unknown_location.
Markdown for agents: /docs/domains.md.Built from Jadpo main at a707efb.