@adula/kit 0.2.0-alpha.3 → 1.0.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 +12 -2
- package/build/agent/capabilities.md +49 -7
- package/build/agent/skills/idea-review/SKILL.md +26 -1
- package/build/agent/skills/module-review/SKILL.md +22 -0
- package/build/agent/skills/perf-review/SKILL.md +24 -0
- package/build/agent/skills/schema-review/SKILL.md +22 -0
- package/build/agent/skills/security-review/SKILL.md +24 -0
- package/build/agent/skills/ui-review/SKILL.md +22 -0
- package/build/commands/capabilities.d.ts +4 -0
- package/build/commands/capabilities.js +35 -4
- package/build/commands/gaps.js +5 -8
- package/build/commands/main.d.ts +4 -2
- package/build/commands/main.js +2 -0
- package/build/database/migrations/1770000000004_kit_collaboration.d.ts +5 -0
- package/build/database/migrations/1770000000004_kit_collaboration.js +10 -0
- package/build/database/migrations/1770000000005_kit_assignments.d.ts +5 -0
- package/build/database/migrations/1770000000005_kit_assignments.js +10 -0
- package/build/database/migrations/1770000000006_kit_messaging.d.ts +5 -0
- package/build/database/migrations/1770000000006_kit_messaging.js +10 -0
- package/build/database/migrations/1770000000007_kit_webhooks.d.ts +5 -0
- package/build/database/migrations/1770000000007_kit_webhooks.js +10 -0
- package/build/database/migrations/1770000000008_kit_imports.d.ts +5 -0
- package/build/database/migrations/1770000000008_kit_imports.js +10 -0
- package/build/database/migrations/1770000000010_kit_workflows.d.ts +5 -0
- package/build/database/migrations/1770000000010_kit_workflows.js +10 -0
- package/build/index.d.ts +22 -2
- package/build/index.js +13 -2
- package/build/src/admin/contracts.js +19 -10
- package/build/src/admin/controller.d.ts +1 -0
- package/build/src/admin/controller.js +6 -0
- package/build/src/admin/resource_service.d.ts +48 -3
- package/build/src/admin/resource_service.js +194 -18
- package/build/src/attachments/attachment_service.d.ts +18 -1
- package/build/src/attachments/attachment_service.js +62 -0
- package/build/src/auth/ability.d.ts +2 -0
- package/build/src/collaboration/assignments.d.ts +78 -0
- package/build/src/collaboration/assignments.js +219 -0
- package/build/src/collaboration/record_collaboration.d.ts +86 -0
- package/build/src/collaboration/record_collaboration.js +360 -0
- package/build/src/commands/agent_assets.js +5 -0
- package/build/src/commands/capabilities.d.ts +19 -0
- package/build/src/commands/capabilities.js +160 -0
- package/build/src/commands/gap_report.d.ts +8 -0
- package/build/src/commands/gap_report.js +12 -0
- package/build/src/core/message_templates.d.ts +80 -0
- package/build/src/core/message_templates.js +288 -0
- package/build/src/core/saved_views.js +31 -6
- package/build/src/core/user_invitations.js +2 -2
- package/build/src/database/schema.d.ts +18 -0
- package/build/src/database/schema.js +192 -0
- package/build/src/events/outbox.d.ts +1 -0
- package/build/src/events/outbox.js +1 -1
- package/build/src/events/record_mutation.d.ts +9 -0
- package/build/src/events/record_mutation.js +18 -3
- package/build/src/integrations/imports.d.ts +74 -0
- package/build/src/integrations/imports.js +331 -0
- package/build/src/integrations/openapi.d.ts +39 -0
- package/build/src/integrations/openapi.js +256 -0
- package/build/src/integrations/print.d.ts +37 -0
- package/build/src/integrations/print.js +123 -0
- package/build/src/integrations/webhooks.d.ts +98 -0
- package/build/src/integrations/webhooks.js +298 -0
- package/build/src/resource/define_resource.d.ts +1 -0
- package/build/src/resource/define_resource.js +9 -1
- package/build/src/resource/registry.d.ts +2 -0
- package/build/src/resource/registry.js +9 -0
- package/build/src/resource/types.d.ts +13 -1
- package/build/src/workflows/define_workflow.d.ts +95 -0
- package/build/src/workflows/define_workflow.js +83 -0
- package/build/src/workflows/engine.d.ts +119 -0
- package/build/src/workflows/engine.js +687 -0
- package/package.json +7 -13
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @adula/kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Resource framework for AdonisJS 7 and PostgreSQL 17, version 1.0.0 (accepted by the owner, ADR 028). Node 24 or later is required. MIT licensed. The public API in `api/kit-api.json` follows semantic versioning.
|
|
4
4
|
|
|
5
5
|
## Install into a consumer
|
|
6
6
|
|
|
@@ -28,4 +28,14 @@ Doctor measures the deployment's `storage/uploads` directory and warns above 5 d
|
|
|
28
28
|
|
|
29
29
|
## Current limitations
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
Phases 3 and 4 (collaboration, assignments, templates and realtime notifications,
|
|
32
|
+
CSV import, printing, webhooks, API tokens/OpenAPI, amend-by-copy and versioned
|
|
33
|
+
XState workflows) are implemented with PostgreSQL tests; see the
|
|
34
|
+
[business features guide](https://github.com/adulash/adula-kit/blob/main/docs/business-features.md).
|
|
35
|
+
|
|
36
|
+
- Two-factor authentication is not included; it is planned for 2.0 (ADR 027).
|
|
37
|
+
- Impersonation was reviewed by automated adversarial and black-box tests only; its
|
|
38
|
+
human security review is deferred to 2.0 (ADR 027).
|
|
39
|
+
- XLSX import is not available (GAP-006); CSV is.
|
|
40
|
+
|
|
41
|
+
See [implementation status](https://github.com/adulash/adula-kit/blob/main/docs/implementation-status.md), [gaps](https://github.com/adulash/adula-kit/blob/main/KIT_GAPS.md) and [1.0 acceptance](https://github.com/adulash/adula-kit/blob/main/docs/acceptance-1.0.md).
|
|
@@ -1,13 +1,55 @@
|
|
|
1
|
-
#
|
|
1
|
+
# adula-kit capabilities (1.0.0)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Generated by `node ace adula:capabilities`. Read this before proposing a module; anything not listed here is not provided by the kit.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Resource definition
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
| Field type | Storage |
|
|
8
|
+
|---|---|
|
|
9
|
+
| string | varchar |
|
|
10
|
+
| text | text |
|
|
11
|
+
| integer | integer |
|
|
12
|
+
| money | bigint minor units, decimal string in JSON |
|
|
13
|
+
| boolean | boolean |
|
|
14
|
+
| date | date (YYYY-MM-DD) |
|
|
15
|
+
| datetime | timestamptz |
|
|
16
|
+
| json | jsonb |
|
|
17
|
+
| attachment | attachments row id; per-field accept/maxSize |
|
|
18
|
+
| belongsTo | foreign key, preloaded, restrict on delete |
|
|
19
|
+
| hasMany | child resource; inline rows saved with the parent |
|
|
20
|
+
| lookup | lookups group key |
|
|
8
21
|
|
|
9
|
-
|
|
22
|
+
Field options: required, unique (partial, active rows), sortable, searchable (generated tsvector), filterable, permissionLevel, sequence, column.
|
|
10
23
|
|
|
11
|
-
|
|
24
|
+
Resource options: scoped (required), submittable (docStatus, submit/cancel/amend-by-copy), version (optimistic locking, default with submittable), customFields, list / form / show / serialize / hidden, actions, hooks.beforeSave / hooks.afterSave.
|
|
12
25
|
|
|
13
|
-
|
|
26
|
+
Role rule conditions: $eq, $ne, $in, $lt, $gt, $like on scalar fields; unsupported conditions are refused. Organization scope is always added with AND.
|
|
27
|
+
|
|
28
|
+
Workflow steps: condition, update, notify, approval, delay, http, end.
|
|
29
|
+
|
|
30
|
+
## Services
|
|
31
|
+
|
|
32
|
+
- **Resources and authorization:** `defineResource`, `ResourceRegistry`, `ResourceService`, `createResourceController`, `buildAbility`, `accessibleBy`, `ActorStore`, `packedResourceRules`
|
|
33
|
+
- **Records and collaboration:** `RecordCollaboration`, `followerListeners`, `Assignments`, `SavedViews`, `logActivity`
|
|
34
|
+
- **Documents and workflows:** `defineWorkflow`, `WorkflowEngine`, `workflowListeners`
|
|
35
|
+
- **Notifications and messages:** `notify`, `notifyWithTemplate`, `MessageTemplates`, `deliverNotificationMail`, `listenForNotifications`, `NotificationsAdmin`
|
|
36
|
+
- **Integration:** `Webhooks`, `signWebhook`, `openApiDocument`, `ImportBatches`, `renderPrintHtml`, `htmlToPdf`
|
|
37
|
+
- **Security:** `UserInvitations`, `UsersAdmin`, `RolesAdmin`
|
|
38
|
+
- **Data and operations:** `sequence`, `Settings`, `SettingsAdmin`, `publishOutbox`, `consumeEvent`, `recordMutation`, `moveOrgUnit`, `migrateStorage`, `verifyBackup`, `runtimeHealth`
|
|
39
|
+
|
|
40
|
+
## Extension points
|
|
41
|
+
|
|
42
|
+
- Resource hooks (beforeSave, afterSave) inside the save transaction
|
|
43
|
+
- Page override: inertia/pages/<resource>/{index,form,show}.tsx replaces the generated page
|
|
44
|
+
- Domain events <module>.<resource>.{created,updated,deleted,submitted,cancelled,amended} with idempotent listeners
|
|
45
|
+
- Module workflows (Module.workflows) with versioned definitions
|
|
46
|
+
- Message templates edited per deployment
|
|
47
|
+
- Outgoing webhooks and the bearer-token /api/v1 API
|
|
48
|
+
|
|
49
|
+
## Outside the kit
|
|
50
|
+
|
|
51
|
+
- Dynamic fields or a field editor screen
|
|
52
|
+
- Runtime plugins
|
|
53
|
+
- A visual workflow editor
|
|
54
|
+
- Multi-tenant SaaS in one database (one deployment per organization)
|
|
55
|
+
- XLSX import until a maintained parser passes the dependency rule (GAP-006)
|
|
@@ -3,4 +3,29 @@ name: idea-review
|
|
|
3
3
|
description: Translate a new module or workflow into existing kit resources and declared extension points before writing code.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Use for a new module or workflow only; field changes do not need it.
|
|
7
|
+
|
|
8
|
+
1. Run `node ace adula:capabilities` and read the output: kit field types, services,
|
|
9
|
+
workflow steps, extension points, what is outside the kit, and this project's
|
|
10
|
+
registered modules, resources and workflows. Read docs/decisions and KIT_GAPS.md.
|
|
11
|
+
2. Find existing entities with the same meaning; reference them with belongsTo.
|
|
12
|
+
Never duplicate a table owned by another module.
|
|
13
|
+
3. Produce a compact blueprint:
|
|
14
|
+
- module name, `dependsOn`, owned resources with `scoped` stated explicitly;
|
|
15
|
+
- fields with kit types, required/unique/searchable/filterable, permission levels,
|
|
16
|
+
hidden fields, lookups (groups and keys) and sequences;
|
|
17
|
+
- submittable documents and their workflow as steps (condition, update, notify,
|
|
18
|
+
approval, delay, http, end) with approvers by role;
|
|
19
|
+
- events consumed and emitted, listeners (idempotent) and any webhooks;
|
|
20
|
+
- role rules per action, including conditions from the six operators;
|
|
21
|
+
- acceptance tests: 403/404/uniqueness/scope from the generator plus the
|
|
22
|
+
business rules.
|
|
23
|
+
4. Classify each requirement: **now** (kit capability), **extension** (hooks, page
|
|
24
|
+
override, listener, workflow), or **outside the kit** (record it in KIT_GAPS.md
|
|
25
|
+
with Needed by, Tried, Blocked because, Proposed kit change, Workaround).
|
|
26
|
+
5. Never design a dynamic field editor, runtime plugin loader, visual workflow editor
|
|
27
|
+
or a second tenant model. An already-approved plan authorizes its modules; do not
|
|
28
|
+
ask to approve them again.
|
|
29
|
+
|
|
30
|
+
After implementation, run the reviewers: module-review, security-review,
|
|
31
|
+
schema-review, ui-review and perf-review.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: module-review
|
|
3
|
+
description: Review a module's boundaries, dependencies, events and scope before merging.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Check, citing file and line for every finding:
|
|
7
|
+
|
|
8
|
+
- The module lives in `app/modules/<name>` and is registered in `start/modules.ts`
|
|
9
|
+
after every module it depends on; `dependsOn` lists each module whose resources
|
|
10
|
+
it references. `ResourceRegistry.register` must accept the order.
|
|
11
|
+
- It writes only its own tables. Cross-module effects happen in idempotent
|
|
12
|
+
listeners (`consumeEvent` + processed_events), never by importing another
|
|
13
|
+
module's controllers or services. Heavy listeners dispatch jobs.
|
|
14
|
+
- Every resource declares `scoped`. Central (`scoped: false`) resources are
|
|
15
|
+
justified; scoped ones rely on the kit's organization scope, not custom filters.
|
|
16
|
+
- Documents that need approval use `submittable: true` and a module workflow; the
|
|
17
|
+
operational status is a lookup separate from `docStatus`.
|
|
18
|
+
- No kit service is re-implemented under another name (notify, sequence, settings,
|
|
19
|
+
assignments, comments, imports, webhooks, workflows).
|
|
20
|
+
- Educational fixtures are not imported by the application.
|
|
21
|
+
|
|
22
|
+
Verdict: accept, or a numbered list of blocking findings.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: perf-review
|
|
3
|
+
description: Review queries, pagination and background work against the performance budget.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Budget (plan section 13): list with two relations p95 < 300 ms, form save < 200 ms,
|
|
7
|
+
cached Ability build < 5 ms, on 100,000 seeded rows and 50 concurrent users.
|
|
8
|
+
|
|
9
|
+
Check, citing file and line:
|
|
10
|
+
|
|
11
|
+
- Lists go through `ResourceService.list`: keyset pagination, limit ≤ 100, selected
|
|
12
|
+
columns only, belongsTo preloaded in one query per relation; no query in a loop.
|
|
13
|
+
- Custom queries have supporting indexes (foreign keys, `(org_unit_id, deleted_at)`,
|
|
14
|
+
sort columns used by saved views); `EXPLAIN` shows no sequential scan on large
|
|
15
|
+
tables for the common filters.
|
|
16
|
+
- Save paths keep one transaction: record, lines, activity, field changes and outbox.
|
|
17
|
+
Anything slow (mail, HTTP, PDF, imports) runs in the worker, never inline.
|
|
18
|
+
- Listeners are idempotent and cheap or dispatch jobs; workflows do not poll.
|
|
19
|
+
- Caches (Ability, lookups, settings) are invalidated by the kit's revision rules,
|
|
20
|
+
not by time alone.
|
|
21
|
+
- Run `pnpm test:medical` with `K6_BINARY` on staging-like hardware before release
|
|
22
|
+
and record the measured p95 values; never relax the thresholds.
|
|
23
|
+
|
|
24
|
+
Verdict: accept, or findings with the measurement or query plan.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: schema-review
|
|
3
|
+
description: Review migrations and resource definitions for integrity and evolution.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Check, citing file and line:
|
|
7
|
+
|
|
8
|
+
- Migrations are additive (expand/contract): no drop or rename of a column still
|
|
9
|
+
read by the previous release; kit migrations are never edited after release.
|
|
10
|
+
- Standard columns come from the generator (`id`, `org_unit_id` when scoped,
|
|
11
|
+
`created_by`, `updated_by`, timestamps, `deleted_at`, `version`, `doc_status`,
|
|
12
|
+
`amended_from_id`); they are not hand-edited.
|
|
13
|
+
- Every foreign key is indexed and `restrict` on delete (cascade only inside the
|
|
14
|
+
same module); `(org_unit_id, deleted_at)` exists for scoped tables.
|
|
15
|
+
- Unique rules are partial (`WHERE deleted_at IS NULL`); searchable fields produce
|
|
16
|
+
the generated tsvector with a GIN index.
|
|
17
|
+
- Money is bigint minor units; dates use `date`, instants `timestamptz`; changeable
|
|
18
|
+
lists are lookups, numbering uses sequences.
|
|
19
|
+
- The definition's `form`, `list`, `show` and `serialize` match the columns, and
|
|
20
|
+
generated contract tests cover 403/404/uniqueness/scope.
|
|
21
|
+
|
|
22
|
+
Verdict: accept, or blocking findings with the corrected migration.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-review
|
|
3
|
+
description: Review authorization, serialization and sensitive flows of a change.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Check, citing file and line:
|
|
7
|
+
|
|
8
|
+
- Every route passes authentication and the resource goes through ResourceService
|
|
9
|
+
(or `resources.access` for record features). Custom queries use `accessibleBy`;
|
|
10
|
+
nothing reads records by id without the scope and Ability checks.
|
|
11
|
+
- Responses use the kit serializers; hidden and `permissionLevel` fields never leave
|
|
12
|
+
the server, including through search, sort, filters, exports, prints, history,
|
|
13
|
+
notifications, webhooks and OpenAPI.
|
|
14
|
+
- Role rules use only the six operators; nothing widens scope with an allow rule.
|
|
15
|
+
- No hand-written crypto, sessions, password or token handling. Secrets are sealed
|
|
16
|
+
with the application encryption; tokens and recovery codes are stored hashed.
|
|
17
|
+
- Outgoing HTTP (webhooks, workflow steps) targets HTTPS and cannot reach private
|
|
18
|
+
addresses in production; payloads carry identifiers, not record fields.
|
|
19
|
+
- Uploads and imports are size-limited and parsed by the kit; errors never echo
|
|
20
|
+
secrets. Rate limits cover authentication, second factor and token creation.
|
|
21
|
+
- 2FA, impersonation and authentication changes are flagged for human review
|
|
22
|
+
(AGENTS rule 11); map the change to ASVS 4.0.3 V2/V3/V4 items.
|
|
23
|
+
|
|
24
|
+
Verdict: accept, or blocking findings with the exploit scenario for each.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ui-review
|
|
3
|
+
description: Review pages and components for RTL, the component system and data access.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Check, citing file and line:
|
|
7
|
+
|
|
8
|
+
- Components come from `inertia/components/ui` (installed by `node ace adula:ui add`);
|
|
9
|
+
no `shadcn add` in modules, no hand-styled native controls or homemade dialogs.
|
|
10
|
+
- Forms and record details use the shadcn Dialog (ResourceSurface) unless the user
|
|
11
|
+
asked otherwise; destructive actions confirm; edits guard against closing.
|
|
12
|
+
- RTL: `dir="rtl"`, logical properties (`ms-`, `ps-`, `text-start`), arrows follow
|
|
13
|
+
the reading direction, Latin digits in amounts per the UI preference, Arabic
|
|
14
|
+
labels and English identifiers. Dates honor the calendar preference.
|
|
15
|
+
- Generated pages are overridden only through `pages/<resource>/<mode>.tsx`.
|
|
16
|
+
- Heavy sections are deferred props or fetched after render; lists paginate with
|
|
17
|
+
the scroll prop; no page renders data the server did not serialize for the user.
|
|
18
|
+
- Accessible names exist for icon buttons, dialogs and regions; errors use
|
|
19
|
+
`role="alert"`; focus stays inside dialogs.
|
|
20
|
+
- Company identity from docs/design-identity.md is applied, not invented.
|
|
21
|
+
|
|
22
|
+
Verdict: accept, or findings with screenshots or selectors.
|
|
@@ -1,9 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { BaseCommand, flags } from '@adonisjs/core/ace';
|
|
8
|
+
import { writeFile } from 'node:fs/promises';
|
|
9
|
+
import { capabilityCatalog } from '../src/commands/capabilities.js';
|
|
3
10
|
export default class Capabilities extends BaseCommand {
|
|
4
11
|
static commandName = 'adula:capabilities';
|
|
5
|
-
static description = '
|
|
12
|
+
static description = 'Generate the capability catalog (kit features plus this project registry)';
|
|
13
|
+
static options = { startApp: true };
|
|
6
14
|
async run() {
|
|
7
|
-
|
|
15
|
+
let registry;
|
|
16
|
+
try {
|
|
17
|
+
;
|
|
18
|
+
({ registry } = await this.app.import('#start/modules'));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
this.logger.warning('start/modules could not be loaded; printing kit capabilities only');
|
|
22
|
+
}
|
|
23
|
+
// Imported lazily: main.ts lists this command itself.
|
|
24
|
+
const { getMetaData } = await import('./main.js');
|
|
25
|
+
const metadata = await getMetaData();
|
|
26
|
+
const catalog = capabilityCatalog({
|
|
27
|
+
registry,
|
|
28
|
+
commands: metadata.map((command) => `${command.commandName} — ${command.description}`),
|
|
29
|
+
});
|
|
30
|
+
if (this.write) {
|
|
31
|
+
await writeFile(this.app.makePath('capabilities.md'), catalog);
|
|
32
|
+
this.logger.success('capabilities.md');
|
|
33
|
+
}
|
|
34
|
+
else
|
|
35
|
+
this.logger.log(catalog);
|
|
8
36
|
}
|
|
9
37
|
}
|
|
38
|
+
__decorate([
|
|
39
|
+
flags.boolean({ description: 'Write capabilities.md at the project root' })
|
|
40
|
+
], Capabilities.prototype, "write", void 0);
|
package/build/commands/gaps.js
CHANGED
|
@@ -6,6 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { BaseCommand, args, flags } from '@adonisjs/core/ace';
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import { gapReport } from '../src/commands/gap_report.js';
|
|
9
10
|
/** Collects KIT_GAPS.md for reporting; nothing leaves the machine without explicit confirmation. */
|
|
10
11
|
export default class Gaps extends BaseCommand {
|
|
11
12
|
static commandName = 'adula:gaps';
|
|
@@ -22,14 +23,10 @@ export default class Gaps extends BaseCommand {
|
|
|
22
23
|
catch {
|
|
23
24
|
throw new Error('KIT_GAPS.md does not exist; adula:install creates it');
|
|
24
25
|
}
|
|
25
|
-
const masked = content
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.
|
|
29
|
-
const gaps = masked.match(/^## GAP-\d+.*$/gm) ?? [];
|
|
30
|
-
this.logger.info(`${gaps.length} gap(s) recorded in KIT_GAPS.md`);
|
|
31
|
-
for (const title of gaps)
|
|
32
|
-
this.logger.log(` ${title.replace(/^## /, '')}`);
|
|
26
|
+
const { masked, titles } = gapReport(content);
|
|
27
|
+
this.logger.info(`${titles.length} gap(s) recorded in KIT_GAPS.md`);
|
|
28
|
+
for (const title of titles)
|
|
29
|
+
this.logger.log(` ${title}`);
|
|
33
30
|
if (!this.yes) {
|
|
34
31
|
const confirmed = await this.prompt.confirm('Show the full masked report? Nothing is sent anywhere by this command.');
|
|
35
32
|
if (!confirmed)
|
package/build/commands/main.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import Resource from './resource.js';
|
|
1
2
|
import Doctor from './doctor.js';
|
|
2
|
-
import
|
|
3
|
+
import ModuleAdd from './module_add.js';
|
|
4
|
+
import Ui from './ui.js';
|
|
3
5
|
export declare function getMetaData(): Promise<import("@adonisjs/core/types/ace").CommandMetaData[]>;
|
|
4
6
|
export declare function getCommand(meta: {
|
|
5
7
|
commandName: string;
|
|
6
|
-
}): Promise<typeof
|
|
8
|
+
}): Promise<typeof Resource | typeof Doctor | typeof ModuleAdd | typeof Ui | null>;
|
package/build/commands/main.js
CHANGED
|
@@ -6,6 +6,7 @@ import ModuleAdd from './module_add.js';
|
|
|
6
6
|
import ModuleRemove from './module_remove.js';
|
|
7
7
|
import Ui from './ui.js';
|
|
8
8
|
import StorageMigrate from './storage_migrate.js';
|
|
9
|
+
import Gaps from './gaps.js';
|
|
9
10
|
const commands = [
|
|
10
11
|
Resource,
|
|
11
12
|
Doctor,
|
|
@@ -15,6 +16,7 @@ const commands = [
|
|
|
15
16
|
ModuleRemove,
|
|
16
17
|
Ui,
|
|
17
18
|
StorageMigrate,
|
|
19
|
+
Gaps,
|
|
18
20
|
];
|
|
19
21
|
export async function getMetaData() {
|
|
20
22
|
return commands.map((command) => {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createCollaborationSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitCollaboration extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createCollaborationSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createAssignmentsSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitAssignments extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createAssignmentsSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createMessagingSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitMessaging extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createMessagingSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createWebhooksSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitWebhooks extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createWebhooksSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createImportsSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitImports extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createImportsSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createWorkflowSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitWorkflows extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createWorkflowSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
package/build/index.d.ts
CHANGED
|
@@ -14,8 +14,26 @@ export { accessibleBy, authorizationSql, conditionSql } from './src/auth/sql.js'
|
|
|
14
14
|
export { ResourceService } from './src/admin/resource_service.js';
|
|
15
15
|
export { serialize, writableInput, selectedFields } from './src/admin/contracts.js';
|
|
16
16
|
export { KitError } from './src/admin/errors.js';
|
|
17
|
-
export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, } from './src/database/schema.js';
|
|
18
|
-
export {
|
|
17
|
+
export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, createCollaborationSchema, createAssignmentsSchema, createMessagingSchema, createWebhooksSchema, createImportsSchema, createWorkflowSchema, } from './src/database/schema.js';
|
|
18
|
+
export { defineWorkflow, nextStep } from './src/workflows/define_workflow.js';
|
|
19
|
+
export type { WorkflowDefinition, WorkflowInput, WorkflowStep, WorkflowEvent, StepContext, Recipients, } from './src/workflows/define_workflow.js';
|
|
20
|
+
export { WorkflowEngine, workflowListeners } from './src/workflows/engine.js';
|
|
21
|
+
export type { WorkflowRun, WorkflowRunStatus, WorkflowOptions } from './src/workflows/engine.js';
|
|
22
|
+
export { ImportBatches, importCell, IMPORT_ROW_LIMIT } from './src/integrations/imports.js';
|
|
23
|
+
export type { ImportBatch, ImportStatus, ImportTarget, ActorSource, } from './src/integrations/imports.js';
|
|
24
|
+
export { openApiDocument } from './src/integrations/openapi.js';
|
|
25
|
+
export { renderPrintHtml, htmlToPdf } from './src/integrations/print.js';
|
|
26
|
+
export type { PrintIdentity, PrintInput } from './src/integrations/print.js';
|
|
27
|
+
export { Webhooks, signWebhook, WEBHOOK_MAX_ATTEMPTS } from './src/integrations/webhooks.js';
|
|
28
|
+
export type { SecretBox, Webhook, WebhookDelivery, WebhookOptions, HttpPoster, } from './src/integrations/webhooks.js';
|
|
29
|
+
export { MessageTemplates, DEFAULT_TEMPLATES, renderTemplate, notifyWithTemplate, deliverNotificationMail, listenForNotifications, } from './src/core/message_templates.js';
|
|
30
|
+
export type { TemplateDefinition, MessageTemplate, RenderedMessage, MailSender, NotificationSignal, } from './src/core/message_templates.js';
|
|
31
|
+
export { Assignments } from './src/collaboration/assignments.js';
|
|
32
|
+
export type { Assignment, AssignmentPage, AssignmentStatus, } from './src/collaboration/assignments.js';
|
|
33
|
+
export { RecordCollaboration, followerListeners } from './src/collaboration/record_collaboration.js';
|
|
34
|
+
export type { ActorLoader, CommentEntry, FieldChangeEntry, RecordCollaborationState, MentionCandidate, } from './src/collaboration/record_collaboration.js';
|
|
35
|
+
export type { FieldChange } from './src/events/record_mutation.js';
|
|
36
|
+
export { registerUpload, findAttachment, loadAttachments, claimAttachment, releaseAttachment, summarizeAttachment, attachmentUrl, isAttachmentId, isRelativeDiskPath, attachmentPolicy, pendingUploadCount, staleUploads, forgetUpload, DEFAULT_ATTACHMENT_EXTENSIONS, PENDING_UPLOAD_LIMIT, UNBOUND_UPLOAD_TTL_MS, } from './src/attachments/attachment_service.js';
|
|
19
37
|
export type { AttachmentRecord, AttachmentSummary, UploadInput, ClaimInput, } from './src/attachments/attachment_service.js';
|
|
20
38
|
export { migrateStorage } from './src/attachments/storage_migrate.js';
|
|
21
39
|
export type { StorageDisk, StorageMigrationOptions, StorageMigrationResult, } from './src/attachments/storage_migrate.js';
|
|
@@ -49,3 +67,5 @@ export { runtimeHealth, isBackupStale, backupStale, heartbeat, HEARTBEAT_MAX_AGE
|
|
|
49
67
|
export type { RuntimeHealth, HeartbeatStatus, QueueSnapshot, QueueCounts, FailedJob, } from './src/core/health.js';
|
|
50
68
|
export { MailDeliveryTest, MAIL_TEST_KEY, type MailTestState } from './src/core/mail_test.js';
|
|
51
69
|
export { InitialSetup, type SetupCheck } from './src/core/setup.js';
|
|
70
|
+
export { KIT_VERSION } from './src/version.js';
|
|
71
|
+
export { capabilityCatalog, SERVICES as CAPABILITY_SERVICES, FIELD_TYPES, WORKFLOW_STEPS, } from './src/commands/capabilities.js';
|
package/build/index.js
CHANGED
|
@@ -10,8 +10,17 @@ export { accessibleBy, authorizationSql, conditionSql } from './src/auth/sql.js'
|
|
|
10
10
|
export { ResourceService } from './src/admin/resource_service.js';
|
|
11
11
|
export { serialize, writableInput, selectedFields } from './src/admin/contracts.js';
|
|
12
12
|
export { KitError } from './src/admin/errors.js';
|
|
13
|
-
export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, } from './src/database/schema.js';
|
|
14
|
-
export {
|
|
13
|
+
export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, createCollaborationSchema, createAssignmentsSchema, createMessagingSchema, createWebhooksSchema, createImportsSchema, createWorkflowSchema, } from './src/database/schema.js';
|
|
14
|
+
export { defineWorkflow, nextStep } from './src/workflows/define_workflow.js';
|
|
15
|
+
export { WorkflowEngine, workflowListeners } from './src/workflows/engine.js';
|
|
16
|
+
export { ImportBatches, importCell, IMPORT_ROW_LIMIT } from './src/integrations/imports.js';
|
|
17
|
+
export { openApiDocument } from './src/integrations/openapi.js';
|
|
18
|
+
export { renderPrintHtml, htmlToPdf } from './src/integrations/print.js';
|
|
19
|
+
export { Webhooks, signWebhook, WEBHOOK_MAX_ATTEMPTS } from './src/integrations/webhooks.js';
|
|
20
|
+
export { MessageTemplates, DEFAULT_TEMPLATES, renderTemplate, notifyWithTemplate, deliverNotificationMail, listenForNotifications, } from './src/core/message_templates.js';
|
|
21
|
+
export { Assignments } from './src/collaboration/assignments.js';
|
|
22
|
+
export { RecordCollaboration, followerListeners } from './src/collaboration/record_collaboration.js';
|
|
23
|
+
export { registerUpload, findAttachment, loadAttachments, claimAttachment, releaseAttachment, summarizeAttachment, attachmentUrl, isAttachmentId, isRelativeDiskPath, attachmentPolicy, pendingUploadCount, staleUploads, forgetUpload, DEFAULT_ATTACHMENT_EXTENSIONS, PENDING_UPLOAD_LIMIT, UNBOUND_UPLOAD_TTL_MS, } from './src/attachments/attachment_service.js';
|
|
15
24
|
export { migrateStorage } from './src/attachments/storage_migrate.js';
|
|
16
25
|
export { diagnoseAttachments } from './src/attachments/doctor.js';
|
|
17
26
|
export { Settings, sequence, notify } from './src/services/settings.js';
|
|
@@ -32,3 +41,5 @@ export { SettingsAdmin, isProtectedSetting, parseSettingValue, SETTING_SCOPES, P
|
|
|
32
41
|
export { runtimeHealth, isBackupStale, backupStale, heartbeat, HEARTBEAT_MAX_AGE_MS, BACKUP_MAX_AGE_MS, } from './src/core/health.js';
|
|
33
42
|
export { MailDeliveryTest, MAIL_TEST_KEY } from './src/core/mail_test.js';
|
|
34
43
|
export { InitialSetup } from './src/core/setup.js';
|
|
44
|
+
export { KIT_VERSION } from './src/version.js';
|
|
45
|
+
export { capabilityCatalog, SERVICES as CAPABILITY_SERVICES, FIELD_TYPES, WORKFLOW_STEPS, } from './src/commands/capabilities.js';
|
|
@@ -19,18 +19,27 @@ export function selectedFields(resource, ability, options = {}) {
|
|
|
19
19
|
]),
|
|
20
20
|
].filter((key) => key !== 'orgPath' && resource.fields[key]?.type !== 'hasMany');
|
|
21
21
|
}
|
|
22
|
+
const rowKeys = new WeakMap();
|
|
23
|
+
/** Record keys and their columns for a resource, computed once per definition. */
|
|
24
|
+
function keysOf(resource) {
|
|
25
|
+
let keys = rowKeys.get(resource);
|
|
26
|
+
if (!keys) {
|
|
27
|
+
keys = [
|
|
28
|
+
...standard,
|
|
29
|
+
'orgUnitId',
|
|
30
|
+
'version',
|
|
31
|
+
'docStatus',
|
|
32
|
+
'amendedFromId',
|
|
33
|
+
'orgPath',
|
|
34
|
+
...Object.keys(resource.fields),
|
|
35
|
+
].map((key) => [key, resource.fields[key]?.column ?? columnName(key)]);
|
|
36
|
+
rowKeys.set(resource, keys);
|
|
37
|
+
}
|
|
38
|
+
return keys;
|
|
39
|
+
}
|
|
22
40
|
export function fromRow(row, resource) {
|
|
23
41
|
const result = {};
|
|
24
|
-
for (const key of
|
|
25
|
-
...standard,
|
|
26
|
-
'orgUnitId',
|
|
27
|
-
'version',
|
|
28
|
-
'docStatus',
|
|
29
|
-
'amendedFromId',
|
|
30
|
-
'orgPath',
|
|
31
|
-
...Object.keys(resource.fields),
|
|
32
|
-
]) {
|
|
33
|
-
const column = resource.fields[key]?.column ?? columnName(key);
|
|
42
|
+
for (const [key, column] of keysOf(resource)) {
|
|
34
43
|
if (column in row) {
|
|
35
44
|
const value = row[column];
|
|
36
45
|
result[key] =
|
|
@@ -22,6 +22,7 @@ export interface ResourceController {
|
|
|
22
22
|
destroy(ctx: HttpContext): Promise<unknown>;
|
|
23
23
|
submit(ctx: HttpContext): Promise<unknown>;
|
|
24
24
|
cancel(ctx: HttpContext): Promise<unknown>;
|
|
25
|
+
amend(ctx: HttpContext): Promise<unknown>;
|
|
25
26
|
create(ctx: HttpContext): Promise<unknown>;
|
|
26
27
|
edit(ctx: HttpContext): Promise<unknown>;
|
|
27
28
|
options(ctx: HttpContext): Promise<unknown>;
|
|
@@ -27,6 +27,7 @@ export function createResourceController(resolveRuntime, renderList, renderForm,
|
|
|
27
27
|
sort: ctx.request.input('sort'),
|
|
28
28
|
direction: ctx.request.input('direction'),
|
|
29
29
|
filters: ctx.request.input('filters'),
|
|
30
|
+
tag: ctx.request.input('tag'),
|
|
30
31
|
estimate: ctx.request.input('estimate') !== 'false' && ctx.request.input('estimate') !== false,
|
|
31
32
|
});
|
|
32
33
|
return renderList && ctx.request.accepts(['html', 'json']) === 'html'
|
|
@@ -70,6 +71,11 @@ export function createResourceController(resolveRuntime, renderList, renderForm,
|
|
|
70
71
|
async cancel(ctx) {
|
|
71
72
|
return this.#transition(ctx, 'cancel');
|
|
72
73
|
}
|
|
74
|
+
async amend(ctx) {
|
|
75
|
+
return this.#execute(ctx, async ({ resources, actor }, resource) => ctx.response.created({
|
|
76
|
+
data: await resources.amend(resource.name, this.#id(ctx), actor),
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
73
79
|
#id(ctx) {
|
|
74
80
|
return this.#positiveId(ctx.params.id);
|
|
75
81
|
}
|