Summary#
An Osy# project is a manifest and four folders. The folders are not a style preference — they decide what is deployed and what merely runs, so putting a file in the wrong one has consequences.
Signature#
app.osy the manifest — what compiles, what is tested, which capabilities the app uses
model/ entities, functions, security, UI (compiled and deployed)
seed/ data the app needs in order to exist (compiled and deployed)
migrations/ explicit schema and data migrations (passed to a deploy, not compiled)
tests/ [Test] functions (run, never deployed)Description#
Why the split matters#
model/ and tests/ are the two you will use every day, and the line between them is the one that matters: tests
are never deployed. A [Test] function lives in tests/, runs against a throwaway clone of the app, and never
reaches production — so a test may create rows, break rules and assert on the wreckage without any of it mattering.
Anything in model/ is the application. If you put a test helper there, you have shipped it.
Splitting model/ up#
model/ is a glob, so its internal shape is yours. One file per area reads well and keeps a diff small:
model/
orders.osy entities + the functions that act on them
customers.osy
security.osy the security rules, in one place you can review
ui/ components and pagesThere is no required file naming and no ordering rule — the compiler reads the whole model as one unit, so a function in one file may freely reference an entity declared in another.
Seed vs migrations#
They are easy to confuse and they answer different questions.
seed/— data the app cannot exist without: the roles, the statuses, the country list. It is re-applied to make the app be what it says it is, so it must be safe to run repeatedly.migrations/— a one-time, explicit change to an existing deployment: a column that needs backfilling, a non-additive schema change you have reviewed and authorised, or where a workflow run parked in a state you changed now stands.
If you find yourself wanting to "just seed" a production fix, you want a migration.
A *.migration is not compiled with your model, and it could not be: it is written against one PAIR of
versions and applied once, so re-applying it on every compile is exactly what must not happen. You hand it to the
deploy that needs it — osy compile --migration migrations/<name>.migration — and
osy compile --generate-migration writes it here for you to review first.
See also#
- app.osy — the
app.osythat names these folders - Compiling your app —
osy compile, which compiles model/ and seed/, and takes a migration with--migration - Running tests locally — running what is in
tests/