@happyvertical/smrt-human-resources 0.57.37 → 0.57.39

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.
@@ -1,4 +1,4 @@
1
- import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
1
+ import { SmrtCollection, SmrtObject, type SmrtSaveOptions } from '@happyvertical/smrt-core';
2
2
  import { type EmploymentChangeKind, type EmploymentStatus, type IsoDate, type WorkerType } from '../types.js';
3
3
  /**
4
4
  * One person's employment with a tenant: the stable record applications and
@@ -24,7 +24,7 @@ export declare class Employment extends SmrtObject {
24
24
  /** Position or trade label; latest recorded value. */
25
25
  position: string | null;
26
26
  status: EmploymentStatus;
27
- save(): Promise<this>;
27
+ save(options?: SmrtSaveOptions): Promise<this>;
28
28
  delete(): Promise<void>;
29
29
  }
30
30
  /**
@@ -38,7 +38,7 @@ export declare class EmploymentTerm extends SmrtObject {
38
38
  startedOn: IsoDate;
39
39
  endedOn: IsoDate | null;
40
40
  endReason: string;
41
- save(): Promise<this>;
41
+ save(options?: SmrtSaveOptions): Promise<this>;
42
42
  delete(): Promise<void>;
43
43
  }
44
44
  /** Append-only dated change to an employment, attributed to an actor. */
@@ -51,7 +51,7 @@ export declare class EmploymentChange extends SmrtObject {
51
51
  toValue: string | null;
52
52
  note: string;
53
53
  actorProfileId: string;
54
- save(): Promise<this>;
54
+ save(options?: SmrtSaveOptions): Promise<this>;
55
55
  delete(): Promise<void>;
56
56
  }
