532 lines
25 KiB
Markdown
532 lines
25 KiB
Markdown
# Vitruvio Development Guidelines
|
|
|
|
## What is Vitruvio
|
|
|
|
Vitruvio is a Java 21 / Spring / Vaadin 7 multi-tenant BPM platform. Developers extend it by creating **content repositories** — git repos that contain panels, processes, scripts, queries, reports, endpoints, and more. Vitruvio reads these repos and renders their content at runtime. This file is one such repository.
|
|
|
|
Every repository must have a `vitruvio.json` manifest at its root that declares all artifacts. That manifest is the source of truth for what the platform will register.
|
|
|
|
---
|
|
|
|
## Repository Structure
|
|
|
|
Artifacts live under their own top-level directories, matching the paths declared in `vitruvio.json`:
|
|
|
|
```
|
|
vitruvio.json
|
|
panels/
|
|
<panel-key>/
|
|
<panel-key>-desktop.xml
|
|
<panel-key>-mobile.xml # optional
|
|
default-state.json
|
|
thumbnail.png
|
|
processes/
|
|
<process-key>/
|
|
<process-key>.bpmn
|
|
<process-key>-desktop.xml
|
|
<process-key>-mobile.xml # optional
|
|
scripts/
|
|
<script-key>.js
|
|
<script-key>.md # optional documentation
|
|
endpoints/
|
|
<endpoint-key>.js
|
|
queries/
|
|
<query-key>.sql
|
|
reports/
|
|
<report-key>/
|
|
template.jrxml
|
|
params.xml
|
|
libraries/
|
|
<library-key>/
|
|
patches/
|
|
```
|
|
|
|
All `key` values in `vitruvio.json` must be **kebab-case**, unique within their artifact type, and stable — changing a key is a breaking change.
|
|
|
|
---
|
|
|
|
## vitruvio.json Manifest
|
|
|
|
`version` and `metadata.key` are the only required fields. All other sections are optional arrays.
|
|
|
|
### metadata
|
|
```json
|
|
{
|
|
"name": "Human-readable module name",
|
|
"key": "module-key", // kebab-case, unique across tenants
|
|
"standardProduct": false // true only for widespread modules
|
|
}
|
|
```
|
|
|
|
### Artifact sections
|
|
Each section is an array. Omit the section entirely if there are no items — don't leave empty arrays unless needed.
|
|
|
|
Key rules per artifact:
|
|
- **panels** — UI screens built from XML forms. `forms.desktop` is the primary form path; mobile is optional.
|
|
- **processes** — BPMN workflows. Can declare `schedules` (cron or simple interval triggers). Are composed from a BPMN file for Activiti, a xml file for the web form and one or two xml files for the mobile forms.
|
|
- **scripts** — Reusable JS logic. `domain` is either `"SISTEMA"` (system-level) or `"USUARIO"` (user-level). Will generally be USUARIO. For non-trivial logic, see Unit Testing below.
|
|
- **endpoints** — REST endpoints. `authMode` is one of `"PUBLIC"`, `"STATIC_TOKEN"`, `"VITRUVIO_WS_USER_AUTH"`, or `"HTTP_BASIC_AUTH"`. Default to `"PUBLIC"`. `active: true` to enable. For non-trivial logic, see Unit Testing below.
|
|
- **queries** — Named SQL queries. `connection` references a configured datasource. Use `"vitruvio_producao"` for the default datasource.
|
|
- **reports** — Jasper reports. Require a query key, a `.jrxml` template, and optionally a parameter form.
|
|
- **libraries** — Static file bundles (JS/CSS/images). `type: "LOCAL"` for files in this repo.
|
|
- **groups** — User groups this module manages or depends on.
|
|
- **properties** — User-configurable key/value settings.
|
|
- **menu** — Navigation tree. See the Menu section below for structure and type values.
|
|
- **permissions** — Process-level access control per group. Mostly unused, generally defined in the bpmn file for the process.
|
|
- **patches** — Path to a directory containing per-database Liquibase changelogs. Has `oracle/` and `postgresql/` subdirectories, each with its own XML changelog file.
|
|
|
|
---
|
|
|
|
## XML Forms (Panels & Processes)
|
|
|
|
Forms are XML files validated against Vitruvio's XSD schema. Vaadin components are declared in XML and rendered by the platform's Java presenter layer — there is no manual Java UI code in content repos (except if imported in scripts using the Rhino engine).
|
|
|
|
**Form files are named `<key>-desktop.xml` / `<key>-mobile.xml` and the BPMN `<key>.bpmn`** (artifact key + suffix), so each form is searchable by its key rather than dozens of identical `form-desktop.xml` tabs.
|
|
|
|
**Desktop vs mobile forms are different schemas.** Desktop (`<key>-desktop.xml`) uses the `<panel-form>` / `<forms>` schemas, the 78-component desktop set, and Rhino ES5 scripts with auto-injected process variables. Mobile (`<key>-mobile.xml`) uses the `<mobile-forms>` schema (namespace `.../vitruvio/mobile-form`), only the 18 mobile components, **modern React-Native JS on the client** (Promises) with **server-side `<ServerSide><Bridge>` blocks in Rhino ES5** for any lib/DB/service access, and **explicitly declared data** (`<Autoload>` variables, `<QueryDataSource>`, bridges via `vCommunicationService.executeOnServer`). Use the focused skills — `vitruvio-criar-processo-bpmn`, `vitruvio-criar-form-desktop`, `vitruvio-criar-form-mobile` (driven by the `vitruvio-criar-painel` / `vitruvio-criar-processo` orchestrators) — and read `docs/components/mobile/` before building a mobile form.
|
|
|
|
General rules:
|
|
- **Always save form/XML files as UTF-8 *without* a BOM.** A leading byte-order mark (`EF BB BF`) — or any whitespace/content before the `<?xml` declaration — makes the platform's XML parser fail with `Content is not allowed in prolog` when the form is opened, even though the file looks fine in an editor. When writing or editing `.xml`/`.bpmn` files, never prepend a BOM or blank line; the declaration must be the very first bytes. Run `vitruvio validate` (which checks for this) before committing.
|
|
- Always validate your XML against the XSD before committing. Malformed forms fail on open.
|
|
- Keep forms focused. One screen = one form. Split complex layouts into sub-forms or components if the schema allows.
|
|
- Use `<script>` blocks with `<![CDATA[...]]>` for inline JavaScript on components (button actions, lifecycle hooks, field validators). For non-trivial logic, delegate to a named script file rather than writing large CDATA blocks inline or repetitive code and import it using `libService.loadScript("lib_name")`.
|
|
- `displayOrder` on panels controls the order they appear in listings. Use gaps (10, 20, 30…) to allow future insertions without reshuffling.
|
|
|
|
---
|
|
|
|
## JavaScript — ES5 / Rhino Engine
|
|
|
|
All JavaScript in this platform runs on **Mozilla Rhino**, an ES5 interpreter embedded in the JVM. Modern JS features are not available.
|
|
|
|
### What you CANNOT use
|
|
```javascript
|
|
// NO — ES6+ is not supported
|
|
const x = 1;
|
|
let y = 2;
|
|
const fn = () => {};
|
|
`template ${literal}`;
|
|
const { a, b } = obj;
|
|
const [first, ...rest] = arr;
|
|
class Foo {}
|
|
async function bar() {}
|
|
await something();
|
|
import x from 'y';
|
|
export default x;
|
|
for (const item of iterable) {}
|
|
Promise.resolve();
|
|
Array.from(x);
|
|
Object.assign({}, a, b);
|
|
```
|
|
|
|
### What you MUST use instead
|
|
```javascript
|
|
// YES — ES5 style
|
|
var x = 1;
|
|
var y = 2;
|
|
var fn = function() {};
|
|
"template " + variable;
|
|
var a = obj.a; var b = obj.b;
|
|
// loop with index
|
|
for (var i = 0; i < arr.length; i++) {}
|
|
// prototype-based, not class
|
|
function Foo() {}
|
|
Foo.prototype.bar = function() {};
|
|
// callbacks, not async/await
|
|
doSomething(function(result) { ... });
|
|
```
|
|
|
|
### Additional Rhino caveats
|
|
- `JSON.parse` and `JSON.stringify` are available.
|
|
- `typeof`, `instanceof`, standard `Array`/`Object`/`String` methods from ES5 work fine.
|
|
- No browser globals (`window`, `document`, `fetch`, `XMLHttpRequest`).
|
|
- No Node.js globals (`require`, `process`, `Buffer`, `__dirname`).
|
|
- Rhino exposes Java interop — avoid it in business scripts unless you know what you're doing.
|
|
- Always declare variables with `var`. Undeclared variables become globals and cause hard-to-trace bugs.
|
|
- When comparing values that originate from Java (DB query results, form field values, process variables), use `==` / `!=` — Java types do not strict-equal JavaScript primitives. Use `===` / `!==` only when you control both sides and know they are pure JS values.
|
|
- `Array.prototype` iteration methods `forEach`, `map`, `filter`, `reduce`, `some`, `every` are available — they are ES5 and work fine in Rhino.
|
|
|
|
---
|
|
|
|
## Unit Testing
|
|
|
|
Tests run under **Jest on Node**, not Rhino — this is the one place in the repo where modern JS
|
|
(`const`, arrow functions, destructuring) is fine, because `*.test.js` files never execute on the
|
|
platform. The production code they test still must be ES5/Rhino-safe.
|
|
|
|
**Scope: `scripts/*.js` and `endpoints/*.js` only.** Inline `<script>` CDATA in panel/process XML and
|
|
`.sql` queries have no module boundary to hook Jest into and are not unit tested this way.
|
|
|
|
**When to write a test.** Only for non-trivial logic — a function with a branch, a loop, or a call
|
|
into `db`/`http`/a platform service. A script or endpoint that's a straight passthrough doesn't need
|
|
one. **Any bug fix always gets a regression test**, written test-first:
|
|
1. Write a test asserting the correct behavior.
|
|
2. Run it and confirm it **fails** (proves it actually catches the bug).
|
|
3. Fix the root cause.
|
|
4. Run it and confirm it **passes**.
|
|
5. Run the full suite (`npm test`) to check for regressions elsewhere.
|
|
|
|
Only add the dependency-injection seam below to scripts/endpoints that actually get a test — don't
|
|
restructure trivial code preemptively for testability it doesn't need.
|
|
|
|
### Making a script testable
|
|
|
|
Wrap the logic in a constructor accepting an optional `deps` object, falling back to the real
|
|
platform globals. Guard the CommonJS export with `typeof module` — Rhino's script-loading context
|
|
(`libService.loadScript`) never defines `module`, Node always does. See `scripts/exemplo.js` /
|
|
`scripts/exemplo.test.js` for the full example.
|
|
|
|
```javascript
|
|
function MinhaLib(deps) {
|
|
var banco = deps ? deps.banco : new db(db.VITRUVIO_DATASOURCE);
|
|
this.metodo = function() { ... };
|
|
}
|
|
|
|
if (typeof module !== 'undefined') module.exports = MinhaLib;
|
|
```
|
|
|
|
### Making an endpoint testable
|
|
|
|
Endpoints have a fixed production contract: the platform's Rhino endpoint loader expects
|
|
`module.exports` to already be an instance with `onGet`/`onPost`/etc, not a constructor — and Rhino
|
|
*does* define `module` there, so the `typeof module` guard doesn't distinguish it from Node. Instead,
|
|
guard on `process`, which only exists in Node:
|
|
|
|
```javascript
|
|
function WebService(deps) {
|
|
if (deps) {
|
|
this.db = deps.db;
|
|
this.webApi = deps.webApi;
|
|
} else {
|
|
this.db = libService.loadScript('db');
|
|
this.webApi = libService.loadScript('minha-lib');
|
|
}
|
|
this.onPost = function(params, headers, res) { ... };
|
|
}
|
|
|
|
if (typeof process !== "undefined" && process.env.NODE_ENV === "test") {
|
|
module.exports = WebService;
|
|
} else {
|
|
module.exports = new WebService();
|
|
}
|
|
```
|
|
|
|
When there's more than one dependency, swap the **whole `deps` object** in one `if`/`else` block
|
|
rather than per-field fallback (`deps.x || real`). A test that forgets to mock one dependency then
|
|
gets `undefined` and fails loudly, instead of silently hitting a real service.
|
|
|
|
### Mocking
|
|
|
|
Prefer the shared helpers over hand-rolled stubs:
|
|
- `@davinti/vitruvio-core-libs/db/mock` → `MockDb`, `createQueryResult` for anything using `db`.
|
|
- `@davinti/vitruvio-test-utils` → `createMockServletResponse`, `createMockLibService` for endpoint
|
|
responses and `libService.loadScript` lookups.
|
|
- The shared Jest preset (`jest.config.js` → `preset: '@davinti/vitruvio-test-utils'`) already stubs
|
|
`println`, `java`, `libService`, `vLogger` as globals — `libService.loadScript` returns `null` for
|
|
anything not explicitly mocked, by design, so an unmocked lib dependency fails loudly rather than
|
|
silently.
|
|
|
|
For a platform service with no shared mock yet (most of them — only `db` has one so far), stub the
|
|
global inline in the test file:
|
|
|
|
```javascript
|
|
beforeEach(() => {
|
|
global.vEmailService = { enviarEmail: jest.fn() };
|
|
});
|
|
```
|
|
|
|
If the same stub keeps getting copy-pasted across test files, that's a signal to request it be added
|
|
to `@davinti/vitruvio-test-utils` upstream — don't duplicate it locally across many test files.
|
|
|
|
### Running
|
|
|
|
`npm test` must pass before scripts/endpoints work is considered done — same standing as
|
|
`vitruvio validate` for XML forms.
|
|
|
|
---
|
|
|
|
## E2E Testing
|
|
|
|
E2E tests run against a real Vitruvio instance spun up by `vitruvio test:start`. Use them for
|
|
**process workflows** — happy paths that cross multiple artifacts (BPMN → script → DB write) and are
|
|
too integrated to unit test meaningfully. Don't E2E test things that unit tests already cover
|
|
(pure script logic, single endpoint calls with mocked deps).
|
|
|
|
### Setup
|
|
|
|
Nenhuma configuração é necessária — `vitruvio test:start` funciona direto. Um usuário de
|
|
teste é gerado automaticamente a cada execução (veja `resolveE2ECredentials` em
|
|
`@davinti/vitruvio-test-utils`).
|
|
|
|
Se quiser usar um usuário fixo em vez do gerado automaticamente:
|
|
|
|
```bash
|
|
cp tests/.env.example tests/.env
|
|
# preencha TEST_USER e TEST_PASSWORD — nunca use admin
|
|
```
|
|
|
|
`tests/.env` é gitignored.
|
|
|
|
### Running
|
|
|
|
```bash
|
|
vitruvio test:start # spin up Vitruvio + Postgres + gitea-mock (Docker)
|
|
vitruvio test:sync # push current working tree and import into Vitruvio
|
|
npm run test:e2e # run tests in tests/*.e2e.js
|
|
vitruvio test:stop # tear down containers and volumes
|
|
```
|
|
|
|
`test:sync` pushes uncommitted changes — you don't need to commit before testing. Re-run it whenever
|
|
you change a process, form, script, or vitruvio.json.
|
|
|
|
### Writing a test
|
|
|
|
Tests live in `tests/*.e2e.js`. Use `VitruvioClient` from `@davinti/vitruvio-test-utils`:
|
|
|
|
```javascript
|
|
'use strict';
|
|
var { VitruvioClient } = require('@davinti/vitruvio-test-utils');
|
|
var client = new VitruvioClient();
|
|
|
|
beforeAll(async function() {
|
|
await client.login(process.env.TEST_USER, process.env.TEST_PASSWORD);
|
|
});
|
|
|
|
test('meu-processo: completa tarefa de aprovação', async function() {
|
|
var instance = await client.startProcess('meu-processo-key');
|
|
var task = await client.waitForTask('Task_aprovacao', { processInstanceId: instance.processInstanceId });
|
|
var data = await client.getTaskData(task.id);
|
|
await client.completeTask(task.id, Object.assign({}, data, { aprovado: true }));
|
|
});
|
|
```
|
|
|
|
**`global-setup.js` runs before every test suite** — it pings Vitruvio and seeds the test user. Your
|
|
test file just needs `beforeAll` for `client.login`.
|
|
|
|
### Prerequisites for a process to be testable
|
|
|
|
Two things must be true or `startProcess` returns 404:
|
|
|
|
1. **`forms.mobile` declared in `vitruvio.json`** — the REST API only exposes processes with a mobile
|
|
form entry. Point it at the desktop XML if there's no real mobile form:
|
|
```json
|
|
"forms": { "desktop": "processes/meu-processo/meu-processo-desktop.xml", "mobile": "processes/meu-processo/meu-processo-desktop.xml" }
|
|
```
|
|
|
|
2. **`candidateStarterGroups` must exist in nauth with `tag = 'vi_task_group'`** — Vitruvio filters
|
|
starter groups by that tag. Groups imported from `vitruvio.json` get it automatically. If you add a
|
|
new group just for a process, pass it in `global-setup.js` so `createTestUser` seeds it:
|
|
```javascript
|
|
await createTestUser(client, { login: login, password: password, groups: ['meu-grupo'] });
|
|
```
|
|
If `candidateStarterGroups` is absent from the BPMN, any authenticated user can start — fine for
|
|
tests but usually wrong for production.
|
|
|
|
### `VitruvioClient` API
|
|
|
|
| Method | What it does |
|
|
|--------|-------------|
|
|
| `login(user, pass)` | Authenticates and stores the JWT |
|
|
| `startProcess(key, data?)` | Starts a process instance; returns `{ processInstanceId, ... }` |
|
|
| `getTasks()` | Returns all tasks visible to the logged-in user |
|
|
| `waitForTask(taskKey, opts?)` | Polls until a task with that `taskDefinitionKey` appears; `opts`: `{ processInstanceId, timeout, interval }` |
|
|
| `waitForProcessEnd(instanceId, opts?)` | Polls until no tasks remain for the given process instance |
|
|
| `getTaskData(id)` | Returns the task's current form data |
|
|
| `completeTask(id, data?)` | Completes the task with the given form data |
|
|
| `callEndpoint(key, opts?)` | Calls a public integration endpoint |
|
|
|
|
`waitForTask` and `waitForProcessEnd` default to a 30 s timeout with 2 s polling.
|
|
|
|
### DB seed utilities
|
|
|
|
Available from `@davinti/vitruvio-test-utils` for use in `global-setup.js`:
|
|
|
|
**`deleteTestProcessInstances(pg, processKey)`** — deletes all instances of a process key from the
|
|
test DB (Activiti runtime + history + all Vitruvio child rows). Call it at the top of the setup
|
|
function so each run starts clean and `waitForTask` can't match a task from a previous run:
|
|
|
|
```javascript
|
|
await deleteTestProcessInstances(client, 'meu-processo-key');
|
|
await createTestUser(client, { login: login, password: password, groups: ['vi_user'] });
|
|
```
|
|
|
|
**`seedConexao(pg, options)`** — upserts a `conexao` row so scripts using `new db('my-key')` or
|
|
queries with `connection: 'my-key'` can resolve the datasource. Idempotent — safe to call on every
|
|
test run. Required fields: `siglaId`, `host`, `instancia`. Optional: `nome`, `porta` (default 5432),
|
|
`usuario`, `senha`, `plataforma` (default 2 = PostgreSQL), `aliases` (array of alias strings):
|
|
|
|
```javascript
|
|
await seedConexao(client, {
|
|
siglaId: 'minha-conexao',
|
|
host: process.env.TEST_DB_HOST || 'localhost',
|
|
porta: parseInt(process.env.TEST_DB_PORT || '15432'),
|
|
instancia: process.env.TEST_DB_NAME || 'vitruvio',
|
|
usuario: process.env.TEST_DB_USER || 'postgres',
|
|
senha: process.env.TEST_DB_PASSWORD || 'postgres',
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Vitruvio Platform Services
|
|
|
|
Injected objects available in script and endpoint contexts (e.g. `vEmailService`, `vProcessService`, `libService`, `vFileService`, `vLoginService`…).
|
|
|
|
**Before calling any service method, read its doc file:**
|
|
|
|
```
|
|
~/.local/share/vitruvio-platform/docs/services/<ServiceName>.md
|
|
```
|
|
|
|
Every injected service has its own file there — method signatures, parameters, return types, and examples. Do not guess method names or signatures; always check the file first.
|
|
|
|
---
|
|
|
|
## Developer Libraries
|
|
|
|
These are widely-used libraries already available in the platform environment:
|
|
|
|
| Library | Purpose |
|
|
| ------- | ------------------------------------------------------------------------------------- |
|
|
| `http` | HTTP request utilities (GET, POST, etc.) |
|
|
| `db` | Database query helpers — prefer named queries from `queries/` over raw SQL in scripts |
|
|
|
|
> Also not full list, there are more usable libs.
|
|
|
|
### `db` usage notes
|
|
|
|
- `db.query()` always returns a result wrapper object, **never `null`** — even with zero rows, you get a wrapper whose `.each()` simply doesn't invoke the callback. Don't null-check it, just call `.each()` directly:
|
|
|
|
```javascript
|
|
var rows = banco.query("SELECT ...", {});
|
|
rows.each(function(row) { ... });
|
|
```
|
|
|
|
`db.queryRow()` is the one that returns `null` when there are no rows — that one you do need to null-check.
|
|
|
|
- Values from `db.queryRow()` and `db.query()` row properties are Java objects. Use `==` / `!=` when comparing them to JavaScript primitives (follows from the Java interop rule above).
|
|
- The default datasource connection key is `"vitruvio_producao"`. Use it for `connection-key` in `sqlBuilderDataSource`/`freeQuery`, for `connection` in `vitruvio.json` queries, and when constructing `new db('vitruvio_producao')` in scripts. The string `"default"` does not resolve to anything and will cause errors.
|
|
|
|
---
|
|
|
|
## Menu
|
|
|
|
The `menu` section of `vitruvio.json` defines the navigation tree shown to users. It is a flat-ish array — nesting is done via `children` on `MENU` items.
|
|
|
|
```json
|
|
"menu": [
|
|
{
|
|
"key": "my-panel-item",
|
|
"name": "My Panel",
|
|
"order": 1,
|
|
"type": "PAINEL",
|
|
"panelKey": "my-panel-key",
|
|
"children": []
|
|
},
|
|
{
|
|
"key": "my-group",
|
|
"name": "My Group",
|
|
"icon": 61946,
|
|
"order": 2,
|
|
"type": "MENU",
|
|
"children": [
|
|
{
|
|
"key": "my-group/child-panel",
|
|
"name": "Child Panel",
|
|
"icon": 62030,
|
|
"order": 0,
|
|
"type": "PAINEL",
|
|
"panelKey": "child-panel-key",
|
|
"children": []
|
|
}
|
|
]
|
|
}
|
|
]
|
|
```
|
|
|
|
### Field reference
|
|
|
|
| Field | Required | Notes |
|
|
|-------|----------|-------|
|
|
| `key` | yes | Unique identifier. For children, use `Parent/Child` path convention |
|
|
| `name` | yes | Label shown in the UI |
|
|
| `type` | yes | `MENU` (group/submenu), `PAINEL` (panel), `RELATORIO` (report), `PROCESSO` (process) |
|
|
| `order` | yes | Display order within its level |
|
|
| `icon` | no | Numeric codepoint for the item icon |
|
|
| `panelKey` | for PAINEL | Must match the `key` of a registered panel |
|
|
| `children` | yes | Array of child items. Always include, even as `[]` on leaf items |
|
|
|
|
### Rules
|
|
|
|
- `MENU` items are containers only — they do not link to anything themselves, only their `children` do.
|
|
- Keys must be unique across the whole menu tree. Use the `Parent/Child` path convention for nested items to avoid collisions.
|
|
- `order` controls sorting within a level; gaps (0, 10, 20…) allow future insertions.
|
|
- **Never generate menu entries unless the user explicitly asks for it.** Creating a panel, process, or other artifact does not imply adding it to the menu.
|
|
|
|
---
|
|
|
|
## Global Platform Reference
|
|
|
|
A shared directory exists outside this repo with platform-wide resources. Always check it before writing new code.
|
|
|
|
| OS | Path |
|
|
|----|------|
|
|
| Linux | `~/.local/share/vitruvio-platform/` |
|
|
| Windows | `%LOCALAPPDATA%\vitruvio-platform\` |
|
|
|
|
### What's where and when to use it
|
|
|
|
| Folder | Contents | When to look here |
|
|
|--------|----------|-------------------|
|
|
| `libs/` | Core JS library files (`db`, `http`, `messages`, `vaadinComponents`, etc.) | Before implementing something that a platform lib likely already handles |
|
|
| `docs/services/` | One `.md` per injected Java service — method signatures, parameters, return types. Named by injection variable (e.g. `vProcessInstanceService.md`, `vEmailService.md`). | When you need to call a platform service and don't know what methods it exposes |
|
|
| `docs/java/` | Full exported JavaDocs (HTML). Package structure: `br/`, `com/`, `org/`. | When you need to `importClass(Packages....)` a Java class and want to know its API |
|
|
| `docs/components/desktop/` | 78 Vaadin component reference markdowns — attributes, events, usage examples. See `docs/components/INDEX.md` for the full list. | When working with any component and unsure of its attributes or behaviour. Read `docs/components/desktop/<ComponentName>.md` before using a component you're not certain about. |
|
|
| `docs/components/mobile/` | 18 mobile component reference markdowns. | When building mobile forms. |
|
|
| `examples/panels/` | Example panel XML forms | Before writing a panel from scratch |
|
|
| `examples/processes/` | Example BPMN + process XML forms | Before writing a process from scratch |
|
|
| `examples/scripts/` | Example library and task scripts | Before writing a script from scratch |
|
|
| `examples/endpoints/` | Example REST endpoints | Before writing an endpoint from scratch |
|
|
| `examples/reports/` | Example Jasper report configs | Before writing a report from scratch |
|
|
|
|
> Examples show how things generally work in the platform — treat them as functional reference, not necessarily best-practice code.
|
|
|
|
### Services vs. libs — key distinction
|
|
|
|
- **Services** (`docs/services/`) are Java objects injected directly into every script context. Call them by their variable name — no loading needed. Names follow the `vClassName` convention (e.g. `vProcessInstanceService`, `vEmailService`, `vConfigService`). Exceptions: `libService`, `engine`, `execution`.
|
|
- **Libs** (`libs/`) are JS files loaded on demand with `libService.loadScript('key')`. The `db` lib is the primary example — it wraps `ConexaoService` into a friendlier JS API.
|
|
|
|
---
|
|
|
|
## General Conventions
|
|
|
|
- **Named queries versus inline SQL.** Put SQL in `queries/*.sql` and reference by key if they will be reused only. Keeps SQL auditable and reusable across scripts/reports.
|
|
- **Group keys are shared contracts.** If a `group-key` is referenced across permission rules and menu items, treat it as a public API — dont change the key.
|
|
- **Patches are append-only.** `patches/` has `oracle/` and `postgresql/` subdirectories, each with its own Liquibase XML changelog. Never modify existing changesets — only append new ones. Keep both files in sync.
|
|
- **No BOM, ever.** All text artifacts (XML forms, BPMN, scripts, queries, reports) must be plain UTF-8 with no byte-order mark. A BOM breaks XML parsing at runtime and is invisible in most editors — `vitruvio validate` now flags it, but don't introduce it in the first place.
|
|
|
|
---
|
|
|
|
## Git Commits
|
|
|
|
Applies to every commit in this repo. Follow **Conventional Commits**
|
|
(`type(scope): summary`, e.g. `feat`, `fix`, `refactor`, `docs`, `chore`), in Brazilian Portuguese or
|
|
English. The body must give context on **what changed, why, and how** — not just restate the diff —
|
|
and reference the ticket number when one exists.
|
|
|
|
```
|
|
feat(compras): adiciona comprador específico na solicitação de compra
|
|
|
|
Permite abrir a solicitação para um comprador específico e filtra os
|
|
produtos por comprador no painel de precificação.
|
|
|
|
Ref: ticket 23917
|
|
```
|
|
|
|
## README
|
|
|
|
Check `README.md` whenever the repo looks near-complete or complete (most artifacts registered,
|
|
feature work wrapping up). If it's missing or still the `projeto-base` placeholder, warn the dev and
|
|
ask them to describe what the module does — then write/update the README covering: what it manages,
|
|
how it works, the most important files and how they interact, and any caveats worth flagging to a
|
|
future reader. Only write it once the dev has confirmed the description; don't invent one.
|