@loj-lang/cli 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -0
- package/agent-assets/loj-authoring/SKILL.md +179 -0
- package/agent-assets/loj-authoring/agents/openai.yaml +3 -0
- package/agent-assets/loj-authoring/metadata.json +6 -0
- package/agent-assets/loj-authoring/references/backend-family.md +340 -0
- package/agent-assets/loj-authoring/references/backend-targets.md +171 -0
- package/agent-assets/loj-authoring/references/frontend-family.md +794 -0
- package/agent-assets/loj-authoring/references/frontend-runtime-trace.md +204 -0
- package/agent-assets/loj-authoring/references/policy-rules-proof.md +178 -0
- package/agent-assets/loj-authoring/references/project-and-transport.md +454 -0
- package/agent-assets/loj-authoring/references/workflow-flow-proof.md +263 -0
- package/dist/database-native-sql.d.ts +4 -0
- package/dist/database-native-sql.d.ts.map +1 -0
- package/dist/database-native-sql.js +266 -0
- package/dist/database-native-sql.js.map +1 -0
- package/dist/env.d.ts +31 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +229 -0
- package/dist/env.js.map +1 -0
- package/dist/fastapi-dev-runner.d.ts +3 -0
- package/dist/fastapi-dev-runner.d.ts.map +1 -0
- package/dist/fastapi-dev-runner.js +263 -0
- package/dist/fastapi-dev-runner.js.map +1 -0
- package/dist/flow-proof.d.ts +3 -0
- package/dist/flow-proof.d.ts.map +1 -0
- package/dist/flow-proof.js +2 -0
- package/dist/flow-proof.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5353 -0
- package/dist/index.js.map +1 -0
- package/dist/rules-proof.d.ts +3 -0
- package/dist/rules-proof.d.ts.map +1 -0
- package/dist/rules-proof.js +2 -0
- package/dist/rules-proof.js.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# @loj-lang/cli
|
|
2
|
+
|
|
3
|
+
Repo-level orchestration CLI for `loj.project.yaml`.
|
|
4
|
+
|
|
5
|
+
Current implemented commands:
|
|
6
|
+
|
|
7
|
+
- `loj validate`
|
|
8
|
+
- `loj build`
|
|
9
|
+
- `loj dev`
|
|
10
|
+
- `loj status`
|
|
11
|
+
- `loj stop`
|
|
12
|
+
- `loj doctor`
|
|
13
|
+
- `loj rules validate`
|
|
14
|
+
- `loj rules build`
|
|
15
|
+
- `loj flow validate`
|
|
16
|
+
- `loj flow build`
|
|
17
|
+
- `loj agent install <codex|windsurf|generic>`
|
|
18
|
+
- `loj agent add <codex|windsurf|generic> --from <source>`
|
|
19
|
+
- `loj agent export <codex|windsurf|generic> --out-dir <dir>`
|
|
20
|
+
|
|
21
|
+
This package coordinates sibling frontend and backend targets rather than replacing target-local CLIs.
|
|
22
|
+
Its agent commands only distribute the bundled `loj-authoring` skill; they do not replace the
|
|
23
|
+
canonical syntax docs or the manifest/inspect/trace contract.
|
|
24
|
+
|
|
25
|
+
Recommended project-shell loop:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# inspect dependencies, generated outputs, linked files, and current dev state
|
|
29
|
+
npx @loj-lang/cli doctor ./loj.project.yaml
|
|
30
|
+
|
|
31
|
+
# start the managed host/backend loop
|
|
32
|
+
npx @loj-lang/cli dev ./loj.project.yaml
|
|
33
|
+
|
|
34
|
+
# inspect current URLs, services, probes, and debugger endpoints
|
|
35
|
+
npx @loj-lang/cli status ./loj.project.yaml
|
|
36
|
+
|
|
37
|
+
# stop the active managed session
|
|
38
|
+
npx @loj-lang/cli stop ./loj.project.yaml
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# validate a standalone policy/rules proof file
|
|
45
|
+
npx @loj-lang/cli rules validate ./policies/invoice-access.rules.loj
|
|
46
|
+
|
|
47
|
+
# emit a target-neutral semantic manifest
|
|
48
|
+
npx @loj-lang/cli rules build ./policies/invoice-access.rules.loj --out-dir ./generated/rules
|
|
49
|
+
|
|
50
|
+
# validate a standalone workflow/state-machine proof file
|
|
51
|
+
npx @loj-lang/cli flow validate ./workflows/booking-process.flow.loj
|
|
52
|
+
|
|
53
|
+
# emit a shared workflow manifest
|
|
54
|
+
npx @loj-lang/cli flow build ./workflows/booking-process.flow.loj --out-dir ./generated/flow
|
|
55
|
+
|
|
56
|
+
# install into CODEX_HOME/skills or ~/.codex/skills
|
|
57
|
+
npx @loj-lang/cli agent install codex
|
|
58
|
+
|
|
59
|
+
# install into WINDSURF_HOME/skills or ~/.codeium/windsurf/skills
|
|
60
|
+
npx @loj-lang/cli agent install windsurf
|
|
61
|
+
|
|
62
|
+
# vendor a pinned project copy under ./.loj/agents/codex/skills
|
|
63
|
+
npx @loj-lang/cli agent install codex --scope project
|
|
64
|
+
|
|
65
|
+
# add a skill bundle from a local or remote source
|
|
66
|
+
npx @loj-lang/cli agent add codex --from ./tooling/skills/loj-authoring
|
|
67
|
+
|
|
68
|
+
# install into any explicit skills directory
|
|
69
|
+
npx @loj-lang/cli agent install generic --skills-dir ~/.my-agent/skills
|
|
70
|
+
|
|
71
|
+
# export into any custom directory
|
|
72
|
+
npx @loj-lang/cli agent export codex --out-dir ./tooling/skills
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The current `.rules.loj` slice is intentionally narrow: one named rule set per file, grouped
|
|
76
|
+
`allow/deny`, `eligibility`, `validate`, and `derive` entries, standalone manifest emission
|
|
77
|
+
through `loj rules build`, plus narrow backend-family linkage through `resource auth.policy`,
|
|
78
|
+
`resource create.rules`, and `readModel rules`. It is still not orchestrated through
|
|
79
|
+
`loj.project.yaml`. The current `.flow.loj` slice is even narrower: standalone validate/build
|
|
80
|
+
only, with one `workflow <name>:` block compiling to a shared workflow manifest.
|
|
81
|
+
|
|
82
|
+
Local workspace commands:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm run build --workspace=@loj-lang/cli
|
|
86
|
+
npm run test --workspace=@loj-lang/cli
|
|
87
|
+
```
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: loj-authoring
|
|
3
|
+
description: >
|
|
4
|
+
Use this skill when creating, editing, reviewing, or debugging `.web.loj` / legacy `.rdsl`
|
|
5
|
+
files, `.api.loj` / legacy `.sdsl` files, `.style.loj` files, linked `.rules.loj` / `.flow.loj`
|
|
6
|
+
slices, or `loj.project.yaml` orchestration files for the Loj DSL framework. Covers current
|
|
7
|
+
web/api/style family syntax, linked rules/workflow/SQL escape hatches, project-shell
|
|
8
|
+
database/runtime/dev commands, and how those inputs map to generated React, Spring Boot, and
|
|
9
|
+
FastAPI output.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Loj Authoring
|
|
13
|
+
|
|
14
|
+
Use this skill for:
|
|
15
|
+
|
|
16
|
+
- frontend-family `.web.loj` / legacy `.rdsl`
|
|
17
|
+
- style `.style.loj`
|
|
18
|
+
- backend-family `.api.loj` / legacy `.sdsl`
|
|
19
|
+
- linked `.rules.loj`
|
|
20
|
+
- linked `.flow.loj`
|
|
21
|
+
- `loj.project.yaml`
|
|
22
|
+
|
|
23
|
+
(For codex) If this skill is missing outside the repo, current install/export commands are:
|
|
24
|
+
|
|
25
|
+
- `npx @loj-lang/cli agent install codex`
|
|
26
|
+
- `npx @loj-lang/cli agent install codex --scope project`
|
|
27
|
+
- `npx @loj-lang/cli agent export codex --out-dir ./tooling/skills`
|
|
28
|
+
|
|
29
|
+
All portable technique references required by this skill live in `references/`.
|
|
30
|
+
You may not have knowledge of the Loj DSL framework at this time, so you must read the references to understand the syntax and semantics of the DSL.
|
|
31
|
+
This skill should remain usable even when vendored outside the repo.
|
|
32
|
+
|
|
33
|
+
| Task involves | Read |
|
|
34
|
+
|---|---|
|
|
35
|
+
| frontend-family syntax, models/resources/pages/read-model pages, style/SEO/assets, workflow-linked surfaces | `references/frontend-family.md` |
|
|
36
|
+
| generated React runtime assumptions, runtime imports, inspect/trace behavior | `references/frontend-runtime-trace.md` |
|
|
37
|
+
| backend-family syntax, models/resources/read-models, linked rules/workflow/SQL, transaction defaults | `references/backend-family.md` |
|
|
38
|
+
| Spring Boot / FastAPI target-specific output and escape-hatch constraints | `references/backend-targets.md` |
|
|
39
|
+
| standalone policy/rules proof syntax and current linkage boundaries | `references/policy-rules-proof.md` |
|
|
40
|
+
| standalone workflow/state-machine syntax and current linked resource behavior | `references/workflow-flow-proof.md` |
|
|
41
|
+
| `loj.project.yaml`, project-shell database/runtime slices, dev/status/doctor flows, frontend↔backend transport alignment | `references/project-and-transport.md` |
|
|
42
|
+
|
|
43
|
+
## Workflow
|
|
44
|
+
|
|
45
|
+
1. Identify whether the task is frontend-family, backend-family, linked rules/workflow, or project-shell orchestration.
|
|
46
|
+
2. For new source, prefer canonical suffixes and target names:
|
|
47
|
+
- `.web.loj`, `.api.loj`
|
|
48
|
+
- `type: web`, `type: api`
|
|
49
|
+
3. Read only the minimal bundled reference slice from the router above.
|
|
50
|
+
4. Generate only implemented syntax from those references.
|
|
51
|
+
5. If the requested shape is outside the current slice, say so and use the narrowest implemented escape hatch or project/runtime profile.
|
|
52
|
+
|
|
53
|
+
## Command Shortcuts
|
|
54
|
+
|
|
55
|
+
Default recommendation: use project-shell commands first whenever a `loj.project.yaml` exists.
|
|
56
|
+
|
|
57
|
+
- preferred default:
|
|
58
|
+
- `loj validate loj.project.yaml`
|
|
59
|
+
- `loj build loj.project.yaml`
|
|
60
|
+
- `loj dev loj.project.yaml`
|
|
61
|
+
- `loj rebuild loj.project.yaml --target <alias>`
|
|
62
|
+
- `loj restart loj.project.yaml --service <host|server|all>`
|
|
63
|
+
- `loj status loj.project.yaml`
|
|
64
|
+
- `loj stop loj.project.yaml`
|
|
65
|
+
- `loj doctor loj.project.yaml`
|
|
66
|
+
- single-target project-shell:
|
|
67
|
+
- `loj validate loj.project.yaml --target <alias>`
|
|
68
|
+
- `loj build loj.project.yaml --target <alias>`
|
|
69
|
+
- `loj dev loj.project.yaml --target <alias>`
|
|
70
|
+
- `loj status loj.project.yaml --target <alias>`
|
|
71
|
+
- `loj doctor loj.project.yaml --target <alias>`
|
|
72
|
+
- standalone rules proof:
|
|
73
|
+
- `loj rules validate <entry.rules.loj>`
|
|
74
|
+
- `loj rules build <entry.rules.loj> --out-dir <dir>`
|
|
75
|
+
- standalone workflow proof:
|
|
76
|
+
- `loj flow validate <entry.flow.loj>`
|
|
77
|
+
- `loj flow build <entry.flow.loj> --out-dir <dir>`
|
|
78
|
+
- family-local fallback:
|
|
79
|
+
- `rdsl validate <entry.web.loj>`
|
|
80
|
+
- `rdsl build <entry.web.loj> --out-dir <dir>`
|
|
81
|
+
- `sdsl validate <entry.api.loj>`
|
|
82
|
+
- `sdsl build <entry.api.loj> --out-dir <dir>`
|
|
83
|
+
|
|
84
|
+
Use `rdsl` / `sdsl` mainly for pure single-family work or compiler/debug tasks. Do not treat them as
|
|
85
|
+
the default entrypoint for new multi-file app work when `loj.project.yaml` exists.
|
|
86
|
+
|
|
87
|
+
Useful debugging commands:
|
|
88
|
+
|
|
89
|
+
- `rdsl inspect <entry.web.loj|build-dir> [--node <id>]`
|
|
90
|
+
- `rdsl trace <entry.web.loj|build-dir> <generated-file:line[:col]>`
|
|
91
|
+
|
|
92
|
+
## Hard Rules
|
|
93
|
+
|
|
94
|
+
### Common
|
|
95
|
+
|
|
96
|
+
- Files are a strict YAML subset: no anchors, aliases, merge keys, or custom tags.
|
|
97
|
+
- For new files, use canonical suffixes; keep `.rdsl` / `.sdsl` only for legacy edits.
|
|
98
|
+
- Prefer single-file apps for small demos. Use `imports:` only when the app really benefits from splitting by domain.
|
|
99
|
+
- `imports:` entries are relative family-source paths (`.web.loj` / `.rdsl`, `.api.loj` / `.sdsl`) or directories ending with `/`.
|
|
100
|
+
- Nested imports are allowed. Cycles are invalid. Directory imports expand direct children only.
|
|
101
|
+
- One root file owns `app:` and `compiler:`. Module files may not contain them.
|
|
102
|
+
- Model/resource names must stay unique across the merged namespace.
|
|
103
|
+
- Keep primitives target-neutral and business-oriented.
|
|
104
|
+
- Do not leak framework/runtime specifics into the DSL source.
|
|
105
|
+
|
|
106
|
+
### Frontend-family
|
|
107
|
+
|
|
108
|
+
- Expression language stays constrained. No loops, statements, closures, or inline JS outside implemented escape hatches.
|
|
109
|
+
- Escape preference: built-in DSL > `@expr` > `@fn` > `@custom`.
|
|
110
|
+
- Treat suffix-bearing escape paths such as `.ts` / `.tsx` as deliberate frontend lock-in, not the default style.
|
|
111
|
+
- `toast` accepts static string or descriptor only.
|
|
112
|
+
- Current UI-copy descriptor support is still narrow:
|
|
113
|
+
- use plain strings for fixed copy
|
|
114
|
+
- use `{ key?, defaultMessage?, values? }` when future i18n or scalar-literal interpolation matters
|
|
115
|
+
- copy descriptors are currently implemented only on the documented title/label/date-navigation/SEO slices
|
|
116
|
+
- `app.style` links `.style.loj`; shell-level `style:` references are currently narrow and do not imply table internals or responsive/mobile variants.
|
|
117
|
+
- `app.seo`, `page.seo`, and `@asset(...)` are web metadata/asset surfaces, not style DSL features.
|
|
118
|
+
- Escape file paths resolve relative to the declaring `.web.loj` file, not the root file.
|
|
119
|
+
|
|
120
|
+
### Backend-family
|
|
121
|
+
|
|
122
|
+
- `compiler:` must use an implemented `target + language + profile` triple.
|
|
123
|
+
- `auth:` describes policy intent, not framework internals.
|
|
124
|
+
- `operations:` controls generated CRUD endpoints; all default `true` if omitted.
|
|
125
|
+
- No frontend concepts like pages, navigation, columns, or toast in `.api.loj`.
|
|
126
|
+
- Do not encode Java/Python/SQLAlchemy/JPA into DSL primitives; keep them in target/profile or escape-hatch code.
|
|
127
|
+
- `resource auth.policy` may use either `@fn("./policies/x")` or `@rules("./policies/x")`.
|
|
128
|
+
- `resource create.rules` may use `@rules("./rules/x")` for narrow create eligibility/validation.
|
|
129
|
+
- `readModel rules` may use `@rules("./rules/x")` for narrow eligibility/validation/derivation.
|
|
130
|
+
- `resource workflow` may use `@flow("./workflows/x")`.
|
|
131
|
+
- `readModel handler` may use `@fn("./handlers/x")` or narrow file-backed `@sql("./queries/x")`.
|
|
132
|
+
- `@sql(...)` is read-model-only, read-only, and file-backed; keep procedures and write-oriented SQL in `@fn(...)`.
|
|
133
|
+
- Generated write paths are transactional by default in the implemented targets; do not invent `transactional: true`.
|
|
134
|
+
|
|
135
|
+
### `.rules.loj`
|
|
136
|
+
|
|
137
|
+
- Use exactly one top-level `rules <name>:` block per file.
|
|
138
|
+
- Stay within the current slice:
|
|
139
|
+
- `allow/deny <operation>`
|
|
140
|
+
- `eligibility <name>`
|
|
141
|
+
- `validate <name>`
|
|
142
|
+
- `derive <field>`
|
|
143
|
+
- shared `when`, optional `or`, optional `message`, and list-only `scopeWhen/scope` on auth entries
|
|
144
|
+
- `.rules.loj` is linked only through the documented frontend/backend slices; do not invent new integration points.
|
|
145
|
+
- Do not put `.rules.loj` under `loj.project.yaml`.
|
|
146
|
+
|
|
147
|
+
### `.flow.loj`
|
|
148
|
+
|
|
149
|
+
- Use exactly one top-level `workflow <name>:` block per file.
|
|
150
|
+
- Stay within the current slice:
|
|
151
|
+
- `model`
|
|
152
|
+
- `field`
|
|
153
|
+
- `states`
|
|
154
|
+
- optional `wizard.steps`
|
|
155
|
+
- `transitions`
|
|
156
|
+
- `.flow.loj` is linked only through `resource workflow: ...` in `.web.loj` / `.api.loj`.
|
|
157
|
+
- Do not invent project-shell workflow targets, page-level router DSL, or framework-specific state-machine syntax.
|
|
158
|
+
|
|
159
|
+
### `loj.project.yaml`
|
|
160
|
+
|
|
161
|
+
- `loj.project.yaml` is orchestration only. Never place `model`, `resource`, `page`, or backend implementation details in it.
|
|
162
|
+
- Prefer `type: web` / `type: api`. Treat `type: rdsl` / `type: sdsl` as deprecated legacy aliases.
|
|
163
|
+
- `entry` should point at canonical suffixes for new examples: `app.web.loj`, `app.api.loj`.
|
|
164
|
+
- Database/runtime/dev orchestration belongs here, not in `.web.loj` / `.api.loj`.
|
|
165
|
+
- Keep `dev:` and `targets.<alias>.runtime` narrow and declarative. Do not turn them into arbitrary scripting or general ops config.
|
|
166
|
+
- For new projects, default to the recommended bundled directory structure from `references/project-and-transport.md` instead of inventing an ad hoc tree.
|
|
167
|
+
|
|
168
|
+
## Review Before Final Output
|
|
169
|
+
|
|
170
|
+
- Valid strict-YAML-subset?
|
|
171
|
+
- Canonical suffix/type chosen for new files unless editing legacy input?
|
|
172
|
+
- Read from bundled `references/` rather than guessing from stale memory?
|
|
173
|
+
- Top-level keys allowed for this file type (root vs module)?
|
|
174
|
+
- Model/resource names unique project-wide?
|
|
175
|
+
- Rules/effects within the implemented slice?
|
|
176
|
+
- Escape hatches narrow and intentional?
|
|
177
|
+
- No framework/runtime detail leaking into family DSL source?
|
|
178
|
+
- For `.api.loj`: implemented `target/language/profile` triple and current linkage boundaries respected?
|
|
179
|
+
- For `loj.project.yaml`: orchestration-only, with `web/api` preferred and database/runtime/dev slices kept narrow?
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.5.0",
|
|
3
|
+
"organization": "Loj",
|
|
4
|
+
"date": "March 2026",
|
|
5
|
+
"abstract": "Unified AI authoring skill for the Loj DSL framework. Covers frontend-family .web.loj (legacy .rdsl), backend-family .api.loj (legacy .sdsl), style .style.loj, linked .rules.loj and .flow.loj sub-DSL slices, and loj.project.yaml orchestration authoring, review, and debugging. Uses bundled references for current syntax, runtime, transport, project-shell, style, and generated-output guidance."
|
|
6
|
+
}
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# Backend-Family Authoring (`.api.loj`, legacy `.sdsl`)
|
|
2
|
+
|
|
3
|
+
Use this reference when authoring or reviewing backend-family source files.
|
|
4
|
+
|
|
5
|
+
## Defaults
|
|
6
|
+
|
|
7
|
+
- Prefer `.api.loj` for new files. Use `.sdsl` only for legacy edits.
|
|
8
|
+
- Files are a strict YAML subset:
|
|
9
|
+
- no anchors
|
|
10
|
+
- no aliases
|
|
11
|
+
- no merge keys
|
|
12
|
+
- no custom tags
|
|
13
|
+
|
|
14
|
+
Implemented compiler triples today:
|
|
15
|
+
|
|
16
|
+
- `spring-boot / java / mvc-jpa-security`
|
|
17
|
+
- `fastapi / python / rest-sqlalchemy-auth`
|
|
18
|
+
|
|
19
|
+
If `compiler:` is omitted, default is the Spring triple above.
|
|
20
|
+
|
|
21
|
+
## File Shape
|
|
22
|
+
|
|
23
|
+
Root files may contain:
|
|
24
|
+
|
|
25
|
+
- `app:`
|
|
26
|
+
- optional `compiler:`
|
|
27
|
+
- optional `imports:`
|
|
28
|
+
- `model <Name>:`
|
|
29
|
+
- `resource <name>:`
|
|
30
|
+
- `readModel <name>:`
|
|
31
|
+
|
|
32
|
+
Module files may contain:
|
|
33
|
+
|
|
34
|
+
- optional `imports:`
|
|
35
|
+
- `model <Name>:`
|
|
36
|
+
- `resource <name>:`
|
|
37
|
+
- `readModel <name>:`
|
|
38
|
+
|
|
39
|
+
Module files may not contain `app:` or `compiler:`.
|
|
40
|
+
|
|
41
|
+
## Imports
|
|
42
|
+
|
|
43
|
+
- Use single-file for small demos.
|
|
44
|
+
- Split by domain only when the service grows.
|
|
45
|
+
- `imports:` entries must be relative `.api.loj` / `.sdsl` paths or directories ending in `/`.
|
|
46
|
+
- Nested imports are allowed.
|
|
47
|
+
- Import cycles are invalid.
|
|
48
|
+
- Directory imports expand direct child family files only, sorted lexicographically.
|
|
49
|
+
|
|
50
|
+
## `app:`
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
app:
|
|
54
|
+
name: "Booking Service"
|
|
55
|
+
package: "com.example.booking"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Rules:
|
|
59
|
+
|
|
60
|
+
- `name` is required
|
|
61
|
+
- `package` is required
|
|
62
|
+
- `package` must be a valid dotted Java-style package root
|
|
63
|
+
- do not place auth provider, database vendor, shutdown, proxy, or deploy details here
|
|
64
|
+
|
|
65
|
+
## `compiler:`
|
|
66
|
+
|
|
67
|
+
```yaml
|
|
68
|
+
compiler:
|
|
69
|
+
target: spring-boot
|
|
70
|
+
language: java
|
|
71
|
+
profile: mvc-jpa-security
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Rules:
|
|
75
|
+
|
|
76
|
+
- `target`, `language`, and `profile` must form an implemented triple
|
|
77
|
+
- do not encode language into `target`
|
|
78
|
+
- `compiler:` is for generation target selection, not business semantics
|
|
79
|
+
|
|
80
|
+
## `model <Name>:`
|
|
81
|
+
|
|
82
|
+
Example:
|
|
83
|
+
|
|
84
|
+
```yaml
|
|
85
|
+
model Booking:
|
|
86
|
+
reference: string @required @unique
|
|
87
|
+
baseFare: decimal @required
|
|
88
|
+
travelDate: date @required
|
|
89
|
+
status: enum(DRAFT, READY, CONFIRMED, FAILED)
|
|
90
|
+
memberId: belongsTo(Member)
|
|
91
|
+
passengers: hasMany(Passenger, by: bookingId)
|
|
92
|
+
createdAt: datetime @createdAt
|
|
93
|
+
updatedAt: datetime @updatedAt
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Types:
|
|
97
|
+
|
|
98
|
+
- `string`
|
|
99
|
+
- `text`
|
|
100
|
+
- `integer`
|
|
101
|
+
- `long`
|
|
102
|
+
- `decimal`
|
|
103
|
+
- `boolean`
|
|
104
|
+
- `datetime`
|
|
105
|
+
- `date`
|
|
106
|
+
- `enum(A, B, C)`
|
|
107
|
+
- `belongsTo(Model)`
|
|
108
|
+
- `hasMany(Model, by: field)`
|
|
109
|
+
|
|
110
|
+
Decorators:
|
|
111
|
+
|
|
112
|
+
- `@required`
|
|
113
|
+
- `@email`
|
|
114
|
+
- `@unique`
|
|
115
|
+
- `@minLen(n)`
|
|
116
|
+
- `@maxLen(n)`
|
|
117
|
+
- `@createdAt`
|
|
118
|
+
- `@updatedAt`
|
|
119
|
+
|
|
120
|
+
Implicit persistence identity:
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
id: long
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Do not declare `id` manually in `v0.1`.
|
|
127
|
+
|
|
128
|
+
Relation rules:
|
|
129
|
+
|
|
130
|
+
- `belongsTo(Model)` is supported for narrow foreign-key-style relations
|
|
131
|
+
- `hasMany(Model, by: field)` is inverse metadata only
|
|
132
|
+
- `hasMany(..., by: ...)` must point to a target-model field declared as
|
|
133
|
+
`belongsTo(CurrentModel)`
|
|
134
|
+
- current backend-family relation support is metadata plus generated foreign-key handling; it is not
|
|
135
|
+
a query DSL
|
|
136
|
+
|
|
137
|
+
## `readModel <name>:`
|
|
138
|
+
|
|
139
|
+
Example:
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
readModel flightAvailability:
|
|
143
|
+
api: /api/flight-availability
|
|
144
|
+
auth:
|
|
145
|
+
mode: public
|
|
146
|
+
inputs:
|
|
147
|
+
departureAirport: string @required
|
|
148
|
+
departureDate: date @required
|
|
149
|
+
result:
|
|
150
|
+
flightNo: string
|
|
151
|
+
quotedFare: decimal
|
|
152
|
+
handler: '@sql("./queries/flightAvailability")'
|
|
153
|
+
rules: '@rules("./rules/flight-availability")'
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Rules:
|
|
157
|
+
|
|
158
|
+
- current read-models are narrow named GET list surfaces, not a generic query DSL
|
|
159
|
+
- `api` is required and must start with `/`
|
|
160
|
+
- `inputs:` and `result:` reuse model-style field authoring, but currently support scalar and enum
|
|
161
|
+
field shapes only
|
|
162
|
+
- current `inputs:` support only `@required`
|
|
163
|
+
- current `inputs:` do not support `datetime`
|
|
164
|
+
- current `result:` fields do not support decorators
|
|
165
|
+
- `auth:` currently supports only `mode` / `roles`
|
|
166
|
+
- `handler:` is required and must use `@fn("./path")` or `@sql("./path")`
|
|
167
|
+
- extensionless logical ids are preferred; target resolution uses `.java` for Spring and `.py` for
|
|
168
|
+
FastAPI
|
|
169
|
+
- `@sql(...)` is read-model-only and intentionally narrow:
|
|
170
|
+
- file-backed query only
|
|
171
|
+
- read-only `SELECT` / `WITH`
|
|
172
|
+
- no procedures, `CALL`, `EXEC`, or write SQL
|
|
173
|
+
- alias columns to declared `result:` field names
|
|
174
|
+
- `rules:` is optional and must use `@rules("./rules/x")`
|
|
175
|
+
- current read-model rules support only:
|
|
176
|
+
- `eligibility`
|
|
177
|
+
- `validate`
|
|
178
|
+
- `derive`
|
|
179
|
+
- `allow/deny` entries are rejected on backend read-model linkage
|
|
180
|
+
- read-model rule expressions currently allow:
|
|
181
|
+
- `currentUser.*`
|
|
182
|
+
- `input.<field>`
|
|
183
|
+
- `item.<resultField>` inside derivations
|
|
184
|
+
- bare uppercase literals like `ADMIN`
|
|
185
|
+
|
|
186
|
+
## `resource <name>:`
|
|
187
|
+
|
|
188
|
+
Example:
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
resource bookings:
|
|
192
|
+
model: Booking
|
|
193
|
+
api: /api/bookings
|
|
194
|
+
auth:
|
|
195
|
+
mode: authenticated
|
|
196
|
+
roles: [AGENT, ADMIN]
|
|
197
|
+
create:
|
|
198
|
+
rules: '@rules("./rules/booking-create")'
|
|
199
|
+
includes:
|
|
200
|
+
- field: passengers
|
|
201
|
+
fields: [name, seat]
|
|
202
|
+
update:
|
|
203
|
+
includes:
|
|
204
|
+
- field: passengers
|
|
205
|
+
fields: [id, name, seat]
|
|
206
|
+
workflow: '@flow("./workflows/booking-lifecycle")'
|
|
207
|
+
operations:
|
|
208
|
+
list: true
|
|
209
|
+
get: true
|
|
210
|
+
create: true
|
|
211
|
+
update: true
|
|
212
|
+
delete: true
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Current resource rules:
|
|
216
|
+
|
|
217
|
+
- `model` and `api` are required
|
|
218
|
+
- `auth.policy` may use `@fn("./policies/x")` or `@rules("./policies/x")`
|
|
219
|
+
- `create.rules` may use `@rules("./rules/x")`
|
|
220
|
+
- `create.rules` currently supports only:
|
|
221
|
+
- `eligibility`
|
|
222
|
+
- `validate`
|
|
223
|
+
- `create.rules` rejects:
|
|
224
|
+
- `allow/deny`
|
|
225
|
+
- `derive`
|
|
226
|
+
- `create.includes` / `update.includes` are the current one-level aggregate-root nested-write slice
|
|
227
|
+
- they accept only direct `hasMany(Target, by: field)` relations
|
|
228
|
+
- child `fields:` must belong to the target model
|
|
229
|
+
- the inverse `by:` field is seeded automatically and must not be listed again
|
|
230
|
+
- child `fields:` may currently use scalar, enum, or `belongsTo(...)`
|
|
231
|
+
- child `fields:` may not use `hasMany(...)`
|
|
232
|
+
- `update.includes` one-level diff semantics are:
|
|
233
|
+
- child items with `id` update existing children under the parent
|
|
234
|
+
- child items without `id` create new children
|
|
235
|
+
- omitted existing children are deleted
|
|
236
|
+
|
|
237
|
+
Current `workflow:` rules:
|
|
238
|
+
|
|
239
|
+
- `workflow:` is optional and must use `@flow("./workflows/x")`
|
|
240
|
+
- extensionless logical ids are preferred for `workflow:`
|
|
241
|
+
- the linked workflow `model` must match the resource model
|
|
242
|
+
- the linked workflow `field` must point to an `enum(...)` field on that model
|
|
243
|
+
- the linked workflow must declare every enum value from that field, and every declared workflow
|
|
244
|
+
state must exist in that enum
|
|
245
|
+
- generated workflow mutation paths add transition enforcement endpoints and preserve state on normal
|
|
246
|
+
update payloads
|
|
247
|
+
|
|
248
|
+
## Transaction Rule
|
|
249
|
+
|
|
250
|
+
Generated backend write paths are transactional by default in the implemented targets:
|
|
251
|
+
|
|
252
|
+
- `resource create`
|
|
253
|
+
- `resource update`
|
|
254
|
+
- `resource delete`
|
|
255
|
+
- nested `create.includes` / `update.includes`
|
|
256
|
+
- workflow-linked create/update/transition paths
|
|
257
|
+
|
|
258
|
+
Current target behavior:
|
|
259
|
+
|
|
260
|
+
- Spring -> `@Transactional`
|
|
261
|
+
- FastAPI -> one generated `Session` commit/rollback boundary
|
|
262
|
+
|
|
263
|
+
Authors do not need and should not invent `transactional: true` in source DSL.
|
|
264
|
+
|
|
265
|
+
Custom escape hatches keep their own transaction boundary:
|
|
266
|
+
|
|
267
|
+
- `@fn(...)` is responsible for itself
|
|
268
|
+
- `@sql(...)` is read-model-only and read-only today
|
|
269
|
+
|
|
270
|
+
## Backend Escape Hatches
|
|
271
|
+
|
|
272
|
+
Use escape hatches only when the current `.api.loj` slice cannot express the behavior directly.
|
|
273
|
+
|
|
274
|
+
### `readModel handler: '@fn("./handlers/x")'`
|
|
275
|
+
|
|
276
|
+
Use `@fn(...)` for target-local query logic that is too specific for the shared read-model slice.
|
|
277
|
+
|
|
278
|
+
Rules:
|
|
279
|
+
|
|
280
|
+
- the handler file is a target-language function-body snippet, not a full controller/service/module
|
|
281
|
+
- extensionless logical ids are preferred
|
|
282
|
+
- Spring resolves to `.java`
|
|
283
|
+
- FastAPI resolves to `.py`
|
|
284
|
+
|
|
285
|
+
Current snippet contract:
|
|
286
|
+
|
|
287
|
+
- Spring executes inside:
|
|
288
|
+
- `List<ReadModelResult> execute(ReadModelInput input, PolicyPrincipal principal)`
|
|
289
|
+
- FastAPI executes inside:
|
|
290
|
+
- `def execute(db: Session, input: ReadModelInput, principal: AuthenticatedUser | None) -> list[ReadModelResult]`
|
|
291
|
+
|
|
292
|
+
Current file-shape rule:
|
|
293
|
+
|
|
294
|
+
- backend `@fn(...)` read-model handlers are function-body snippets
|
|
295
|
+
- do not include package declarations, imports, class declarations, or outer function declarations
|
|
296
|
+
- write only the body that runs inside the generated adapter function
|
|
297
|
+
|
|
298
|
+
Keep handler code target-local:
|
|
299
|
+
|
|
300
|
+
- use repositories / ORM / raw SQL as needed inside the snippet
|
|
301
|
+
- do not try to invent backend-family query-builder syntax around it
|
|
302
|
+
|
|
303
|
+
### `readModel handler: '@sql("./queries/x")'`
|
|
304
|
+
|
|
305
|
+
Use `@sql(...)` only for narrow read-only read-model handlers.
|
|
306
|
+
|
|
307
|
+
Rules:
|
|
308
|
+
|
|
309
|
+
- file-backed only; do not inline large SQL strings into `.api.loj`
|
|
310
|
+
- read-only `SELECT` / `WITH` only
|
|
311
|
+
- no procedures, `CALL`, `EXEC`, or write SQL
|
|
312
|
+
- alias result columns to the declared `result:` field names
|
|
313
|
+
- Spring gets a generated `NamedParameterJdbcTemplate` adapter
|
|
314
|
+
- FastAPI gets a generated `sqlalchemy.text(...)` adapter
|
|
315
|
+
|
|
316
|
+
### `auth.policy: '@fn(...)'`
|
|
317
|
+
|
|
318
|
+
Use `@fn(...)` for target-local auth decisions that cannot be expressed by `mode` / `roles` or the
|
|
319
|
+
current `.rules.loj` slice.
|
|
320
|
+
|
|
321
|
+
Keep it narrow:
|
|
322
|
+
|
|
323
|
+
- it is an additional policy check, not a replacement for the whole resource contract
|
|
324
|
+
- it keeps its own local transaction/runtime behavior
|
|
325
|
+
- policy snippets are also function-body snippets in the current backend-family targets
|
|
326
|
+
- do not include package/import/class/function declarations there either
|
|
327
|
+
|
|
328
|
+
## Commands
|
|
329
|
+
|
|
330
|
+
- `sdsl validate <entry.api.loj>`
|
|
331
|
+
- `sdsl build <entry.api.loj> --out-dir <dir>`
|
|
332
|
+
|
|
333
|
+
Use `loj.project.yaml` instead when you need project-shell database/runtime profiles, auto-provision,
|
|
334
|
+
shutdown/probe/cors/base-path handling, or coordinated `dev/status/doctor`.
|
|
335
|
+
|
|
336
|
+
## Guardrails
|
|
337
|
+
|
|
338
|
+
- Do not invent generic query composition or generic SQL DSL around `readModel`.
|
|
339
|
+
- Do not move database vendors or server runtime/deploy settings into `.api.loj`.
|
|
340
|
+
- Do not leak Spring/FastAPI framework vocabulary into source DSL.
|