57
57
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/employment/models.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,cAAc,EACd,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAErB,KAAK,OAAO,EACZ,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAerB;;;;;;;;;GASG;AACH,qBAiBa,UAAW,SAAQ,UAAU;IAC5B,QAAQ,SAAM;IAC1B,2BAA2B;IAK3B,SAAS,SAAM;IACf,4EAA4E;IAE5E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC7B,4EAA4E;IAK5E,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACxC,oCAAoC;IAIpC,cAAc,SAAM;IAMpB,UAAU,EAAE,UAAU,CAAc;IACpC,sDAAsD;IAEtD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B,MAAM,EAAE,gBAAgB,CAAY;IAErB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BrB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvC;AAED;;;;GAIG;AACH,qBAca,cAAe,SAAQ,UAAU;IAChC,QAAQ,SAAM;IAG1B,YAAY,SAAM;IAElB,SAAS,EAAE,OAAO,CAAM;IAOxB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAQ;IAE/B,SAAS,SAAM;IAEA,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBrB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvC;AAED,yEAAyE;AACzE,qBAca,gBAAiB,SAAQ,UAAU;IAClC,QAAQ,SAAM;IAC0B,YAAY,SAAM;IAC7C,IAAI,EAAE,oBAAoB,CAAW;IACrC,WAAW,EAAE,OAAO,CAAM;IACV,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAChC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAQ;IACvE,IAAI,SAAM;IAIV,cAAc,SAAM;IAEL,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAUrB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvC;AAED;;;;GAIG;AACH,qBACa,oBAAqB,SAAQ,cAAc,CAAC,UAAU,CAAC;IAClE,MAAM,CAAC,QAAQ,CAAC,UAAU,oBAAc;CACzC;AACD,qDAAqD;AACrD,qBACa,wBAAyB,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC1E,MAAM,CAAC,QAAQ,CAAC,UAAU,wBAAkB;CAC7C;AACD,mEAAmE;AACnE,qBACa,0BAA2B,SAAQ,cAAc,CAAC,gBAAgB,CAAC;IAC9E,MAAM,CAAC,QAAQ,CAAC,UAAU,0BAAoB;CAC/C"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/employment/models.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,cAAc,EACd,UAAU,EACV,KAAK,eAAe,EAErB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAErB,KAAK,OAAO,EACZ,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAerB;;;;;;;;;GASG;AACH,qBAiBa,UAAW,SAAQ,UAAU;IAC5B,QAAQ,SAAM;IAC1B,2BAA2B;IAK3B,SAAS,SAAM;IACf,4EAA4E;IAE5E,MAAM,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC7B,4EAA4E;IAK5E,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACxC,oCAAoC;IAIpC,cAAc,SAAM;IAMpB,UAAU,EAAE,UAAU,CAAc;IACpC,sDAAsD;IAEtD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/B,MAAM,EAAE,gBAAgB,CAAY;IAErB,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B9C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvC;AAED;;;;GAIG;AACH,qBAca,cAAe,SAAQ,UAAU;IAChC,QAAQ,SAAM;IAG1B,YAAY,SAAM;IAElB,SAAS,EAAE,OAAO,CAAM;IAOxB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAQ;IAE/B,SAAS,SAAM;IAEA,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB9C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvC;AAED,yEAAyE;AACzE,qBAca,gBAAiB,SAAQ,UAAU;IAClC,QAAQ,SAAM;IAC0B,YAAY,SAAM;IAC7C,IAAI,EAAE,oBAAoB,CAAW;IACrC,WAAW,EAAE,OAAO,CAAM;IACV,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAChC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAQ;IACvE,IAAI,SAAM;IAIV,cAAc,SAAM;IAEL,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAU9C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAMvC;AAED;;;;GAIG;AACH,qBACa,oBAAqB,SAAQ,cAAc,CAAC,UAAU,CAAC;IAClE,MAAM,CAAC,QAAQ,CAAC,UAAU,oBAAc;CACzC;AACD,qDAAqD;AACrD,qBACa,wBAAyB,SAAQ,cAAc,CAAC,cAAc,CAAC;IAC1E,MAAM,CAAC,QAAQ,CAAC,UAAU,wBAAkB;CAC7C;AACD,mEAAmE;AACnE,qBACa,0BAA2B,SAAQ,cAAc,CAAC,gBAAgB,CAAC;IAC9E,MAAM,CAAC,QAAQ,CAAC,UAAU,0BAAoB;CAC/C"}
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { ObjectRegistry, SmrtCollection, SmrtObject, SmrtRecipe, crossPackageRef
4
4
  import { TenantScoped, getTenantId, tenantId, withTenant } from "@happyvertical/smrt-tenancy";
5
5
  import { createLogger } from "@happyvertical/logger";
6
6
  //#region src/__smrt-register__.ts
7
- ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-human-resources","packageVersion":"0.57.37","objects":{"@happyvertical/smrt-human-resources:Employment":{"name":"employment","className":"Employment","qualifiedName":"@happyvertical/smrt-human-resources:Employment","collection":"employments","description":"One person's employment with a tenant: the stable record applications and payroll key on. There is one per tenant and profile; a rehire adds an EmploymentTerm to the same row.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"profileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","description":"The person who works for you.","_meta":{"description":"The person who works for you.","onDelete":"RESTRICT"}},"userId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-users:User","_meta":{"nullable":true}},"employerProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","_meta":{"nullable":true,"onDelete":"RESTRICT"}},"employeeNumber":{"type":"text","required":false,"description":"Your own reference for this person, such as a staff number.","_meta":{"description":"Your own reference for this person, such as a staff number."}},"workerType":{"type":"text","required":false,"description":"Whether they are an employee, contractor or another kind of worker.","_meta":{"description":"Whether they are an employee, contractor or another kind of worker."}},"position":{"type":"text","required":false,"description":"Their role or trade.","_meta":{"nullable":true,"description":"Their role or trade."}},"status":{"type":"text","required":false,"description":"Whether they currently work for you.","_meta":{"description":"Whether they currently work for you."},"enum":["active","on-leave","ended"]}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"employments","sensitive":true,"conflictColumns":["tenant_id","employee_number"],"indexes":[{"name":"employments_tenant_profile_uq","columns":["tenantId","profileId"],"unique":true},{"name":"employments_tenant_user_idx","columns":["tenantId","userId"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"}},"extends":"SmrtObject","exportName":"Employment","collectionExportName":"EmploymentCollection","validationRules":[],"schema":{"tableName":"employments","ddl":"CREATE TABLE IF NOT EXISTS \\"employments\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"profile_id\\" UUID,\\n \\"user_id\\" UUID,\\n \\"employer_profile_id\\" UUID,\\n \\"employee_number\\" TEXT,\\n \\"worker_type\\" TEXT,\\n \\"position\\" TEXT,\\n \\"status\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employer_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employee_number":{"type":"TEXT","notNull":false,"unique":false},"worker_type":{"type":"TEXT","notNull":false,"unique":false},"position":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"employments_tenant_id_employee_number_idx","columns":["tenant_id","employee_number"],"unique":true,"nullsNotDistinct":true},{"name":"employments_slug_context_idx","columns":["slug","context"]},{"name":"employments_tenant_profile_uq","columns":["tenant_id","profile_id"],"unique":true},{"name":"employments_tenant_user_idx","columns":["tenant_id","user_id"]},{"name":"employments_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employments_profile_id_idx","columns":["profile_id"]},{"name":"employments_user_id_idx","columns":["user_id"]},{"name":"employments_employer_profile_id_idx","columns":["employer_profile_id"]}],"version":"ff7ef7a8"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentTerm":{"name":"employmentterm","className":"EmploymentTerm","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentTerm","collection":"employmentterms","description":"One continuous period of employment. endedOn is the last day employed (inclusive); null means the term is open. \\"Employed on a date\\" is answered from terms, never from Employment.status.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"employmentId":{"type":"foreignKey","required":false,"related":"Employment","description":"The person this period of work belongs to.","_meta":{"description":"The person this period of work belongs to.","onDelete":"RESTRICT"}},"startedOn":{"type":"text","required":false,"description":"The first day of this period of work.","_meta":{"description":"The first day of this period of work."}},"endedOn":{"type":"text","required":false,"description":"The last day of this period of work. Empty while it continues.","_meta":{"nullable":true,"description":"The last day of this period of work. Empty while it continues."}},"endReason":{"type":"text","required":false,"description":"Why the period of work ended.","_meta":{"description":"Why the period of work ended."}}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"employment_terms","sensitive":true,"indexes":[{"name":"employment_terms_employment_idx","columns":["tenantId","employmentId","startedOn"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"EmploymentTerm","collectionExportName":"EmploymentTermCollection","validationRules":[],"schema":{"tableName":"employment_terms","ddl":"CREATE TABLE IF NOT EXISTS \\"employment_terms\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"employment_id\\" UUID,\\n \\"started_on\\" TEXT,\\n \\"ended_on\\" TEXT,\\n \\"end_reason\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"started_on":{"type":"TEXT","notNull":false,"unique":false},"ended_on":{"type":"TEXT","notNull":false,"unique":false},"end_reason":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"employment_terms_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"employment_terms_employment_idx","columns":["tenant_id","employment_id","started_on"]},{"name":"employment_terms_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employment_terms_employment_id_idx","columns":["employment_id"]}],"version":"165d209b"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentChange":{"name":"employmentchange","className":"EmploymentChange","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentChange","collection":"employmentchanges","description":"Append-only dated change to an employment, attributed to an actor.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"employmentId":{"type":"foreignKey","required":false,"related":"Employment","_meta":{"onDelete":"RESTRICT"}},"kind":{"type":"text","required":false,"_meta":{},"enum":["hired","ended","rehired","position-changed","worker-type-changed","leave-started","leave-ended","login-linked","login-unlinked"]},"effectiveOn":{"type":"text","required":false,"_meta":{}},"fromValue":{"type":"text","required":false,"_meta":{"nullable":true}},"toValue":{"type":"text","required":false,"_meta":{"nullable":true}},"note":{"type":"text","required":false},"actorProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","_meta":{"onDelete":"RESTRICT"}}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"employment_changes","sensitive":true,"indexes":[{"name":"employment_changes_employment_idx","columns":["tenantId","employmentId","effectiveOn"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"EmploymentChange","collectionExportName":"EmploymentChangeCollection","validationRules":[],"schema":{"tableName":"employment_changes","ddl":"CREATE TABLE IF NOT EXISTS \\"employment_changes\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"employment_id\\" UUID,\\n \\"kind\\" TEXT,\\n \\"effective_on\\" TEXT,\\n \\"from_value\\" TEXT,\\n \\"to_value\\" TEXT,\\n \\"note\\" TEXT,\\n \\"actor_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"kind":{"type":"TEXT","notNull":false,"unique":false},"effective_on":{"type":"TEXT","notNull":false,"unique":false},"from_value":{"type":"TEXT","notNull":false,"unique":false},"to_value":{"type":"TEXT","notNull":false,"unique":false},"note":{"type":"TEXT","notNull":false,"unique":false},"actor_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"employment_changes_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"employment_changes_employment_idx","columns":["tenant_id","employment_id","effective_on"]},{"name":"employment_changes_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employment_changes_employment_id_idx","columns":["employment_id"]},{"name":"employment_changes_actor_profile_id_idx","columns":["actor_profile_id"]}],"version":"5d93422f"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentCollection":{"name":"employmentcollection","className":"EmploymentCollection","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentCollection","collection":"employments","description":"Scoped persistence collection; mutations must use EmploymentService.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"employments"},"extends":"SmrtCollection","extendsTypeArg":"Employment","exportName":"EmploymentCollection","collectionExportName":"EmploymentCollectionCollection","schema":{"tableName":"employments","ddl":"CREATE TABLE IF NOT EXISTS \\"employments\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"profile_id\\" UUID,\\n \\"user_id\\" UUID,\\n \\"employer_profile_id\\" UUID,\\n \\"employee_number\\" TEXT,\\n \\"worker_type\\" TEXT,\\n \\"position\\" TEXT,\\n \\"status\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employer_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employee_number":{"type":"TEXT","notNull":false,"unique":false},"worker_type":{"type":"TEXT","notNull":false,"unique":false},"position":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"employments_tenant_id_employee_number_idx","columns":["tenant_id","employee_number"],"unique":true,"nullsNotDistinct":true},{"name":"employments_slug_context_idx","columns":["slug","context"]},{"name":"employments_tenant_profile_uq","columns":["tenant_id","profile_id"],"unique":true},{"name":"employments_tenant_user_idx","columns":["tenant_id","user_id"]},{"name":"employments_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employments_profile_id_idx","columns":["profile_id"]},{"name":"employments_user_id_idx","columns":["user_id"]},{"name":"employments_employer_profile_id_idx","columns":["employer_profile_id"]}],"version":"ff7ef7a8"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentTermCollection":{"name":"employmenttermcollection","className":"EmploymentTermCollection","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentTermCollection","collection":"employmentterms","description":"Scoped term collection; closed like its model.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"employment_terms"},"extends":"SmrtCollection","extendsTypeArg":"EmploymentTerm","exportName":"EmploymentTermCollection","collectionExportName":"EmploymentTermCollectionCollection","schema":{"tableName":"employment_terms","ddl":"CREATE TABLE IF NOT EXISTS \\"employment_terms\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"employment_id\\" UUID,\\n \\"started_on\\" TEXT,\\n \\"ended_on\\" TEXT,\\n \\"end_reason\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"started_on":{"type":"TEXT","notNull":false,"unique":false},"ended_on":{"type":"TEXT","notNull":false,"unique":false},"end_reason":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"employment_terms_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"employment_terms_employment_idx","columns":["tenant_id","employment_id","started_on"]},{"name":"employment_terms_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employment_terms_employment_id_idx","columns":["employment_id"]}],"version":"165d209b"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentChangeCollection":{"name":"employmentchangecollection","className":"EmploymentChangeCollection","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentChangeCollection","collection":"employmentchanges","description":"Scoped append-only change collection; closed like its model.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"employment_changes"},"extends":"SmrtCollection","extendsTypeArg":"EmploymentChange","exportName":"EmploymentChangeCollection","collectionExportName":"EmploymentChangeCollectionCollection","schema":{"tableName":"employment_changes","ddl":"CREATE TABLE IF NOT EXISTS \\"employment_changes\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"employment_id\\" UUID,\\n \\"kind\\" TEXT,\\n \\"effective_on\\" TEXT,\\n \\"from_value\\" TEXT,\\n \\"to_value\\" TEXT,\\n \\"note\\" TEXT,\\n \\"actor_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"kind":{"type":"TEXT","notNull":false,"unique":false},"effective_on":{"type":"TEXT","notNull":false,"unique":false},"from_value":{"type":"TEXT","notNull":false,"unique":false},"to_value":{"type":"TEXT","notNull":false,"unique":false},"note":{"type":"TEXT","notNull":false,"unique":false},"actor_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"employment_changes_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"employment_changes_employment_idx","columns":["tenant_id","employment_id","effective_on"]},{"name":"employment_changes_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employment_changes_employment_id_idx","columns":["employment_id"]},{"name":"employment_changes_actor_profile_id_idx","columns":["actor_profile_id"]}],"version":"5d93422f"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:Qualification":{"name":"qualification","className":"Qualification","qualifiedName":"@happyvertical/smrt-human-resources:Qualification","collection":"qualifications","description":"A qualification definition: a managed list per tenant. Other packages gate work by referencing its id (@happyvertical/smrt-human-resources:Qualification).","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"key":{"type":"text","required":false},"name":{"type":"text","required":false,"description":"What the qualification is called, such as First aid.","_meta":{"description":"What the qualification is called, such as First aid."}},"kind":{"type":"text","required":false,"description":"The sort of qualification, such as a certificate or a licence.","_meta":{"description":"The sort of qualification, such as a certificate or a licence."},"enum":["ticket","certification","authorization","training","restriction"]},"issuingBody":{"type":"text","required":false,"description":"Who gives it out.","_meta":{"description":"Who gives it out."}},"expires":{"type":"boolean","required":true,"default":false,"description":"Whether it has to be renewed.","_meta":{"description":"Whether it has to be renewed."}},"validityMonths":{"type":"integer","required":false,"description":"How many months it lasts once given.","_meta":{"nullable":true,"description":"How many months it lasts once given."}},"scope":{"type":"text","required":false,"_meta":{},"enum":["person","employment"]},"isActive":{"type":"boolean","required":true,"default":true}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"qualifications","sensitive":true,"conflictColumns":["tenant_id","key"],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"}},"extends":"SmrtObject","exportName":"Qualification","collectionExportName":"QualificationCollection","displayLabelField":"name","validationRules":[{"field":"expires","rule":"required","fieldType":"boolean"},{"field":"isActive","rule":"required","fieldType":"boolean"}],"schema":{"tableName":"qualifications","ddl":"CREATE TABLE IF NOT EXISTS \\"qualifications\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"key\\" TEXT,\\n \\"name\\" TEXT,\\n \\"kind\\" TEXT,\\n \\"issuing_body\\" TEXT,\\n \\"expires\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\"validity_months\\" INTEGER,\\n \\"scope\\" TEXT,\\n \\"is_active\\" BOOLEAN NOT NULL DEFAULT TRUE\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"key":{"type":"TEXT","notNull":false,"unique":false},"name":{"type":"TEXT","notNull":false,"unique":false},"kind":{"type":"TEXT","notNull":false,"unique":false},"issuing_body":{"type":"TEXT","notNull":false,"unique":false},"expires":{"type":"BOOLEAN","notNull":true,"unique":false,"default":false},"validity_months":{"type":"INTEGER","notNull":false,"unique":false},"scope":{"type":"TEXT","notNull":false,"unique":false},"is_active":{"type":"BOOLEAN","notNull":true,"unique":false,"default":true}},"indexes":[{"name":"qualifications_tenant_id_key_idx","columns":["tenant_id","key"],"unique":true,"nullsNotDistinct":true},{"name":"qualifications_slug_context_idx","columns":["slug","context"]},{"name":"qualifications_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"c9fa3721"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:HeldQualification":{"name":"heldqualification","className":"HeldQualification","qualifiedName":"@happyvertical/smrt-human-resources:HeldQualification","collection":"heldqualifications","description":"A person holds a qualification. employmentId is set when the definition's scope is employment; such a row is revoked when that employment ends.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"qualificationId":{"type":"foreignKey","required":false,"related":"Qualification","description":"The qualification this person holds.","_meta":{"description":"The qualification this person holds.","onDelete":"RESTRICT"}},"profileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","description":"The person who holds it.","_meta":{"description":"The person who holds it.","onDelete":"RESTRICT"}},"employmentId":{"type":"foreignKey","required":false,"related":"Employment","_meta":{"nullable":true,"onDelete":"RESTRICT"}},"issuedOn":{"type":"text","required":false,"description":"The day it was given.","_meta":{"description":"The day it was given."}},"expiresOn":{"type":"text","required":false,"description":"The day it runs out. Empty if it does not.","_meta":{"nullable":true,"description":"The day it runs out. Empty if it does not."}},"certificateNumber":{"type":"text","required":false,"description":"The number printed on the certificate.","_meta":{"description":"The number printed on the certificate."}},"status":{"type":"text","required":false,"description":"Whether it is valid, expired, suspended or revoked.","_meta":{"description":"Whether it is valid, expired, suspended or revoked."},"enum":["valid","expired","suspended","revoked"]},"verifiedByProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","_meta":{"nullable":true,"onDelete":"RESTRICT"}},"verifiedAt":{"type":"datetime","required":false},"documentAssetId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-assets:Asset","_meta":{"nullable":true}},"renewalOfId":{"type":"foreignKey","required":false,"related":"HeldQualification","_meta":{"nullable":true,"onDelete":"RESTRICT"}}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"held_qualifications","sensitive":true,"indexes":[{"name":"held_qualifications_profile_idx","columns":["tenantId","profileId","qualificationId"]},{"name":"held_qualifications_expiry_idx","columns":["tenantId","status","expiresOn"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"HeldQualification","collectionExportName":"HeldQualificationCollection","validationRules":[],"schema":{"tableName":"held_qualifications","ddl":"CREATE TABLE IF NOT EXISTS \\"held_qualifications\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"qualification_id\\" UUID,\\n \\"profile_id\\" UUID,\\n \\"employment_id\\" UUID,\\n \\"issued_on\\" TEXT,\\n \\"expires_on\\" TEXT,\\n \\"certificate_number\\" TEXT,\\n \\"status\\" TEXT,\\n \\"verified_by_profile_id\\" UUID,\\n \\"verified_at\\" TIMESTAMP,\\n \\"document_asset_id\\" UUID,\\n \\"renewal_of_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"qualification_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"issued_on":{"type":"TEXT","notNull":false,"unique":false},"expires_on":{"type":"TEXT","notNull":false,"unique":false},"certificate_number":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false},"verified_by_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"verified_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"document_asset_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"renewal_of_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"held_qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}}},"indexes":[{"name":"held_qualifications_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"held_qualifications_profile_idx","columns":["tenant_id","profile_id","qualification_id"]},{"name":"held_qualifications_expiry_idx","columns":["tenant_id","status","expires_on"]},{"name":"held_qualifications_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"held_qualifications_qualification_id_idx","columns":["qualification_id"]},{"name":"held_qualifications_profile_id_idx","columns":["profile_id"]},{"name":"held_qualifications_employment_id_idx","columns":["employment_id"]},{"name":"held_qualifications_verified_by_profile_id_idx","columns":["verified_by_profile_id"]},{"name":"held_qualifications_document_asset_id_idx","columns":["document_asset_id"]},{"name":"held_qualifications_renewal_of_id_idx","columns":["renewal_of_id"]}],"version":"fafbe37f"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:HeldQualificationChange":{"name":"heldqualificationchange","className":"HeldQualificationChange","qualifiedName":"@happyvertical/smrt-human-resources:HeldQualificationChange","collection":"heldqualificationchanges","description":"Append-only dated change to a held qualification, attributed to an actor.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"heldQualificationId":{"type":"foreignKey","required":false,"related":"HeldQualification","_meta":{"onDelete":"RESTRICT"}},"kind":{"type":"text","required":false,"_meta":{},"enum":["granted","renewed","suspended","reinstated","revoked","expired"]},"effectiveOn":{"type":"text","required":false,"_meta":{}},"reason":{"type":"text","required":false},"actorProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","_meta":{"onDelete":"RESTRICT"}}},"methods":{"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"held_qualification_changes","sensitive":true,"indexes":[{"name":"held_qualification_changes_held_idx","columns":["tenantId","heldQualificationId","effectiveOn"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"HeldQualificationChange","collectionExportName":"HeldQualificationChangeCollection","validationRules":[],"schema":{"tableName":"held_qualification_changes","ddl":"CREATE TABLE IF NOT EXISTS \\"held_qualification_changes\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"held_qualification_id\\" UUID,\\n \\"kind\\" TEXT,\\n \\"effective_on\\" TEXT,\\n \\"reason\\" TEXT,\\n \\"actor_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"held_qualification_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"held_qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"kind":{"type":"TEXT","notNull":false,"unique":false},"effective_on":{"type":"TEXT","notNull":false,"unique":false},"reason":{"type":"TEXT","notNull":false,"unique":false},"actor_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"held_qualification_changes_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"held_qualification_changes_held_idx","columns":["tenant_id","held_qualification_id","effective_on"]},{"name":"held_qualification_changes_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"held_qualification_changes_held_qualification_id_idx","columns":["held_qualification_id"]},{"name":"held_qualification_changes_actor_profile_id_idx","columns":["actor_profile_id"]}],"version":"ed9ed5e1"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:QualificationCollection":{"name":"qualificationcollection","className":"QualificationCollection","qualifiedName":"@happyvertical/smrt-human-resources:QualificationCollection","collection":"qualifications","description":"Scoped definition collection; mutations must use QualificationService.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"qualifications"},"extends":"SmrtCollection","extendsTypeArg":"Qualification","exportName":"QualificationCollection","collectionExportName":"QualificationCollectionCollection","schema":{"tableName":"qualifications","ddl":"CREATE TABLE IF NOT EXISTS \\"qualifications\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"key\\" TEXT,\\n \\"name\\" TEXT,\\n \\"kind\\" TEXT,\\n \\"issuing_body\\" TEXT,\\n \\"expires\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\"validity_months\\" INTEGER,\\n \\"scope\\" TEXT,\\n \\"is_active\\" BOOLEAN NOT NULL DEFAULT TRUE\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"key":{"type":"TEXT","notNull":false,"unique":false},"name":{"type":"TEXT","notNull":false,"unique":false},"kind":{"type":"TEXT","notNull":false,"unique":false},"issuing_body":{"type":"TEXT","notNull":false,"unique":false},"expires":{"type":"BOOLEAN","notNull":true,"unique":false,"default":false},"validity_months":{"type":"INTEGER","notNull":false,"unique":false},"scope":{"type":"TEXT","notNull":false,"unique":false},"is_active":{"type":"BOOLEAN","notNull":true,"unique":false,"default":true}},"indexes":[{"name":"qualifications_tenant_id_key_idx","columns":["tenant_id","key"],"unique":true,"nullsNotDistinct":true},{"name":"qualifications_slug_context_idx","columns":["slug","context"]},{"name":"qualifications_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"c9fa3721"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:HeldQualificationCollection":{"name":"heldqualificationcollection","className":"HeldQualificationCollection","qualifiedName":"@happyvertical/smrt-human-resources:HeldQualificationCollection","collection":"heldqualifications","description":"Scoped held-qualification collection; closed like its model.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"held_qualifications"},"extends":"SmrtCollection","extendsTypeArg":"HeldQualification","exportName":"HeldQualificationCollection","collectionExportName":"HeldQualificationCollectionCollection","schema":{"tableName":"held_qualifications","ddl":"CREATE TABLE IF NOT EXISTS \\"held_qualifications\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"qualification_id\\" UUID,\\n \\"profile_id\\" UUID,\\n \\"employment_id\\" UUID,\\n \\"issued_on\\" TEXT,\\n \\"expires_on\\" TEXT,\\n \\"certificate_number\\" TEXT,\\n \\"status\\" TEXT,\\n \\"verified_by_profile_id\\" UUID,\\n \\"verified_at\\" TIMESTAMP,\\n \\"document_asset_id\\" UUID,\\n \\"renewal_of_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"qualification_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"issued_on":{"type":"TEXT","notNull":false,"unique":false},"expires_on":{"type":"TEXT","notNull":false,"unique":false},"certificate_number":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false},"verified_by_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"verified_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"document_asset_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"renewal_of_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"held_qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}}},"indexes":[{"name":"held_qualifications_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"held_qualifications_profile_idx","columns":["tenant_id","profile_id","qualification_id"]},{"name":"held_qualifications_expiry_idx","columns":["tenant_id","status","expires_on"]},{"name":"held_qualifications_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"held_qualifications_qualification_id_idx","columns":["qualification_id"]},{"name":"held_qualifications_profile_id_idx","columns":["profile_id"]},{"name":"held_qualifications_employment_id_idx","columns":["employment_id"]},{"name":"held_qualifications_verified_by_profile_id_idx","columns":["verified_by_profile_id"]},{"name":"held_qualifications_document_asset_id_idx","columns":["document_asset_id"]},{"name":"held_qualifications_renewal_of_id_idx","columns":["renewal_of_id"]}],"version":"fafbe37f"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:HeldQualificationChangeCollection":{"name":"heldqualificationchangecollection","className":"HeldQualificationChangeCollection","qualifiedName":"@happyvertical/smrt-human-resources:HeldQualificationChangeCollection","collection":"heldqualificationchanges","description":"Scoped append-only change collection; closed like its model.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"held_qualification_changes"},"extends":"SmrtCollection","extendsTypeArg":"HeldQualificationChange","exportName":"HeldQualificationChangeCollection","collectionExportName":"HeldQualificationChangeCollectionCollection","schema":{"tableName":"held_qualification_changes","ddl":"CREATE TABLE IF NOT EXISTS \\"held_qualification_changes\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"held_qualification_id\\" UUID,\\n \\"kind\\" TEXT,\\n \\"effective_on\\" TEXT,\\n \\"reason\\" TEXT,\\n \\"actor_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"held_qualification_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"held_qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"kind":{"type":"TEXT","notNull":false,"unique":false},"effective_on":{"type":"TEXT","notNull":false,"unique":false},"reason":{"type":"TEXT","notNull":false,"unique":false},"actor_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"held_qualification_changes_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"held_qualification_changes_held_idx","columns":["tenant_id","held_qualification_id","effective_on"]},{"name":"held_qualification_changes_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"held_qualification_changes_held_qualification_id_idx","columns":["held_qualification_id"]},{"name":"held_qualification_changes_actor_profile_id_idx","columns":["actor_profile_id"]}],"version":"ed9ed5e1"},"importPath":"@happyvertical/smrt-human-resources"}},"moduleType":"smrt","recipes":[{"id":"human-resources.people","className":"HumanResourcesPeopleRecipe","label":"Employees","summary":"Keep a record of who works for you and in what role. Only people can see it; agents cannot read it.","synonyms":["hr","human resources","staff","people","team","workers"],"models":["@happyvertical/smrt-human-resources:Employment","@happyvertical/smrt-human-resources:EmploymentTerm"],"nav":[{"label":"Employees","model":"@happyvertical/smrt-human-resources:Employment","icon":"users","description":"Everyone who works for you, with their role and status.","noun":"employee"}],"requires":[],"section":{"id":"staff","label":"Staff","icon":"users","description":"The people who work for you."},"options":{"@happyvertical/smrt-human-resources:Employment":{"fields":{"profileId":{"label":"Person","order":1},"employeeNumber":{"order":2},"position":{"order":3},"workerType":{"order":4},"status":{"order":5},"tenantId":{"visibility":"hidden"},"userId":{"visibility":"advanced"},"employerProfileId":{"visibility":"advanced"}}},"@happyvertical/smrt-human-resources:EmploymentTerm":{"fields":{"employmentId":{"label":"Person","order":1},"startedOn":{"label":"First day","order":2},"endedOn":{"label":"Last day","order":3},"endReason":{"order":4},"tenantId":{"visibility":"hidden"}}}},"help":{"markdown":"## Overview\\n\\nEmployees is where you keep a record of who works for you. Each person has an\\nemployment record with their role, their worker type and whether they are\\ncurrently active, plus the dates they started and, if they left, finished.\\n\\nOnly people using the app can see these records. They are kept closed to\\nassistants and other automated tools on purpose, so an agent cannot read them.\\n\\n## Tasks\\n\\n### Add an employee\\n\\n1. Open the list of employees and choose **New**.\\n2. Pick the **{field:Employment.profileId}**.\\n3. Give them an **{field:Employment.employeeNumber}**, your own reference for them.\\n4. Fill in their **{field:Employment.position}** and **{field:Employment.workerType}**.\\n5. Save. They now show in your list of employees.\\n\\n### Record that someone has left\\n\\n1. Open the person from the list.\\n2. Set the **{field:Employment.status}** to show they no longer work for you.\\n3. Record their **{field:EmploymentTerm.endedOn}** and the **{field:EmploymentTerm.endReason}**.\\n4. Save. Their history stays on file.\\n","fieldRefs":["Employment.employeeNumber","Employment.position","Employment.profileId","Employment.status","Employment.workerType","EmploymentTerm.endReason","EmploymentTerm.endedOn"]},"exposure":"ui-only","demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}},{"id":"human-resources.qualifications","className":"HumanResourcesQualificationsRecipe","label":"Qualifications","summary":"Track the certificates and training your people hold, and when they run out. Only people can see it; agents cannot read it.","synonyms":["certifications","certificates","licences","training","first aid"],"models":["@happyvertical/smrt-human-resources:Qualification","@happyvertical/smrt-human-resources:HeldQualification"],"nav":[{"label":"Qualifications","model":"@happyvertical/smrt-human-resources:Qualification","icon":"book","description":"The certificates, licences and training your people can hold.","noun":"qualification"},{"label":"Held qualifications","model":"@happyvertical/smrt-human-resources:HeldQualification","icon":"fileText","description":"Who holds which qualification, and when it runs out.","noun":"held qualification"}],"requires":["human-resources.people"],"section":{"id":"staff","label":"Staff","icon":"users","description":"The people who work for you."},"options":{"@happyvertical/smrt-human-resources:Qualification":{"fields":{"name":{"order":1},"kind":{"order":2},"issuingBody":{"order":3},"expires":{"order":4},"validityMonths":{"order":5},"key":{"visibility":"advanced"},"scope":{"visibility":"advanced"},"isActive":{"visibility":"advanced"},"tenantId":{"visibility":"hidden"}}},"@happyvertical/smrt-human-resources:HeldQualification":{"fields":{"qualificationId":{"label":"Qualification","order":1},"profileId":{"label":"Person","order":2},"issuedOn":{"order":3},"expiresOn":{"order":4},"certificateNumber":{"order":5},"status":{"order":6},"tenantId":{"visibility":"hidden"},"employmentId":{"visibility":"advanced"},"verifiedByProfileId":{"visibility":"advanced"},"verifiedAt":{"visibility":"advanced"},"documentAssetId":{"visibility":"advanced"},"renewalOfId":{"visibility":"hidden"}}}},"help":{"markdown":"## Overview\\n\\nQualifications is where you list the certificates, licences and training your\\nwork needs, such as first aid, and record who holds each one and when it runs\\nout. It builds on Employees, so switch that on first.\\n\\nOnly people using the app can see these records. They are kept closed to\\nassistants and other automated tools on purpose, so an agent cannot read them.\\n\\n## Tasks\\n\\n### Set up a qualification\\n\\n1. Open the list of qualifications and choose **New**.\\n2. Type the **{field:Qualification.name}**, for example \\"First aid\\".\\n3. Say who gives it out in **{field:Qualification.issuingBody}**.\\n4. Tick **{field:Qualification.expires}** if it has to be renewed, and set **{field:Qualification.validityMonths}** to how long it lasts.\\n5. Save.\\n\\n### Record who holds a qualification\\n\\n1. Open the held qualifications and choose **New**.\\n2. Pick the **{field:HeldQualification.qualificationId}** and the **{field:HeldQualification.profileId}** who holds it.\\n3. Enter the date it was **{field:HeldQualification.issuedOn}** and when it **{field:HeldQualification.expiresOn}**.\\n4. Add the **{field:HeldQualification.certificateNumber}** from the certificate.\\n5. Set the **{field:HeldQualification.status}** to show whether it is still valid.\\n6. Save. You can now see who needs to renew before the date.\\n","fieldRefs":["HeldQualification.certificateNumber","HeldQualification.expiresOn","HeldQualification.issuedOn","HeldQualification.profileId","HeldQualification.qualificationId","HeldQualification.status","Qualification.expires","Qualification.issuingBody","Qualification.name","Qualification.validityMonths"]},"exposure":"ui-only","demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}}],"smrtDependencies":["@happyvertical/smrt-core","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624"],"via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
7
+ ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-human-resources","packageVersion":"0.57.39","objects":{"@happyvertical/smrt-human-resources:Employment":{"name":"employment","className":"Employment","qualifiedName":"@happyvertical/smrt-human-resources:Employment","collection":"employments","description":"One person's employment with a tenant: the stable record applications and payroll key on. There is one per tenant and profile; a rehire adds an EmploymentTerm to the same row.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"profileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","description":"The person who works for you.","_meta":{"description":"The person who works for you.","onDelete":"RESTRICT"}},"userId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-users:User","_meta":{"nullable":true}},"employerProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","_meta":{"nullable":true,"onDelete":"RESTRICT"}},"employeeNumber":{"type":"text","required":false,"description":"Your own reference for this person, such as a staff number.","_meta":{"description":"Your own reference for this person, such as a staff number."}},"workerType":{"type":"text","required":false,"description":"Whether they are an employee, contractor or another kind of worker.","_meta":{"description":"Whether they are an employee, contractor or another kind of worker."}},"position":{"type":"text","required":false,"description":"Their role or trade.","_meta":{"nullable":true,"description":"Their role or trade."}},"status":{"type":"text","required":false,"description":"Whether they currently work for you.","_meta":{"description":"Whether they currently work for you."},"enum":["active","on-leave","ended"]}},"methods":{"save":{"name":"save","async":true,"parameters":[{"name":"options","type":"SmrtSaveOptions","optional":true}],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"employments","sensitive":true,"conflictColumns":["tenant_id","employee_number"],"indexes":[{"name":"employments_tenant_profile_uq","columns":["tenantId","profileId"],"unique":true},{"name":"employments_tenant_user_idx","columns":["tenantId","userId"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"}},"extends":"SmrtObject","exportName":"Employment","collectionExportName":"EmploymentCollection","validationRules":[],"schema":{"tableName":"employments","ddl":"CREATE TABLE IF NOT EXISTS \\"employments\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"profile_id\\" UUID,\\n \\"user_id\\" UUID,\\n \\"employer_profile_id\\" UUID,\\n \\"employee_number\\" TEXT,\\n \\"worker_type\\" TEXT,\\n \\"position\\" TEXT,\\n \\"status\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employer_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employee_number":{"type":"TEXT","notNull":false,"unique":false},"worker_type":{"type":"TEXT","notNull":false,"unique":false},"position":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"employments_tenant_id_employee_number_idx","columns":["tenant_id","employee_number"],"unique":true,"nullsNotDistinct":true},{"name":"employments_slug_context_idx","columns":["slug","context"]},{"name":"employments_tenant_profile_uq","columns":["tenant_id","profile_id"],"unique":true},{"name":"employments_tenant_user_idx","columns":["tenant_id","user_id"]},{"name":"employments_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employments_profile_id_idx","columns":["profile_id"]},{"name":"employments_user_id_idx","columns":["user_id"]},{"name":"employments_employer_profile_id_idx","columns":["employer_profile_id"]}],"version":"ff7ef7a8"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentTerm":{"name":"employmentterm","className":"EmploymentTerm","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentTerm","collection":"employmentterms","description":"One continuous period of employment. endedOn is the last day employed (inclusive); null means the term is open. \\"Employed on a date\\" is answered from terms, never from Employment.status.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"employmentId":{"type":"foreignKey","required":false,"related":"Employment","description":"The person this period of work belongs to.","_meta":{"description":"The person this period of work belongs to.","onDelete":"RESTRICT"}},"startedOn":{"type":"text","required":false,"description":"The first day of this period of work.","_meta":{"description":"The first day of this period of work."}},"endedOn":{"type":"text","required":false,"description":"The last day of this period of work. Empty while it continues.","_meta":{"nullable":true,"description":"The last day of this period of work. Empty while it continues."}},"endReason":{"type":"text","required":false,"description":"Why the period of work ended.","_meta":{"description":"Why the period of work ended."}}},"methods":{"save":{"name":"save","async":true,"parameters":[{"name":"options","type":"SmrtSaveOptions","optional":true}],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"employment_terms","sensitive":true,"indexes":[{"name":"employment_terms_employment_idx","columns":["tenantId","employmentId","startedOn"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"EmploymentTerm","collectionExportName":"EmploymentTermCollection","validationRules":[],"schema":{"tableName":"employment_terms","ddl":"CREATE TABLE IF NOT EXISTS \\"employment_terms\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"employment_id\\" UUID,\\n \\"started_on\\" TEXT,\\n \\"ended_on\\" TEXT,\\n \\"end_reason\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"started_on":{"type":"TEXT","notNull":false,"unique":false},"ended_on":{"type":"TEXT","notNull":false,"unique":false},"end_reason":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"employment_terms_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"employment_terms_employment_idx","columns":["tenant_id","employment_id","started_on"]},{"name":"employment_terms_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employment_terms_employment_id_idx","columns":["employment_id"]}],"version":"165d209b"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentChange":{"name":"employmentchange","className":"EmploymentChange","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentChange","collection":"employmentchanges","description":"Append-only dated change to an employment, attributed to an actor.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"employmentId":{"type":"foreignKey","required":false,"related":"Employment","_meta":{"onDelete":"RESTRICT"}},"kind":{"type":"text","required":false,"_meta":{},"enum":["hired","ended","rehired","position-changed","worker-type-changed","leave-started","leave-ended","login-linked","login-unlinked"]},"effectiveOn":{"type":"text","required":false,"_meta":{}},"fromValue":{"type":"text","required":false,"_meta":{"nullable":true}},"toValue":{"type":"text","required":false,"_meta":{"nullable":true}},"note":{"type":"text","required":false},"actorProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","_meta":{"onDelete":"RESTRICT"}}},"methods":{"save":{"name":"save","async":true,"parameters":[{"name":"options","type":"SmrtSaveOptions","optional":true}],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"employment_changes","sensitive":true,"indexes":[{"name":"employment_changes_employment_idx","columns":["tenantId","employmentId","effectiveOn"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"EmploymentChange","collectionExportName":"EmploymentChangeCollection","validationRules":[],"schema":{"tableName":"employment_changes","ddl":"CREATE TABLE IF NOT EXISTS \\"employment_changes\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"employment_id\\" UUID,\\n \\"kind\\" TEXT,\\n \\"effective_on\\" TEXT,\\n \\"from_value\\" TEXT,\\n \\"to_value\\" TEXT,\\n \\"note\\" TEXT,\\n \\"actor_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"kind":{"type":"TEXT","notNull":false,"unique":false},"effective_on":{"type":"TEXT","notNull":false,"unique":false},"from_value":{"type":"TEXT","notNull":false,"unique":false},"to_value":{"type":"TEXT","notNull":false,"unique":false},"note":{"type":"TEXT","notNull":false,"unique":false},"actor_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"employment_changes_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"employment_changes_employment_idx","columns":["tenant_id","employment_id","effective_on"]},{"name":"employment_changes_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employment_changes_employment_id_idx","columns":["employment_id"]},{"name":"employment_changes_actor_profile_id_idx","columns":["actor_profile_id"]}],"version":"5d93422f"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentCollection":{"name":"employmentcollection","className":"EmploymentCollection","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentCollection","collection":"employments","description":"Scoped persistence collection; mutations must use EmploymentService.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"employments"},"extends":"SmrtCollection","extendsTypeArg":"Employment","exportName":"EmploymentCollection","collectionExportName":"EmploymentCollectionCollection","schema":{"tableName":"employments","ddl":"CREATE TABLE IF NOT EXISTS \\"employments\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"profile_id\\" UUID,\\n \\"user_id\\" UUID,\\n \\"employer_profile_id\\" UUID,\\n \\"employee_number\\" TEXT,\\n \\"worker_type\\" TEXT,\\n \\"position\\" TEXT,\\n \\"status\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"user_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employer_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employee_number":{"type":"TEXT","notNull":false,"unique":false},"worker_type":{"type":"TEXT","notNull":false,"unique":false},"position":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"employments_tenant_id_employee_number_idx","columns":["tenant_id","employee_number"],"unique":true,"nullsNotDistinct":true},{"name":"employments_slug_context_idx","columns":["slug","context"]},{"name":"employments_tenant_profile_uq","columns":["tenant_id","profile_id"],"unique":true},{"name":"employments_tenant_user_idx","columns":["tenant_id","user_id"]},{"name":"employments_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employments_profile_id_idx","columns":["profile_id"]},{"name":"employments_user_id_idx","columns":["user_id"]},{"name":"employments_employer_profile_id_idx","columns":["employer_profile_id"]}],"version":"ff7ef7a8"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentTermCollection":{"name":"employmenttermcollection","className":"EmploymentTermCollection","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentTermCollection","collection":"employmentterms","description":"Scoped term collection; closed like its model.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"employment_terms"},"extends":"SmrtCollection","extendsTypeArg":"EmploymentTerm","exportName":"EmploymentTermCollection","collectionExportName":"EmploymentTermCollectionCollection","schema":{"tableName":"employment_terms","ddl":"CREATE TABLE IF NOT EXISTS \\"employment_terms\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"employment_id\\" UUID,\\n \\"started_on\\" TEXT,\\n \\"ended_on\\" TEXT,\\n \\"end_reason\\" TEXT\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"started_on":{"type":"TEXT","notNull":false,"unique":false},"ended_on":{"type":"TEXT","notNull":false,"unique":false},"end_reason":{"type":"TEXT","notNull":false,"unique":false}},"indexes":[{"name":"employment_terms_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"employment_terms_employment_idx","columns":["tenant_id","employment_id","started_on"]},{"name":"employment_terms_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employment_terms_employment_id_idx","columns":["employment_id"]}],"version":"165d209b"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:EmploymentChangeCollection":{"name":"employmentchangecollection","className":"EmploymentChangeCollection","qualifiedName":"@happyvertical/smrt-human-resources:EmploymentChangeCollection","collection":"employmentchanges","description":"Scoped append-only change collection; closed like its model.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/employment/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"employment_changes"},"extends":"SmrtCollection","extendsTypeArg":"EmploymentChange","exportName":"EmploymentChangeCollection","collectionExportName":"EmploymentChangeCollectionCollection","schema":{"tableName":"employment_changes","ddl":"CREATE TABLE IF NOT EXISTS \\"employment_changes\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"employment_id\\" UUID,\\n \\"kind\\" TEXT,\\n \\"effective_on\\" TEXT,\\n \\"from_value\\" TEXT,\\n \\"to_value\\" TEXT,\\n \\"note\\" TEXT,\\n \\"actor_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"kind":{"type":"TEXT","notNull":false,"unique":false},"effective_on":{"type":"TEXT","notNull":false,"unique":false},"from_value":{"type":"TEXT","notNull":false,"unique":false},"to_value":{"type":"TEXT","notNull":false,"unique":false},"note":{"type":"TEXT","notNull":false,"unique":false},"actor_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"employment_changes_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"employment_changes_employment_idx","columns":["tenant_id","employment_id","effective_on"]},{"name":"employment_changes_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"employment_changes_employment_id_idx","columns":["employment_id"]},{"name":"employment_changes_actor_profile_id_idx","columns":["actor_profile_id"]}],"version":"5d93422f"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:Qualification":{"name":"qualification","className":"Qualification","qualifiedName":"@happyvertical/smrt-human-resources:Qualification","collection":"qualifications","description":"A qualification definition: a managed list per tenant. Other packages gate work by referencing its id (@happyvertical/smrt-human-resources:Qualification).","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"key":{"type":"text","required":false},"name":{"type":"text","required":false,"description":"What the qualification is called, such as First aid.","_meta":{"description":"What the qualification is called, such as First aid."}},"kind":{"type":"text","required":false,"description":"The sort of qualification, such as a certificate or a licence.","_meta":{"description":"The sort of qualification, such as a certificate or a licence."},"enum":["ticket","certification","authorization","training","restriction"]},"issuingBody":{"type":"text","required":false,"description":"Who gives it out.","_meta":{"description":"Who gives it out."}},"expires":{"type":"boolean","required":true,"default":false,"description":"Whether it has to be renewed.","_meta":{"description":"Whether it has to be renewed."}},"validityMonths":{"type":"integer","required":false,"description":"How many months it lasts once given.","_meta":{"nullable":true,"description":"How many months it lasts once given."}},"scope":{"type":"text","required":false,"_meta":{},"enum":["person","employment"]},"isActive":{"type":"boolean","required":true,"default":true}},"methods":{"save":{"name":"save","async":true,"parameters":[{"name":"options","type":"SmrtSaveOptions","optional":true}],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"qualifications","sensitive":true,"conflictColumns":["tenant_id","key"],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"}},"extends":"SmrtObject","exportName":"Qualification","collectionExportName":"QualificationCollection","displayLabelField":"name","validationRules":[{"field":"expires","rule":"required","fieldType":"boolean"},{"field":"isActive","rule":"required","fieldType":"boolean"}],"schema":{"tableName":"qualifications","ddl":"CREATE TABLE IF NOT EXISTS \\"qualifications\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"key\\" TEXT,\\n \\"name\\" TEXT,\\n \\"kind\\" TEXT,\\n \\"issuing_body\\" TEXT,\\n \\"expires\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\"validity_months\\" INTEGER,\\n \\"scope\\" TEXT,\\n \\"is_active\\" BOOLEAN NOT NULL DEFAULT TRUE\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"key":{"type":"TEXT","notNull":false,"unique":false},"name":{"type":"TEXT","notNull":false,"unique":false},"kind":{"type":"TEXT","notNull":false,"unique":false},"issuing_body":{"type":"TEXT","notNull":false,"unique":false},"expires":{"type":"BOOLEAN","notNull":true,"unique":false,"default":false},"validity_months":{"type":"INTEGER","notNull":false,"unique":false},"scope":{"type":"TEXT","notNull":false,"unique":false},"is_active":{"type":"BOOLEAN","notNull":true,"unique":false,"default":true}},"indexes":[{"name":"qualifications_tenant_id_key_idx","columns":["tenant_id","key"],"unique":true,"nullsNotDistinct":true},{"name":"qualifications_slug_context_idx","columns":["slug","context"]},{"name":"qualifications_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"c9fa3721"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:HeldQualification":{"name":"heldqualification","className":"HeldQualification","qualifiedName":"@happyvertical/smrt-human-resources:HeldQualification","collection":"heldqualifications","description":"A person holds a qualification. employmentId is set when the definition's scope is employment; such a row is revoked when that employment ends.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"qualificationId":{"type":"foreignKey","required":false,"related":"Qualification","description":"The qualification this person holds.","_meta":{"description":"The qualification this person holds.","onDelete":"RESTRICT"}},"profileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","description":"The person who holds it.","_meta":{"description":"The person who holds it.","onDelete":"RESTRICT"}},"employmentId":{"type":"foreignKey","required":false,"related":"Employment","_meta":{"nullable":true,"onDelete":"RESTRICT"}},"issuedOn":{"type":"text","required":false,"description":"The day it was given.","_meta":{"description":"The day it was given."}},"expiresOn":{"type":"text","required":false,"description":"The day it runs out. Empty if it does not.","_meta":{"nullable":true,"description":"The day it runs out. Empty if it does not."}},"certificateNumber":{"type":"text","required":false,"description":"The number printed on the certificate.","_meta":{"description":"The number printed on the certificate."}},"status":{"type":"text","required":false,"description":"Whether it is valid, expired, suspended or revoked.","_meta":{"description":"Whether it is valid, expired, suspended or revoked."},"enum":["valid","expired","suspended","revoked"]},"verifiedByProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","_meta":{"nullable":true,"onDelete":"RESTRICT"}},"verifiedAt":{"type":"datetime","required":false},"documentAssetId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-assets:Asset","_meta":{"nullable":true}},"renewalOfId":{"type":"foreignKey","required":false,"related":"HeldQualification","_meta":{"nullable":true,"onDelete":"RESTRICT"}}},"methods":{"save":{"name":"save","async":true,"parameters":[{"name":"options","type":"SmrtSaveOptions","optional":true}],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"held_qualifications","sensitive":true,"indexes":[{"name":"held_qualifications_profile_idx","columns":["tenantId","profileId","qualificationId"]},{"name":"held_qualifications_expiry_idx","columns":["tenantId","status","expiresOn"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"HeldQualification","collectionExportName":"HeldQualificationCollection","validationRules":[],"schema":{"tableName":"held_qualifications","ddl":"CREATE TABLE IF NOT EXISTS \\"held_qualifications\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"qualification_id\\" UUID,\\n \\"profile_id\\" UUID,\\n \\"employment_id\\" UUID,\\n \\"issued_on\\" TEXT,\\n \\"expires_on\\" TEXT,\\n \\"certificate_number\\" TEXT,\\n \\"status\\" TEXT,\\n \\"verified_by_profile_id\\" UUID,\\n \\"verified_at\\" TIMESTAMP,\\n \\"document_asset_id\\" UUID,\\n \\"renewal_of_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"qualification_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"issued_on":{"type":"TEXT","notNull":false,"unique":false},"expires_on":{"type":"TEXT","notNull":false,"unique":false},"certificate_number":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false},"verified_by_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"verified_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"document_asset_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"renewal_of_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"held_qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}}},"indexes":[{"name":"held_qualifications_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"held_qualifications_profile_idx","columns":["tenant_id","profile_id","qualification_id"]},{"name":"held_qualifications_expiry_idx","columns":["tenant_id","status","expires_on"]},{"name":"held_qualifications_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"held_qualifications_qualification_id_idx","columns":["qualification_id"]},{"name":"held_qualifications_profile_id_idx","columns":["profile_id"]},{"name":"held_qualifications_employment_id_idx","columns":["employment_id"]},{"name":"held_qualifications_verified_by_profile_id_idx","columns":["verified_by_profile_id"]},{"name":"held_qualifications_document_asset_id_idx","columns":["document_asset_id"]},{"name":"held_qualifications_renewal_of_id_idx","columns":["renewal_of_id"]}],"version":"fafbe37f"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:HeldQualificationChange":{"name":"heldqualificationchange","className":"HeldQualificationChange","qualifiedName":"@happyvertical/smrt-human-resources:HeldQualificationChange","collection":"heldqualificationchanges","description":"Append-only dated change to a held qualification, attributed to an actor.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{"tenantId":{"type":"text","required":true,"_meta":{"sqlType":"UUID","__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":true,"autoPopulate":true,"nullable":false,"mode":"required","field":"tenantId","allowSuperAdminBypass":false}}},"heldQualificationId":{"type":"foreignKey","required":false,"related":"HeldQualification","_meta":{"onDelete":"RESTRICT"}},"kind":{"type":"text","required":false,"_meta":{},"enum":["granted","renewed","suspended","reinstated","revoked","expired"]},"effectiveOn":{"type":"text","required":false,"_meta":{}},"reason":{"type":"text","required":false},"actorProfileId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-profiles:Profile","_meta":{"onDelete":"RESTRICT"}}},"methods":{"save":{"name":"save","async":true,"parameters":[{"name":"options","type":"SmrtSaveOptions","optional":true}],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"held_qualification_changes","sensitive":true,"indexes":[{"name":"held_qualification_changes_held_idx","columns":["tenantId","heldQualificationId","effectiveOn"]}],"api":{"include":[]},"cli":{"include":[]},"mcp":{"include":[]},"tenantScoped":{"mode":"required"},"conflictColumns":["tenant_id","slug","context"]},"extends":"SmrtObject","exportName":"HeldQualificationChange","collectionExportName":"HeldQualificationChangeCollection","validationRules":[],"schema":{"tableName":"held_qualification_changes","ddl":"CREATE TABLE IF NOT EXISTS \\"held_qualification_changes\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"held_qualification_id\\" UUID,\\n \\"kind\\" TEXT,\\n \\"effective_on\\" TEXT,\\n \\"reason\\" TEXT,\\n \\"actor_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"held_qualification_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"held_qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"kind":{"type":"TEXT","notNull":false,"unique":false},"effective_on":{"type":"TEXT","notNull":false,"unique":false},"reason":{"type":"TEXT","notNull":false,"unique":false},"actor_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"held_qualification_changes_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"held_qualification_changes_held_idx","columns":["tenant_id","held_qualification_id","effective_on"]},{"name":"held_qualification_changes_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"held_qualification_changes_held_qualification_id_idx","columns":["held_qualification_id"]},{"name":"held_qualification_changes_actor_profile_id_idx","columns":["actor_profile_id"]}],"version":"ed9ed5e1"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:QualificationCollection":{"name":"qualificationcollection","className":"QualificationCollection","qualifiedName":"@happyvertical/smrt-human-resources:QualificationCollection","collection":"qualifications","description":"Scoped definition collection; mutations must use QualificationService.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"qualifications"},"extends":"SmrtCollection","extendsTypeArg":"Qualification","exportName":"QualificationCollection","collectionExportName":"QualificationCollectionCollection","schema":{"tableName":"qualifications","ddl":"CREATE TABLE IF NOT EXISTS \\"qualifications\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"key\\" TEXT,\\n \\"name\\" TEXT,\\n \\"kind\\" TEXT,\\n \\"issuing_body\\" TEXT,\\n \\"expires\\" BOOLEAN NOT NULL DEFAULT FALSE,\\n \\"validity_months\\" INTEGER,\\n \\"scope\\" TEXT,\\n \\"is_active\\" BOOLEAN NOT NULL DEFAULT TRUE\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"key":{"type":"TEXT","notNull":false,"unique":false},"name":{"type":"TEXT","notNull":false,"unique":false},"kind":{"type":"TEXT","notNull":false,"unique":false},"issuing_body":{"type":"TEXT","notNull":false,"unique":false},"expires":{"type":"BOOLEAN","notNull":true,"unique":false,"default":false},"validity_months":{"type":"INTEGER","notNull":false,"unique":false},"scope":{"type":"TEXT","notNull":false,"unique":false},"is_active":{"type":"BOOLEAN","notNull":true,"unique":false,"default":true}},"indexes":[{"name":"qualifications_tenant_id_key_idx","columns":["tenant_id","key"],"unique":true,"nullsNotDistinct":true},{"name":"qualifications_slug_context_idx","columns":["slug","context"]},{"name":"qualifications_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"c9fa3721"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:HeldQualificationCollection":{"name":"heldqualificationcollection","className":"HeldQualificationCollection","qualifiedName":"@happyvertical/smrt-human-resources:HeldQualificationCollection","collection":"heldqualifications","description":"Scoped held-qualification collection; closed like its model.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"held_qualifications"},"extends":"SmrtCollection","extendsTypeArg":"HeldQualification","exportName":"HeldQualificationCollection","collectionExportName":"HeldQualificationCollectionCollection","schema":{"tableName":"held_qualifications","ddl":"CREATE TABLE IF NOT EXISTS \\"held_qualifications\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"qualification_id\\" UUID,\\n \\"profile_id\\" UUID,\\n \\"employment_id\\" UUID,\\n \\"issued_on\\" TEXT,\\n \\"expires_on\\" TEXT,\\n \\"certificate_number\\" TEXT,\\n \\"status\\" TEXT,\\n \\"verified_by_profile_id\\" UUID,\\n \\"verified_at\\" TIMESTAMP,\\n \\"document_asset_id\\" UUID,\\n \\"renewal_of_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"qualification_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"employment_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"employments","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"issued_on":{"type":"TEXT","notNull":false,"unique":false},"expires_on":{"type":"TEXT","notNull":false,"unique":false},"certificate_number":{"type":"TEXT","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false},"verified_by_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"verified_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"document_asset_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"renewal_of_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"held_qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}}},"indexes":[{"name":"held_qualifications_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"held_qualifications_profile_idx","columns":["tenant_id","profile_id","qualification_id"]},{"name":"held_qualifications_expiry_idx","columns":["tenant_id","status","expires_on"]},{"name":"held_qualifications_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"held_qualifications_qualification_id_idx","columns":["qualification_id"]},{"name":"held_qualifications_profile_id_idx","columns":["profile_id"]},{"name":"held_qualifications_employment_id_idx","columns":["employment_id"]},{"name":"held_qualifications_verified_by_profile_id_idx","columns":["verified_by_profile_id"]},{"name":"held_qualifications_document_asset_id_idx","columns":["document_asset_id"]},{"name":"held_qualifications_renewal_of_id_idx","columns":["renewal_of_id"]}],"version":"fafbe37f"},"importPath":"@happyvertical/smrt-human-resources"},"@happyvertical/smrt-human-resources:HeldQualificationChangeCollection":{"name":"heldqualificationchangecollection","className":"HeldQualificationChangeCollection","qualifiedName":"@happyvertical/smrt-human-resources:HeldQualificationChangeCollection","collection":"heldqualificationchanges","description":"Scoped append-only change collection; closed like its model.","filePath":"/home/runner/work/smrt/smrt/packages/human-resources/src/qualifications/models.ts","packageName":"@happyvertical/smrt-human-resources","fields":{},"methods":{},"decoratorConfig":{"api":{"include":[]},"mcp":{"include":[]},"cli":false,"tableName":"held_qualification_changes"},"extends":"SmrtCollection","extendsTypeArg":"HeldQualificationChange","exportName":"HeldQualificationChangeCollection","collectionExportName":"HeldQualificationChangeCollectionCollection","schema":{"tableName":"held_qualification_changes","ddl":"CREATE TABLE IF NOT EXISTS \\"held_qualification_changes\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID NOT NULL,\\n \\"held_qualification_id\\" UUID,\\n \\"kind\\" TEXT,\\n \\"effective_on\\" TEXT,\\n \\"reason\\" TEXT,\\n \\"actor_profile_id\\" UUID\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":true,"unique":false},"held_qualification_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"held_qualifications","column":"id","onDelete":"RESTRICT","onUpdate":"CASCADE"}},"kind":{"type":"TEXT","notNull":false,"unique":false},"effective_on":{"type":"TEXT","notNull":false,"unique":false},"reason":{"type":"TEXT","notNull":false,"unique":false},"actor_profile_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false}},"indexes":[{"name":"held_qualification_changes_slug_context_idx","columns":["tenant_id","slug","context"],"unique":true},{"name":"held_qualification_changes_held_idx","columns":["tenant_id","held_qualification_id","effective_on"]},{"name":"held_qualification_changes_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"held_qualification_changes_held_qualification_id_idx","columns":["held_qualification_id"]},{"name":"held_qualification_changes_actor_profile_id_idx","columns":["actor_profile_id"]}],"version":"ed9ed5e1"},"importPath":"@happyvertical/smrt-human-resources"}},"moduleType":"smrt","recipes":[{"id":"human-resources.people","className":"HumanResourcesPeopleRecipe","label":"Employees","summary":"Keep a record of who works for you and in what role. Only people can see it; agents cannot read it.","synonyms":["hr","human resources","staff","people","team","workers"],"models":["@happyvertical/smrt-human-resources:Employment","@happyvertical/smrt-human-resources:EmploymentTerm"],"nav":[{"label":"Employees","model":"@happyvertical/smrt-human-resources:Employment","icon":"users","description":"Everyone who works for you, with their role and status.","noun":"employee"}],"requires":[],"section":{"id":"staff","label":"Staff","icon":"users","description":"The people who work for you."},"options":{"@happyvertical/smrt-human-resources:Employment":{"fields":{"profileId":{"label":"Person","order":1},"employeeNumber":{"order":2},"position":{"order":3},"workerType":{"order":4},"status":{"order":5},"tenantId":{"visibility":"hidden"},"userId":{"visibility":"advanced"},"employerProfileId":{"visibility":"advanced"}}},"@happyvertical/smrt-human-resources:EmploymentTerm":{"fields":{"employmentId":{"label":"Person","order":1},"startedOn":{"label":"First day","order":2},"endedOn":{"label":"Last day","order":3},"endReason":{"order":4},"tenantId":{"visibility":"hidden"}}}},"help":{"markdown":"## Overview\\n\\nEmployees is where you keep a record of who works for you. Each person has an\\nemployment record with their role, their worker type and whether they are\\ncurrently active, plus the dates they started and, if they left, finished.\\n\\nOnly people using the app can see these records. They are kept closed to\\nassistants and other automated tools on purpose, so an agent cannot read them.\\n\\n## Tasks\\n\\n### Add an employee\\n\\n1. Open the list of employees and choose **New**.\\n2. Pick the **{field:Employment.profileId}**.\\n3. Give them an **{field:Employment.employeeNumber}**, your own reference for them.\\n4. Fill in their **{field:Employment.position}** and **{field:Employment.workerType}**.\\n5. Save. They now show in your list of employees.\\n\\n### Record that someone has left\\n\\n1. Open the person from the list.\\n2. Set the **{field:Employment.status}** to show they no longer work for you.\\n3. Record their **{field:EmploymentTerm.endedOn}** and the **{field:EmploymentTerm.endReason}**.\\n4. Save. Their history stays on file.\\n","fieldRefs":["Employment.employeeNumber","Employment.position","Employment.profileId","Employment.status","Employment.workerType","EmploymentTerm.endReason","EmploymentTerm.endedOn"]},"exposure":"ui-only","demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}},{"id":"human-resources.qualifications","className":"HumanResourcesQualificationsRecipe","label":"Qualifications","summary":"Track the certificates and training your people hold, and when they run out. Only people can see it; agents cannot read it.","synonyms":["certifications","certificates","licences","training","first aid"],"models":["@happyvertical/smrt-human-resources:Qualification","@happyvertical/smrt-human-resources:HeldQualification"],"nav":[{"label":"Qualifications","model":"@happyvertical/smrt-human-resources:Qualification","icon":"book","description":"The certificates, licences and training your people can hold.","noun":"qualification"},{"label":"Held qualifications","model":"@happyvertical/smrt-human-resources:HeldQualification","icon":"fileText","description":"Who holds which qualification, and when it runs out.","noun":"held qualification"}],"requires":["human-resources.people"],"section":{"id":"staff","label":"Staff","icon":"users","description":"The people who work for you."},"options":{"@happyvertical/smrt-human-resources:Qualification":{"fields":{"name":{"order":1},"kind":{"order":2},"issuingBody":{"order":3},"expires":{"order":4},"validityMonths":{"order":5},"key":{"visibility":"advanced"},"scope":{"visibility":"advanced"},"isActive":{"visibility":"advanced"},"tenantId":{"visibility":"hidden"}}},"@happyvertical/smrt-human-resources:HeldQualification":{"fields":{"qualificationId":{"label":"Qualification","order":1},"profileId":{"label":"Person","order":2},"issuedOn":{"order":3},"expiresOn":{"order":4},"certificateNumber":{"order":5},"status":{"order":6},"tenantId":{"visibility":"hidden"},"employmentId":{"visibility":"advanced"},"verifiedByProfileId":{"visibility":"advanced"},"verifiedAt":{"visibility":"advanced"},"documentAssetId":{"visibility":"advanced"},"renewalOfId":{"visibility":"hidden"}}}},"help":{"markdown":"## Overview\\n\\nQualifications is where you list the certificates, licences and training your\\nwork needs, such as first aid, and record who holds each one and when it runs\\nout. It builds on Employees, so switch that on first.\\n\\nOnly people using the app can see these records. They are kept closed to\\nassistants and other automated tools on purpose, so an agent cannot read them.\\n\\n## Tasks\\n\\n### Set up a qualification\\n\\n1. Open the list of qualifications and choose **New**.\\n2. Type the **{field:Qualification.name}**, for example \\"First aid\\".\\n3. Say who gives it out in **{field:Qualification.issuingBody}**.\\n4. Tick **{field:Qualification.expires}** if it has to be renewed, and set **{field:Qualification.validityMonths}** to how long it lasts.\\n5. Save.\\n\\n### Record who holds a qualification\\n\\n1. Open the held qualifications and choose **New**.\\n2. Pick the **{field:HeldQualification.qualificationId}** and the **{field:HeldQualification.profileId}** who holds it.\\n3. Enter the date it was **{field:HeldQualification.issuedOn}** and when it **{field:HeldQualification.expiresOn}**.\\n4. Add the **{field:HeldQualification.certificateNumber}** from the certificate.\\n5. Set the **{field:HeldQualification.status}** to show whether it is still valid.\\n6. Save. You can now see who needs to renew before the date.\\n","fieldRefs":["HeldQualification.certificateNumber","HeldQualification.expiresOn","HeldQualification.issuedOn","HeldQualification.profileId","HeldQualification.qualificationId","HeldQualification.status","Qualification.expires","Qualification.issuingBody","Qualification.name","Qualification.validityMonths"]},"exposure":"ui-only","demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}}],"smrtDependencies":["@happyvertical/smrt-core","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624"],"via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
8
8
  //#endregion
9
9
  //#region src/dates.ts
10
10
  var ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
@@ -97,11 +97,11 @@ var Employment = class extends SmrtObject {
97
97
  workerType = "employee";
98
98
  position = null;
99
99
  status = "active";
100
- async save() {
100
+ async save(options) {
101
101
  const prior = this.id ? await this.db.get(this.tableName, { id: this.id }) : null;
102
102
  if (!hasHrWrite(this) && (!prior || PACKAGE_OWNED_COLUMNS.some(([column, property]) => (prior[column] ?? null) !== (this[property] ?? null)))) throw new HrError("HR_WRITE_FORBIDDEN", "Employment columns owned by the HR package are writable only through EmploymentService.");
103
103
  if (prior && (prior.tenant_id !== this.tenantId || prior.profile_id !== this.profileId)) throw new HrError("HR_HISTORY_IMMUTABLE", "Employment identity is immutable.");
104
- return await super.save();
104
+ return await super.save(options);
105
105
  }
106
106
  async delete() {
107
107
  throw new HrError("HR_HISTORY_IMMUTABLE", "Employment history cannot be deleted; end the employment instead.");
@@ -151,11 +151,11 @@ var EmploymentTerm = class extends SmrtObject {
151
151
  startedOn = "";
152
152
  endedOn = null;
153
153
  endReason = "";
154
- async save() {
154
+ async save(options) {
155
155
  assertHrWrite(this);
156
156
  const prior = this.id ? await this.db.get(this.tableName, { id: this.id }) : null;
157
157
  if (prior && (prior.ended_on != null || prior.employment_id !== this.employmentId || prior.started_on !== this.startedOn)) throw new HrError("HR_HISTORY_IMMUTABLE", "A term can only be closed once; its start and employment never change.");
158
- return await super.save();
158
+ return await super.save(options);
159
159
  }
160
160
  async delete() {
161
161
  throw new HrError("HR_HISTORY_IMMUTABLE", "Employment terms cannot be deleted.");
@@ -198,11 +198,11 @@ var EmploymentChange = class extends SmrtObject {
198
198
  toValue = null;
199
199
  note = "";
200
200
  actorProfileId = "";
201
- async save() {
201
+ async save(options) {
202
202
  assertHrWrite(this);
203
203
  if (this.id && await this.db.get(this.tableName, { id: this.id })) throw new HrError("HR_HISTORY_IMMUTABLE", "Employment changes are append-only.");
204
204
  this.requireInsertOnSave();
205
- return await super.save();
205
+ return await super.save(options);
206
206
  }
207
207
  async delete() {
208
208
  throw new HrError("HR_HISTORY_IMMUTABLE", "Employment changes cannot be deleted.");
@@ -289,11 +289,11 @@ var Qualification = class extends SmrtObject {
289
289
  validityMonths = null;
290
290
  scope = "person";
291
291
  isActive = true;
292
- async save() {
292
+ async save(options) {
293
293
  assertHrWrite(this);
294
294
  const prior = this.id ? await this.db.get(this.tableName, { id: this.id }) : null;
295
295
  if (prior && (prior.key !== this.key || prior.scope !== this.scope)) throw new HrError("HR_HISTORY_IMMUTABLE", "A qualification key and scope are immutable; deactivate it instead.");
296
- return await super.save();
296
+ return await super.save(options);
297
297
  }
298
298
  async delete() {
299
299
  throw new HrError("HR_HISTORY_IMMUTABLE", "Qualifications cannot be deleted; deactivate them instead.");
@@ -346,12 +346,12 @@ var HeldQualification = class extends SmrtObject {
346
346
  verifiedAt = null;
347
347
  documentAssetId = null;
348
348
  renewalOfId = null;
349
- async save() {
349
+ async save(options) {
350
350
  assertHrWrite(this);
351
351
  const prior = this.id ? await this.db.get(this.tableName, { id: this.id }) : null;
352
352
  if (prior && (prior.tenant_id !== this.tenantId || prior.profile_id !== this.profileId || prior.qualification_id !== this.qualificationId || prior.issued_on !== this.issuedOn)) throw new HrError("HR_HISTORY_IMMUTABLE", "A held qualification keeps its person, qualification and issue date; renew it instead.");
353
353
  if (prior?.status === "revoked" && FROZEN_WHEN_REVOKED.some(([column, property]) => (prior[column] ?? null) !== (this[property] ?? null))) throw new HrError("HR_HISTORY_IMMUTABLE", "A revoked qualification never changes, apart from its verification; grant a new one.");
354
- return await super.save();
354
+ return await super.save(options);
355
355
  }
356
356
  async delete() {
357
357
  throw new HrError("HR_HISTORY_IMMUTABLE", "Held qualifications cannot be deleted; revoke them instead.");
@@ -417,11 +417,11 @@ var HeldQualificationChange = class extends SmrtObject {
417
417
  effectiveOn = "";
418
418
  reason = "";
419
419
  actorProfileId = "";
420
- async save() {
420
+ async save(options) {
421
421
  assertHrWrite(this);
422
422
  if (this.id && await this.db.get(this.tableName, { id: this.id })) throw new HrError("HR_HISTORY_IMMUTABLE", "Held qualification changes are append-only.");
423
423
  this.requireInsertOnSave();
424
- return await super.save();
424
+ return await super.save(options);
425
425
  }
426
426
  async delete() {
427
427
  throw new HrError("HR_HISTORY_IMMUTABLE", "Held qualification changes cannot be deleted.");