@loomcore/api 0.1.78 → 0.1.79

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.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/dist/__tests__/common-test.utils.js +5 -3
  3. package/dist/__tests__/postgres.test-database.js +2 -2
  4. package/dist/__tests__/test-objects.d.ts +6 -1
  5. package/dist/__tests__/test-objects.js +50 -4
  6. package/dist/controllers/auth.controller.d.ts +2 -0
  7. package/dist/controllers/auth.controller.js +9 -4
  8. package/dist/databases/mongo-db/migrations/mongo-initial-schema.js +23 -5
  9. package/dist/databases/operations/__tests__/models/{agent.model.d.ts → test-agent.model.d.ts} +5 -5
  10. package/dist/databases/operations/__tests__/models/test-agent.model.js +8 -0
  11. package/dist/databases/operations/__tests__/models/{client-report.model.d.ts → test-client-report.model.d.ts} +9 -9
  12. package/dist/databases/operations/__tests__/models/test-client-report.model.js +11 -0
  13. package/dist/databases/operations/__tests__/models/test-district.model.d.ts +12 -0
  14. package/dist/databases/operations/__tests__/models/{district.model.js → test-district.model.js} +2 -2
  15. package/dist/databases/operations/__tests__/models/{email-address.model.d.ts → test-email-address.model.d.ts} +3 -3
  16. package/dist/databases/operations/__tests__/models/{email-address.model.js → test-email-address.model.js} +2 -2
  17. package/dist/databases/operations/__tests__/models/{person.model.d.ts → test-person.model.d.ts} +9 -9
  18. package/dist/databases/operations/__tests__/models/test-person.model.js +12 -0
  19. package/dist/databases/operations/__tests__/models/{phone-number.model.d.ts → test-phone-number.model.d.ts} +3 -3
  20. package/dist/databases/operations/__tests__/models/{phone-number.model.js → test-phone-number.model.js} +2 -2
  21. package/dist/databases/operations/__tests__/models/{policy.model.d.ts → test-policy.model.d.ts} +7 -7
  22. package/dist/databases/operations/__tests__/models/test-policy.model.js +12 -0
  23. package/dist/databases/operations/__tests__/models/{premium.model.d.ts → test-premium.model.d.ts} +3 -3
  24. package/dist/databases/operations/__tests__/models/{premium.model.js → test-premium.model.js} +2 -2
  25. package/dist/databases/operations/__tests__/models/test-school.model.d.ts +12 -0
  26. package/dist/databases/operations/__tests__/models/{school.model.js → test-school.model.js} +2 -2
  27. package/dist/databases/operations/__tests__/models/test-state.model.d.ts +8 -0
  28. package/dist/databases/operations/__tests__/models/test-state.model.js +6 -0
  29. package/dist/databases/postgres/migrations/postgres-initial-schema.js +54 -16
  30. package/dist/services/auth.service.d.ts +3 -2
  31. package/dist/services/auth.service.js +15 -1
  32. package/dist/services/person.service.d.ts +6 -0
  33. package/dist/services/person.service.js +7 -0
  34. package/package.json +3 -3
  35. package/dist/databases/operations/__tests__/models/agent.model.js +0 -8
  36. package/dist/databases/operations/__tests__/models/client-report.model.js +0 -11
  37. package/dist/databases/operations/__tests__/models/district.model.d.ts +0 -12
  38. package/dist/databases/operations/__tests__/models/person.model.js +0 -12
  39. package/dist/databases/operations/__tests__/models/policy.model.js +0 -12
  40. package/dist/databases/operations/__tests__/models/school.model.d.ts +0 -12
  41. package/dist/databases/operations/__tests__/models/state.model.d.ts +0 -8
  42. package/dist/databases/operations/__tests__/models/state.model.js +0 -6
package/README.md CHANGED
@@ -63,7 +63,7 @@ The test suite supports two modes for PostgreSQL testing:
63
63
  npm run test:db:stop
64
64
  ```
65
65
 
66
- The container uses port `5433` to avoid conflicts with local PostgreSQL instances. Set `USE_REAL_POSTGRES=true` to use the container instead of pg-mem.
66
+ The container uses port `5444` to avoid conflicts with local PostgreSQL instances. Set `USE_REAL_POSTGRES=true` to use the container instead of pg-mem.
67
67
 
68
68
  ## Example Usage
69
69
 
@@ -17,7 +17,7 @@ import { CategorySpec } from './models/category.model.js';
17
17
  import { ProductSpec } from './models/product.model.js';
18
18
  import { setBaseApiConfig, config } from '../config/index.js';
19
19
  import { entityUtils } from '@loomcore/common/utils';
20
- import { getTestOrgUser } from './test-objects.js';
20
+ import { getTestMetaOrgUserPerson, getTestOrgUser, getTestOrgUserPerson, setTestMetaOrgUserPersonId, setTestOrgUserPersonId } from './test-objects.js';
21
21
  import { TestEmailClient } from './test-email-client.js';
22
22
  let deviceIdCookie;
23
23
  let authService;
@@ -110,13 +110,15 @@ async function createTestUsers() {
110
110
  else {
111
111
  setTestOrgId(existingTestOrg._id);
112
112
  }
113
- const createdTestOrgUser = await authService.createUser(getTestOrgUserContext(), getTestOrgUser());
114
- const createdMetaOrgUser = await authService.createUser(getTestMetaOrgUserContext(), getTestMetaOrgUser());
113
+ const createdTestOrgUser = await authService.createUser(getTestOrgUserContext(), getTestOrgUser(), getTestOrgUserPerson());
114
+ const createdMetaOrgUser = await authService.createUser(getTestMetaOrgUserContext(), getTestMetaOrgUser(), getTestMetaOrgUserPerson());
115
115
  if (!createdTestOrgUser || !createdMetaOrgUser) {
116
116
  throw new Error('Failed to create test user');
117
117
  }
118
118
  setTestMetaOrgUserId(createdMetaOrgUser._id);
119
+ setTestMetaOrgUserPersonId(createdMetaOrgUser.personId);
119
120
  setTestOrgUserId(createdTestOrgUser._id);
121
+ setTestOrgUserPersonId(createdTestOrgUser.personId);
120
122
  return { metaOrgUser: createdMetaOrgUser, testOrgUser: createdTestOrgUser };
121
123
  }
122
124
  catch (error) {
@@ -25,7 +25,7 @@ export class TestPostgresDatabase {
25
25
  let postgresClient;
26
26
  let pool;
27
27
  if (USE_REAL_POSTGRES) {
28
- const connectionString = `postgresql://test-user:test-password@localhost:5433/test-db`;
28
+ const connectionString = `postgresql://test-user:test-password@localhost:5444/test-db`;
29
29
  postgresClient = new Client({
30
30
  connectionString,
31
31
  connectionTimeoutMillis: 5000,
@@ -43,7 +43,7 @@ export class TestPostgresDatabase {
43
43
  `3. Try: docker ps (to verify Docker access)\n` +
44
44
  `Original error: ${errorMessage}`);
45
45
  }
46
- throw new Error(`Failed to connect to PostgreSQL test container at localhost:5433.\n` +
46
+ throw new Error(`Failed to connect to PostgreSQL test container at localhost:5444.\n` +
47
47
  `Make sure the container is running: npm run test:db:start\n` +
48
48
  `Check container status: docker ps | grep postgres-test\n` +
49
49
  `View container logs: npm run test:db:logs\n` +
@@ -1,15 +1,20 @@
1
- import { IOrganization, IUserContext, IUser } from "@loomcore/common/models";
1
+ import { IOrganization, IUserContext, IUser, IPersonModel } from "@loomcore/common/models";
2
2
  export declare let TEST_META_ORG_ID: string | number;
3
3
  export declare let TEST_META_ORG_USER_ID: string | number;
4
+ export declare let TEST_META_ORG_USER_PERSON_ID: string | number;
4
5
  export declare function setTestMetaOrgId(metaOrgId: string | number): void;
5
6
  export declare function setTestMetaOrgUserId(userId: string | number): void;
7
+ export declare function setTestMetaOrgUserPersonId(personId: string | number): void;
6
8
  export declare const TEST_META_ORG_USER_PASSWORD = "test-meta-org-user-password";
7
9
  export declare function getTestMetaOrg(): IOrganization;
8
10
  export declare function getTestMetaOrgUser(): IUser;
11
+ export declare function getTestMetaOrgUserPerson(): IPersonModel;
9
12
  export declare function getTestMetaOrgUserContext(): IUserContext;
10
13
  export declare function setTestOrgId(orgId: string | number): void;
11
14
  export declare function setTestOrgUserId(userId: string | number): void;
15
+ export declare function setTestOrgUserPersonId(personId: string | number): void;
12
16
  export declare function getTestOrg(): IOrganization;
13
17
  export declare const TEST_ORG_USER_PASSWORD = "test-org-user-password";
14
18
  export declare function getTestOrgUser(): IUser;
19
+ export declare function getTestOrgUserPerson(): IPersonModel;
15
20
  export declare function getTestOrgUserContext(): IUserContext;
@@ -1,11 +1,15 @@
1
1
  export let TEST_META_ORG_ID = '69261691f936c45f85da24d0';
2
2
  export let TEST_META_ORG_USER_ID = '69261672f48fb7bf76e54dfb';
3
+ export let TEST_META_ORG_USER_PERSON_ID = '69261672f48fb7bf76e54dfc';
3
4
  export function setTestMetaOrgId(metaOrgId) {
4
5
  TEST_META_ORG_ID = metaOrgId;
5
6
  }
6
7
  export function setTestMetaOrgUserId(userId) {
7
8
  TEST_META_ORG_USER_ID = userId;
8
9
  }
10
+ export function setTestMetaOrgUserPersonId(personId) {
11
+ TEST_META_ORG_USER_PERSON_ID = personId;
12
+ }
9
13
  export const TEST_META_ORG_USER_PASSWORD = 'test-meta-org-user-password';
10
14
  export function getTestMetaOrg() {
11
15
  return {
@@ -25,9 +29,9 @@ export function getTestMetaOrgUser() {
25
29
  return {
26
30
  _id: TEST_META_ORG_USER_ID,
27
31
  _orgId: getTestMetaOrg()._id,
32
+ externalId: 'test-meta-org-user-external-id',
33
+ personId: TEST_META_ORG_USER_PERSON_ID,
28
34
  email: 'test@example.com',
29
- firstName: 'Test',
30
- lastName: 'User',
31
35
  displayName: 'Test User',
32
36
  password: TEST_META_ORG_USER_PASSWORD,
33
37
  _created: new Date(),
@@ -36,6 +40,25 @@ export function getTestMetaOrgUser() {
36
40
  _updatedBy: 'system',
37
41
  };
38
42
  }
43
+ export function getTestMetaOrgUserPerson() {
44
+ return {
45
+ _id: TEST_META_ORG_USER_PERSON_ID,
46
+ _orgId: getTestMetaOrg()._id,
47
+ externalId: 'test-meta-org-user-person-external-id',
48
+ middleName: null,
49
+ firstName: 'Test',
50
+ lastName: 'User',
51
+ isAgent: false,
52
+ isClient: false,
53
+ isEmployee: false,
54
+ dateOfBirth: null,
55
+ extendedTypes: 0,
56
+ _created: new Date(),
57
+ _createdBy: 'system',
58
+ _updated: new Date(),
59
+ _updatedBy: 'system',
60
+ };
61
+ }
39
62
  export function getTestMetaOrgUserContext() {
40
63
  return {
41
64
  user: getTestMetaOrgUser(),
@@ -52,12 +75,16 @@ export function getTestMetaOrgUserContext() {
52
75
  ;
53
76
  let TEST_ORG_ID = '6926167d06c0073a778a124f';
54
77
  let TEST_ORG_USER_ID = '6926167d06c0073a778a1250';
78
+ let TEST_ORG_USER_PERSON_ID = '6926167d06c0073a778a1251';
55
79
  export function setTestOrgId(orgId) {
56
80
  TEST_ORG_ID = orgId;
57
81
  }
58
82
  export function setTestOrgUserId(userId) {
59
83
  TEST_ORG_USER_ID = userId;
60
84
  }
85
+ export function setTestOrgUserPersonId(personId) {
86
+ TEST_ORG_USER_PERSON_ID = personId;
87
+ }
61
88
  export function getTestOrg() {
62
89
  return {
63
90
  _id: TEST_ORG_ID,
@@ -77,9 +104,9 @@ export function getTestOrgUser() {
77
104
  return {
78
105
  _id: TEST_ORG_USER_ID,
79
106
  _orgId: getTestOrg()._id,
107
+ externalId: 'test-org-user-external-id',
80
108
  email: 'test-org-user@example.com',
81
- firstName: 'Test',
82
- lastName: 'User',
109
+ personId: TEST_ORG_USER_PERSON_ID,
83
110
  displayName: 'Test User',
84
111
  password: TEST_ORG_USER_PASSWORD,
85
112
  _created: new Date(),
@@ -88,6 +115,25 @@ export function getTestOrgUser() {
88
115
  _updatedBy: 'system',
89
116
  };
90
117
  }
118
+ export function getTestOrgUserPerson() {
119
+ return {
120
+ _id: TEST_ORG_USER_PERSON_ID,
121
+ _orgId: getTestOrg()._id,
122
+ externalId: 'test-org-user-person-external-id',
123
+ middleName: null,
124
+ firstName: 'Test',
125
+ lastName: 'User',
126
+ isAgent: false,
127
+ isClient: false,
128
+ isEmployee: false,
129
+ dateOfBirth: null,
130
+ extendedTypes: 0,
131
+ _created: new Date(),
132
+ _createdBy: 'system',
133
+ _updated: new Date(),
134
+ _updatedBy: 'system',
135
+ };
136
+ }
91
137
  export function getTestOrgUserContext() {
92
138
  return {
93
139
  user: getTestOrgUser(),
@@ -1,8 +1,10 @@
1
1
  import { Application, Request, Response, NextFunction } from 'express';
2
2
  import { AuthService } from '../services/index.js';
3
3
  import { IDatabase } from '../databases/models/index.js';
4
+ import { PersonService } from '../services/person.service.js';
4
5
  export declare class AuthController {
5
6
  authService: AuthService;
7
+ personService: PersonService;
6
8
  constructor(app: Application, database: IDatabase);
7
9
  mapRoutes(app: Application): void;
8
10
  login(req: Request, res: Response, next: NextFunction): Promise<void>;
@@ -4,10 +4,13 @@ import { BadRequestError, UnauthenticatedError } from '../errors/index.js';
4
4
  import { apiUtils } from '../utils/index.js';
5
5
  import { AuthService } from '../services/index.js';
6
6
  import { isAuthorized } from '../middleware/index.js';
7
+ import { PersonService } from '../services/person.service.js';
7
8
  export class AuthController {
8
9
  authService;
10
+ personService;
9
11
  constructor(app, database) {
10
12
  this.authService = new AuthService(database);
13
+ this.personService = new PersonService(database);
11
14
  this.mapRoutes(app);
12
15
  }
13
16
  mapRoutes(app) {
@@ -27,13 +30,15 @@ export class AuthController {
27
30
  }
28
31
  async registerUser(req, res) {
29
32
  const userContext = req.userContext;
30
- const body = req.body;
31
- const validationErrors = this.authService.validate(body);
32
- entityUtils.handleValidationResult(validationErrors, 'AuthController.registerUser');
33
33
  if (!userContext) {
34
34
  throw new BadRequestError('Missing required fields: userContext is required.');
35
35
  }
36
- const user = await this.authService.createUser(userContext, body);
36
+ const body = req.body;
37
+ let validationErrors = this.authService.validate(body.user);
38
+ entityUtils.handleValidationResult(validationErrors, 'AuthController.registerUser');
39
+ validationErrors = this.personService.validate(body.person);
40
+ entityUtils.handleValidationResult(validationErrors, 'AuthController.registerUser');
41
+ const user = await this.authService.createUser(userContext, body.user, body.person);
37
42
  apiUtils.apiResponse(res, 201, { data: user || undefined }, UserSpec, PublicUserSpec);
38
43
  }
39
44
  async requestTokenUsingRefreshToken(req, res, next) {
@@ -1,7 +1,7 @@
1
1
  import { randomUUID } from 'crypto';
2
- import { initializeSystemUserContext, EmptyUserContext, getSystemUserContext, isSystemUserContextInitialized } from '@loomcore/common/models';
2
+ import { initializeSystemUserContext, EmptyUserContext, getSystemUserContext, isSystemUserContextInitialized, personModelSpec } from '@loomcore/common/models';
3
3
  import { MongoDBDatabase } from '../mongo-db.database.js';
4
- import { AuthService, OrganizationService } from '../../../services/index.js';
4
+ import { AuthService, GenericApiService, OrganizationService } from '../../../services/index.js';
5
5
  export const getMongoInitialSchema = (config) => {
6
6
  const migrations = [];
7
7
  const isMultiTenant = config.app.isMultiTenant;
@@ -167,6 +167,7 @@ export const getMongoInitialSchema = (config) => {
167
167
  up: async ({ context: db }) => {
168
168
  const database = new MongoDBDatabase(db);
169
169
  const authService = new AuthService(database);
170
+ const personService = new GenericApiService(database, 'persons', 'person', personModelSpec);
170
171
  if (!isSystemUserContextInitialized()) {
171
172
  const errorMessage = isMultiTenant
172
173
  ? 'SystemUserContext has not been initialized. The meta-org migration (00000000000008_data-meta-org) should have run before this migration. ' +
@@ -178,15 +179,32 @@ export const getMongoInitialSchema = (config) => {
178
179
  }
179
180
  const systemUserContext = getSystemUserContext();
180
181
  const _id = randomUUID().toString();
182
+ const personId = randomUUID().toString();
183
+ const person = {
184
+ _id: personId,
185
+ _orgId: systemUserContext.organization?._id,
186
+ externalId: 'admin-user-person-external-id',
187
+ middleName: null,
188
+ firstName: 'Admin',
189
+ lastName: 'User',
190
+ isAgent: false,
191
+ isClient: false,
192
+ isEmployee: false,
193
+ dateOfBirth: null,
194
+ extendedTypes: 0,
195
+ _created: new Date(),
196
+ _createdBy: 'system',
197
+ _updated: new Date(),
198
+ _updatedBy: 'system'
199
+ };
181
200
  await authService.createUser(systemUserContext, {
182
201
  _id: _id,
183
202
  _orgId: systemUserContext.organization?._id,
203
+ externalId: 'admin-user-external-id',
184
204
  email: config.auth?.adminUser?.email,
185
205
  password: config.auth?.adminUser?.password,
186
- firstName: 'Admin',
187
- lastName: 'User',
188
206
  displayName: 'Admin User',
189
- });
207
+ }, person);
190
208
  },
191
209
  down: async ({ context: db }) => {
192
210
  if (!config.auth?.adminUser?.email)
@@ -1,10 +1,10 @@
1
1
  import { IAuditable, IEntity } from "@loomcore/common/models";
2
- import { IPersonModel } from "./person.model.js";
3
- export interface IAgentModel extends IEntity, IAuditable {
2
+ import { ITestPersonModel } from "./test-person.model.js";
3
+ export interface ITestAgentModel extends IEntity, IAuditable {
4
4
  person_id: number;
5
- agent_person?: IPersonModel;
5
+ agent_person?: ITestPersonModel;
6
6
  }
7
- export declare const agentSchema: import("@sinclair/typebox").TObject<{
7
+ export declare const testAgentSchema: import("@sinclair/typebox").TObject<{
8
8
  person_id: import("@sinclair/typebox").TNumber;
9
9
  agent_person: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
10
10
  first_name: import("@sinclair/typebox").TString;
@@ -22,4 +22,4 @@ export declare const agentSchema: import("@sinclair/typebox").TObject<{
22
22
  }>>;
23
23
  }>>;
24
24
  }>;
25
- export declare const agentModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
25
+ export declare const testAgentModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -0,0 +1,8 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { testPersonSchema } from "./test-person.model.js";
4
+ export const testAgentSchema = Type.Object({
5
+ person_id: Type.Number(),
6
+ agent_person: Type.Optional(testPersonSchema),
7
+ });
8
+ export const testAgentModelSpec = entityUtils.getModelSpec(testAgentSchema, { isAuditable: true });
@@ -1,13 +1,13 @@
1
- import { IPersonModel } from "./person.model.js";
2
- import { IAgentModel } from "./agent.model.js";
3
- import { IPolicyModel } from "./policy.model.js";
1
+ import { ITestPersonModel } from "./test-person.model.js";
2
+ import { ITestAgentModel } from "./test-agent.model.js";
3
+ import { ITestPolicyModel } from "./test-policy.model.js";
4
4
  import type { IAuditable, IEntity } from "@loomcore/common/models";
5
- export interface IClientReportsModel extends IEntity, IAuditable {
6
- client_person: IPersonModel;
7
- agent?: IAgentModel;
8
- client_policies?: IPolicyModel[];
5
+ export interface ITestClientReportsModel extends IEntity, IAuditable {
6
+ client_person: ITestPersonModel;
7
+ agent?: ITestAgentModel;
8
+ client_policies?: ITestPolicyModel[];
9
9
  }
10
- export declare const clientReportsSchema: import("@sinclair/typebox").TObject<{
10
+ export declare const testClientReportsSchema: import("@sinclair/typebox").TObject<{
11
11
  client_person: import("@sinclair/typebox").TObject<{
12
12
  first_name: import("@sinclair/typebox").TString;
13
13
  middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
@@ -70,4 +70,4 @@ export declare const clientReportsSchema: import("@sinclair/typebox").TObject<{
70
70
  }>>>;
71
71
  }>>>;
72
72
  }>;
73
- export declare const clientReportsModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
73
+ export declare const testClientReportsModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -0,0 +1,11 @@
1
+ import { testPersonSchema } from "./test-person.model.js";
2
+ import { testAgentSchema } from "./test-agent.model.js";
3
+ import { testPolicySchema } from "./test-policy.model.js";
4
+ import { entityUtils } from "@loomcore/common/utils";
5
+ import { Type } from "@sinclair/typebox";
6
+ export const testClientReportsSchema = Type.Object({
7
+ client_person: testPersonSchema,
8
+ agent: Type.Optional(testAgentSchema),
9
+ client_policies: Type.Optional(Type.Array(testPolicySchema))
10
+ });
11
+ export const testClientReportsModelSpec = entityUtils.getModelSpec(testClientReportsSchema, { isAuditable: true });
@@ -0,0 +1,12 @@
1
+ import type { IAuditable, IEntity } from "@loomcore/common/models";
2
+ import { ITestStateModel } from "./test-state.model.js";
3
+ export interface ITestDistrictModel extends IEntity, IAuditable {
4
+ name: string;
5
+ state_id: number;
6
+ state?: ITestStateModel;
7
+ }
8
+ export declare const testDistrictSchema: import("@sinclair/typebox").TObject<{
9
+ name: import("@sinclair/typebox").TString;
10
+ state_id: import("@sinclair/typebox").TNumber;
11
+ }>;
12
+ export declare const testDistrictModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,7 +1,7 @@
1
1
  import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
- export const districtSchema = Type.Object({
3
+ export const testDistrictSchema = Type.Object({
4
4
  name: Type.String(),
5
5
  state_id: Type.Number(),
6
6
  });
7
- export const districtModelSpec = entityUtils.getModelSpec(districtSchema, { isAuditable: true });
7
+ export const testDistrictModelSpec = entityUtils.getModelSpec(testDistrictSchema, { isAuditable: true });
@@ -1,12 +1,12 @@
1
1
  import { IAuditable, IEntity } from "@loomcore/common/models";
2
- export interface IEmailAddressModel extends IEntity, IAuditable {
2
+ export interface ITestEmailAddressModel extends IEntity, IAuditable {
3
3
  person_id: number;
4
4
  email_address: string;
5
5
  is_default: boolean;
6
6
  }
7
- export declare const emailAddressSchema: import("@sinclair/typebox").TObject<{
7
+ export declare const testEmailAddressSchema: import("@sinclair/typebox").TObject<{
8
8
  person_id: import("@sinclair/typebox").TNumber;
9
9
  email_address: import("@sinclair/typebox").TString;
10
10
  is_default: import("@sinclair/typebox").TBoolean;
11
11
  }>;
12
- export declare const emailAddressModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
12
+ export declare const testEmailAddressModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,8 +1,8 @@
1
1
  import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
- export const emailAddressSchema = Type.Object({
3
+ export const testEmailAddressSchema = Type.Object({
4
4
  person_id: Type.Number(),
5
5
  email_address: Type.String(),
6
6
  is_default: Type.Boolean(),
7
7
  });
8
- export const emailAddressModelSpec = entityUtils.getModelSpec(emailAddressSchema);
8
+ export const testEmailAddressModelSpec = entityUtils.getModelSpec(testEmailAddressSchema);
@@ -1,16 +1,16 @@
1
1
  import type { IAuditable, IEntity } from "@loomcore/common/models";
2
- import { IEmailAddressModel } from "./email-address.model.js";
3
- import { IPhoneNumberModel } from "./phone-number.model.js";
4
- import { ISchoolModel } from "./school.model.js";
5
- export interface IPersonModel extends IEntity, IAuditable {
2
+ import { ITestEmailAddressModel } from "./test-email-address.model.js";
3
+ import { ITestPhoneNumberModel } from "./test-phone-number.model.js";
4
+ import { ITestSchoolModel } from "./test-school.model.js";
5
+ export interface ITestPersonModel extends IEntity, IAuditable {
6
6
  first_name: string;
7
7
  middle_name: string | null;
8
8
  last_name: string;
9
- client_email_addresses: IEmailAddressModel[];
10
- client_phone_numbers: IPhoneNumberModel[];
11
- school?: ISchoolModel;
9
+ client_email_addresses: ITestEmailAddressModel[];
10
+ client_phone_numbers: ITestPhoneNumberModel[];
11
+ school?: ITestSchoolModel;
12
12
  }
13
- export declare const personSchema: import("@sinclair/typebox").TObject<{
13
+ export declare const testPersonSchema: import("@sinclair/typebox").TObject<{
14
14
  first_name: import("@sinclair/typebox").TString;
15
15
  middle_name: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
16
16
  last_name: import("@sinclair/typebox").TString;
@@ -25,4 +25,4 @@ export declare const personSchema: import("@sinclair/typebox").TObject<{
25
25
  is_default: import("@sinclair/typebox").TBoolean;
26
26
  }>>;
27
27
  }>;
28
- export declare const personModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
28
+ export declare const testPersonModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -0,0 +1,12 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { testEmailAddressSchema } from "./test-email-address.model.js";
4
+ import { testPhoneNumberSchema } from "./test-phone-number.model.js";
5
+ export const testPersonSchema = Type.Object({
6
+ first_name: Type.String(),
7
+ middle_name: Type.Optional(Type.String()),
8
+ last_name: Type.String(),
9
+ client_phone_numbers: Type.Array(testPhoneNumberSchema),
10
+ client_email_addresses: Type.Array(testEmailAddressSchema),
11
+ });
12
+ export const testPersonModelSpec = entityUtils.getModelSpec(testPersonSchema, { isAuditable: true });
@@ -1,12 +1,12 @@
1
1
  import { IAuditable, IEntity } from "@loomcore/common/models";
2
- export interface IPhoneNumberModel extends IEntity, IAuditable {
2
+ export interface ITestPhoneNumberModel extends IEntity, IAuditable {
3
3
  phone_number: string;
4
4
  phone_number_type: string;
5
5
  is_default: boolean;
6
6
  }
7
- export declare const phoneNumberSchema: import("@sinclair/typebox").TObject<{
7
+ export declare const testPhoneNumberSchema: import("@sinclair/typebox").TObject<{
8
8
  phone_number: import("@sinclair/typebox").TString;
9
9
  phone_number_type: import("@sinclair/typebox").TString;
10
10
  is_default: import("@sinclair/typebox").TBoolean;
11
11
  }>;
12
- export declare const phoneNumberModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
12
+ export declare const testPhoneNumberModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,8 +1,8 @@
1
1
  import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
- export const phoneNumberSchema = Type.Object({
3
+ export const testPhoneNumberSchema = Type.Object({
4
4
  phone_number: Type.String(),
5
5
  phone_number_type: Type.String(),
6
6
  is_default: Type.Boolean(),
7
7
  });
8
- export const phoneNumberModelSpec = entityUtils.getModelSpec(phoneNumberSchema, { isAuditable: true });
8
+ export const testPhoneNumberModelSpec = entityUtils.getModelSpec(testPhoneNumberSchema, { isAuditable: true });
@@ -1,14 +1,14 @@
1
1
  import type { IAuditable, IEntity } from "@loomcore/common/models";
2
- import { IAgentModel } from "./agent.model.js";
3
- import { IPremiumModel } from "./premium.model.js";
4
- export interface IPolicyModel extends IEntity, IAuditable {
2
+ import { ITestAgentModel } from "./test-agent.model.js";
3
+ import { ITestPremiumModel } from "./test-premium.model.js";
4
+ export interface ITestPolicyModel extends IEntity, IAuditable {
5
5
  client_id: number;
6
6
  amount: number;
7
7
  frequency: string;
8
- agents?: IAgentModel[];
9
- policy_premiums?: IPremiumModel[];
8
+ agents?: ITestAgentModel[];
9
+ policy_premiums?: ITestPremiumModel[];
10
10
  }
11
- export declare const policySchema: import("@sinclair/typebox").TObject<{
11
+ export declare const testPolicySchema: import("@sinclair/typebox").TObject<{
12
12
  client_id: import("@sinclair/typebox").TNumber;
13
13
  amount: import("@sinclair/typebox").TNumber;
14
14
  frequency: import("@sinclair/typebox").TString;
@@ -36,4 +36,4 @@ export declare const policySchema: import("@sinclair/typebox").TObject<{
36
36
  date: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TDate, import("@sinclair/typebox").TString]>;
37
37
  }>>>;
38
38
  }>;
39
- export declare const policyModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
39
+ export declare const testPolicyModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -0,0 +1,12 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { testAgentSchema } from "./test-agent.model.js";
4
+ import { testPremiumSchema } from "./test-premium.model.js";
5
+ export const testPolicySchema = Type.Object({
6
+ client_id: Type.Number(),
7
+ amount: Type.Number(),
8
+ frequency: Type.String(),
9
+ agents: Type.Optional(Type.Array(testAgentSchema)),
10
+ policy_premiums: Type.Optional(Type.Array(testPremiumSchema))
11
+ });
12
+ export const testPolicyModelSpec = entityUtils.getModelSpec(testPolicySchema, { isAuditable: true });
@@ -1,12 +1,12 @@
1
1
  import type { IAuditable, IEntity } from "@loomcore/common/models";
2
- export interface IPremiumModel extends IEntity, IAuditable {
2
+ export interface ITestPremiumModel extends IEntity, IAuditable {
3
3
  policy_id: number;
4
4
  amount: number;
5
5
  date: Date | string;
6
6
  }
7
- export declare const premiumSchema: import("@sinclair/typebox").TObject<{
7
+ export declare const testPremiumSchema: import("@sinclair/typebox").TObject<{
8
8
  policy_id: import("@sinclair/typebox").TNumber;
9
9
  amount: import("@sinclair/typebox").TNumber;
10
10
  date: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TDate, import("@sinclair/typebox").TString]>;
11
11
  }>;
12
- export declare const premiumModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
12
+ export declare const testPremiumModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,8 +1,8 @@
1
1
  import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
- export const premiumSchema = Type.Object({
3
+ export const testPremiumSchema = Type.Object({
4
4
  policy_id: Type.Number(),
5
5
  amount: Type.Number(),
6
6
  date: Type.Union([Type.Date(), Type.String()])
7
7
  });
8
- export const premiumModelSpec = entityUtils.getModelSpec(premiumSchema, { isAuditable: true });
8
+ export const testPremiumModelSpec = entityUtils.getModelSpec(testPremiumSchema, { isAuditable: true });
@@ -0,0 +1,12 @@
1
+ import type { IAuditable, IEntity } from "@loomcore/common/models";
2
+ import { ITestDistrictModel } from "./test-district.model.js";
3
+ export interface ITestSchoolModel extends IEntity, IAuditable {
4
+ name: string;
5
+ district_id: number;
6
+ district?: ITestDistrictModel;
7
+ }
8
+ export declare const testSchoolSchema: import("@sinclair/typebox").TObject<{
9
+ name: import("@sinclair/typebox").TString;
10
+ district_id: import("@sinclair/typebox").TNumber;
11
+ }>;
12
+ export declare const testSchoolModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,7 +1,7 @@
1
1
  import { entityUtils } from "@loomcore/common/utils";
2
2
  import { Type } from "@sinclair/typebox";
3
- export const schoolSchema = Type.Object({
3
+ export const testSchoolSchema = Type.Object({
4
4
  name: Type.String(),
5
5
  district_id: Type.Number(),
6
6
  });
7
- export const schoolModelSpec = entityUtils.getModelSpec(schoolSchema, { isAuditable: true });
7
+ export const testSchoolModelSpec = entityUtils.getModelSpec(testSchoolSchema, { isAuditable: true });
@@ -0,0 +1,8 @@
1
+ import type { IAuditable, IEntity } from "@loomcore/common/models";
2
+ export interface ITestStateModel extends IEntity, IAuditable {
3
+ name: string;
4
+ }
5
+ export declare const testStateSchema: import("@sinclair/typebox").TObject<{
6
+ name: import("@sinclair/typebox").TString;
7
+ }>;
8
+ export declare const testStateModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -0,0 +1,6 @@
1
+ import { entityUtils } from "@loomcore/common/utils";
2
+ import { Type } from "@sinclair/typebox";
3
+ export const testStateSchema = Type.Object({
4
+ name: Type.String(),
5
+ });
6
+ export const testStateModelSpec = entityUtils.getModelSpec(testStateSchema, { isAuditable: true });
@@ -43,21 +43,54 @@ export const getPostgresInitialSchema = (config) => {
43
43
  }
44
44
  if (isAuthEnabled)
45
45
  migrations.push({
46
- name: '00000000000002_schema-users',
46
+ name: '00000000000002_schema-persons',
47
47
  up: async ({ context: pool }) => {
48
48
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
49
- const uniqueConstraint = isMultiTenant
49
+ await pool.query(`
50
+ CREATE TABLE IF NOT EXISTS "persons" (
51
+ "_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
52
+ ${orgColumnDef}
53
+ "externalId" VARCHAR(255) UNIQUE,
54
+ "firstName" VARCHAR(255) NOT NULL,
55
+ "middleName" VARCHAR(255),
56
+ "lastName" VARCHAR(255) NOT NULL,
57
+ "dateOfBirth" DATE,
58
+ "isAgent" BOOLEAN NOT NULL DEFAULT FALSE,
59
+ "isClient" BOOLEAN NOT NULL DEFAULT FALSE,
60
+ "isEmployee" BOOLEAN NOT NULL DEFAULT FALSE,
61
+ "extendedTypes" INTEGER NOT NULL DEFAULT 0,
62
+ "_created" TIMESTAMPTZ NOT NULL,
63
+ "_createdBy" INTEGER NOT NULL,
64
+ "_updated" TIMESTAMPTZ NOT NULL,
65
+ "_updatedBy" INTEGER NOT NULL,
66
+ "_deleted" TIMESTAMPTZ,
67
+ "_deletedBy" INTEGER
68
+ )
69
+ `);
70
+ },
71
+ down: async ({ context: pool }) => {
72
+ await pool.query('DROP TABLE IF EXISTS "persons"');
73
+ }
74
+ });
75
+ if (isAuthEnabled)
76
+ migrations.push({
77
+ name: '00000000000003_schema-users',
78
+ up: async ({ context: pool }) => {
79
+ const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
80
+ let uniqueConstraint = isMultiTenant
50
81
  ? 'CONSTRAINT "uk_users_email" UNIQUE ("_orgId", "email")'
51
82
  : 'CONSTRAINT "uk_users_email" UNIQUE ("email")';
83
+ uniqueConstraint += `,
84
+ CONSTRAINT "fk_users_personId" FOREIGN KEY("personId") REFERENCES "persons"("_id") ON DELETE CASCADE`;
52
85
  await pool.query(`
53
86
  CREATE TABLE IF NOT EXISTS "users" (
54
87
  "_id" INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
55
88
  ${orgColumnDef}
89
+ "externalId" VARCHAR(255) UNIQUE,
56
90
  "email" VARCHAR(255) NOT NULL,
57
- "firstName" VARCHAR(255),
58
- "lastName" VARCHAR(255),
59
91
  "displayName" VARCHAR(255),
60
92
  "password" VARCHAR(255) NOT NULL,
93
+ "personId" INTEGER UNIQUE,
61
94
  "_lastLoggedIn" TIMESTAMPTZ,
62
95
  "_lastPasswordChange" TIMESTAMPTZ,
63
96
  "_created" TIMESTAMPTZ NOT NULL,
@@ -76,7 +109,7 @@ export const getPostgresInitialSchema = (config) => {
76
109
  });
77
110
  if (isAuthEnabled)
78
111
  migrations.push({
79
- name: '00000000000003_schema-refresh-tokens',
112
+ name: '00000000000004_schema-refresh-tokens',
80
113
  up: async ({ context: pool }) => {
81
114
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
82
115
  await pool.query(`
@@ -99,7 +132,7 @@ export const getPostgresInitialSchema = (config) => {
99
132
  });
100
133
  if (isAuthEnabled)
101
134
  migrations.push({
102
- name: '00000000000004_schema-password-reset-tokens',
135
+ name: '00000000000005_schema-password-reset-tokens',
103
136
  up: async ({ context: pool }) => {
104
137
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
105
138
  const uniqueConstraint = isMultiTenant
@@ -128,7 +161,7 @@ export const getPostgresInitialSchema = (config) => {
128
161
  });
129
162
  if (isAuthEnabled)
130
163
  migrations.push({
131
- name: '00000000000005_schema-roles',
164
+ name: '00000000000006_schema-roles',
132
165
  up: async ({ context: pool }) => {
133
166
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
134
167
  const uniqueConstraint = isMultiTenant
@@ -150,7 +183,7 @@ export const getPostgresInitialSchema = (config) => {
150
183
  });
151
184
  if (isAuthEnabled)
152
185
  migrations.push({
153
- name: '00000000000006_schema-user-roles',
186
+ name: '00000000000007_schema-user-roles',
154
187
  up: async ({ context: pool }) => {
155
188
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
156
189
  const uniqueConstraint = isMultiTenant
@@ -180,7 +213,7 @@ export const getPostgresInitialSchema = (config) => {
180
213
  });
181
214
  if (isAuthEnabled)
182
215
  migrations.push({
183
- name: '00000000000007_schema-features',
216
+ name: '00000000000008_schema-features',
184
217
  up: async ({ context: pool }) => {
185
218
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
186
219
  const uniqueConstraint = isMultiTenant
@@ -202,7 +235,7 @@ export const getPostgresInitialSchema = (config) => {
202
235
  });
203
236
  if (isAuthEnabled)
204
237
  migrations.push({
205
- name: '00000000000008_schema-authorizations',
238
+ name: '00000000000009_schema-authorizations',
206
239
  up: async ({ context: pool }) => {
207
240
  const orgColumnDef = isMultiTenant ? '"_orgId" INTEGER,' : '';
208
241
  const uniqueConstraint = isMultiTenant
@@ -235,7 +268,7 @@ export const getPostgresInitialSchema = (config) => {
235
268
  });
236
269
  if (isMultiTenant) {
237
270
  migrations.push({
238
- name: '00000000000009_data-meta-org',
271
+ name: '00000000000010_data-meta-org',
239
272
  up: async ({ context: pool }) => {
240
273
  const result = await pool.query(`
241
274
  INSERT INTO "organizations" ("name", "code", "status", "isMetaOrg", "_created", "_createdBy", "_updated", "_updatedBy")
@@ -254,7 +287,7 @@ export const getPostgresInitialSchema = (config) => {
254
287
  }
255
288
  if (isAuthEnabled) {
256
289
  migrations.push({
257
- name: '00000000000010_data-admin-user',
290
+ name: '00000000000011_data-admin-user',
258
291
  up: async ({ context: pool }) => {
259
292
  const client = await pool.connect();
260
293
  try {
@@ -273,14 +306,19 @@ export const getPostgresInitialSchema = (config) => {
273
306
  const userData = {
274
307
  email: config.auth?.adminUser?.email,
275
308
  password: config.auth?.adminUser?.password,
276
- firstName: 'Admin',
277
- lastName: 'User',
278
309
  displayName: 'Admin User',
279
310
  };
280
311
  if (isMultiTenant && systemUserContext.organization?._id) {
281
312
  userData._orgId = systemUserContext.organization._id;
282
313
  }
283
- await authService.createUser(systemUserContext, userData);
314
+ const personData = {
315
+ firstName: 'Admin',
316
+ lastName: 'User',
317
+ };
318
+ if (isMultiTenant && systemUserContext.organization?._id) {
319
+ personData._orgId = systemUserContext.organization._id;
320
+ }
321
+ await authService.createUser(systemUserContext, userData, personData);
284
322
  }
285
323
  finally {
286
324
  client.release();
@@ -295,7 +333,7 @@ export const getPostgresInitialSchema = (config) => {
295
333
  }
296
334
  if (config.auth) {
297
335
  migrations.push({
298
- name: '00000000000011_data-admin-authorizations',
336
+ name: '00000000000012_data-admin-authorizations',
299
337
  up: async ({ context: pool }) => {
300
338
  const client = await pool.connect();
301
339
  try {
@@ -1,5 +1,5 @@
1
1
  import { Request, Response } from 'express';
2
- import { IUserContext, ITokenResponse, ILoginResponse, IUser } from '@loomcore/common/models';
2
+ import { IUserContext, ITokenResponse, ILoginResponse, IUser, IPersonModel } from '@loomcore/common/models';
3
3
  import type { AppIdType } from '@loomcore/common/types';
4
4
  import { MultiTenantApiService } from './multi-tenant-api.service.js';
5
5
  import { UpdateResult } from '../databases/models/update-result.js';
@@ -11,6 +11,7 @@ export declare class AuthService extends MultiTenantApiService<IUser> {
11
11
  private emailService;
12
12
  private organizationService;
13
13
  private authConfig;
14
+ private personService;
14
15
  constructor(database: IDatabase);
15
16
  attemptLogin(req: Request, res: Response, email: string, password: string): Promise<ILoginResponse | null>;
16
17
  logUserIn(userContext: IUserContext, deviceId: string): Promise<{
@@ -22,7 +23,7 @@ export declare class AuthService extends MultiTenantApiService<IUser> {
22
23
  userContext: IUserContext;
23
24
  } | null>;
24
25
  getUserByEmail(email: string): Promise<IUser | null>;
25
- createUser(userContext: IUserContext, user: Partial<IUser>): Promise<IUser | null>;
26
+ createUser(userContext: IUserContext, user: Partial<IUser>, person: Partial<IPersonModel>): Promise<IUser | null>;
26
27
  requestTokenUsingRefreshToken(refreshToken: string, deviceId: string): Promise<ITokenResponse | null>;
27
28
  changeLoggedInUsersPassword(userContext: IUserContext, body: any): Promise<UpdateResult>;
28
29
  changePassword(userContext: IUserContext, queryObject: any, password: string): Promise<UpdateResult>;
@@ -12,18 +12,21 @@ import { passwordUtils } from '../utils/index.js';
12
12
  import { config } from '../config/index.js';
13
13
  import { refreshTokenModelSpec } from '../models/refresh-token.model.js';
14
14
  import { getUserContextAuthorizations } from './utils/getUserContextAuthorizations.util.js';
15
+ import { PersonService } from './person.service.js';
15
16
  export class AuthService extends MultiTenantApiService {
16
17
  refreshTokenService;
17
18
  passwordResetTokenService;
18
19
  emailService;
19
20
  organizationService;
20
21
  authConfig;
22
+ personService;
21
23
  constructor(database) {
22
24
  super(database, 'users', 'user', UserSpec);
23
25
  this.refreshTokenService = new GenericApiService(database, 'refresh_tokens', 'refresh_token', refreshTokenModelSpec);
24
26
  this.passwordResetTokenService = new PasswordResetTokenService(database);
25
27
  this.emailService = new EmailService();
26
28
  this.organizationService = new OrganizationService(database);
29
+ this.personService = new PersonService(database);
27
30
  if (!config.auth) {
28
31
  throw new ServerError('Auth configuration is not set');
29
32
  }
@@ -77,7 +80,7 @@ export class AuthService extends MultiTenantApiService {
77
80
  }
78
81
  return this.database.postProcessEntity(rawUser, this.modelSpec.fullSchema);
79
82
  }
80
- async createUser(userContext, user) {
83
+ async createUser(userContext, user, person) {
81
84
  if (userContext.user._id === 'system') {
82
85
  if (config.app.isMultiTenant && userContext.organization?._id !== user._orgId) {
83
86
  throw new BadRequestError('User is not authorized to create a user in this organization');
@@ -95,6 +98,17 @@ export class AuthService extends MultiTenantApiService {
95
98
  throw new BadRequestError('A user with this email address already exists');
96
99
  }
97
100
  }
101
+ let personId = user.personId;
102
+ if (personId && person) {
103
+ const updatePersonResult = await this.personService.partialUpdateById(userContext, personId, person);
104
+ }
105
+ if (!personId) {
106
+ const newPerson = await this.personService.create(userContext, person);
107
+ if (newPerson) {
108
+ personId = newPerson._id;
109
+ }
110
+ }
111
+ user.personId = personId;
98
112
  return await this.create(userContext, user);
99
113
  }
100
114
  async requestTokenUsingRefreshToken(refreshToken, deviceId) {
@@ -0,0 +1,6 @@
1
+ import { IPersonModel } from "@loomcore/common/models";
2
+ import { IDatabase } from "../databases/index.js";
3
+ import { GenericApiService } from "./generic-api-service/generic-api.service.js";
4
+ export declare class PersonService extends GenericApiService<IPersonModel> {
5
+ constructor(database: IDatabase);
6
+ }
@@ -0,0 +1,7 @@
1
+ import { personModelSpec } from "@loomcore/common/models";
2
+ import { GenericApiService } from "./generic-api-service/generic-api.service.js";
3
+ export class PersonService extends GenericApiService {
4
+ constructor(database) {
5
+ super(database, 'persons', 'person', personModelSpec);
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loomcore/api",
3
- "version": "0.1.78",
3
+ "version": "0.1.79",
4
4
  "private": false,
5
5
  "description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
6
6
  "scripts": {
@@ -57,7 +57,7 @@
57
57
  "qs": "^6.14.1"
58
58
  },
59
59
  "peerDependencies": {
60
- "@loomcore/common": "^0.0.43",
60
+ "@loomcore/common": "^0.0.46",
61
61
  "@sinclair/typebox": "0.34.33",
62
62
  "cookie-parser": "^1.4.6",
63
63
  "cors": "^2.8.5",
@@ -82,7 +82,7 @@
82
82
  "cross-env": "^7.0.3",
83
83
  "mongodb-memory-server": "^9.3.0",
84
84
  "npm-run-all": "^4.1.5",
85
- "pg-mem": "^3.0.8",
85
+ "pg-mem": "^3.0.12",
86
86
  "rxjs": "^7.8.0",
87
87
  "supertest": "^7.1.0",
88
88
  "typescript": "^5.8.3",
@@ -1,8 +0,0 @@
1
- import { entityUtils } from "@loomcore/common/utils";
2
- import { Type } from "@sinclair/typebox";
3
- import { personSchema } from "./person.model.js";
4
- export const agentSchema = Type.Object({
5
- person_id: Type.Number(),
6
- agent_person: Type.Optional(personSchema),
7
- });
8
- export const agentModelSpec = entityUtils.getModelSpec(agentSchema, { isAuditable: true });
@@ -1,11 +0,0 @@
1
- import { personSchema } from "./person.model.js";
2
- import { agentSchema } from "./agent.model.js";
3
- import { policySchema } from "./policy.model.js";
4
- import { entityUtils } from "@loomcore/common/utils";
5
- import { Type } from "@sinclair/typebox";
6
- export const clientReportsSchema = Type.Object({
7
- client_person: personSchema,
8
- agent: Type.Optional(agentSchema),
9
- client_policies: Type.Optional(Type.Array(policySchema))
10
- });
11
- export const clientReportsModelSpec = entityUtils.getModelSpec(clientReportsSchema, { isAuditable: true });
@@ -1,12 +0,0 @@
1
- import type { IAuditable, IEntity } from "@loomcore/common/models";
2
- import { IStateModel } from "./state.model.js";
3
- export interface IDistrictModel extends IEntity, IAuditable {
4
- name: string;
5
- state_id: number;
6
- state?: IStateModel;
7
- }
8
- export declare const districtSchema: import("@sinclair/typebox").TObject<{
9
- name: import("@sinclair/typebox").TString;
10
- state_id: import("@sinclair/typebox").TNumber;
11
- }>;
12
- export declare const districtModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,12 +0,0 @@
1
- import { entityUtils } from "@loomcore/common/utils";
2
- import { Type } from "@sinclair/typebox";
3
- import { emailAddressSchema } from "./email-address.model.js";
4
- import { phoneNumberSchema } from "./phone-number.model.js";
5
- export const personSchema = Type.Object({
6
- first_name: Type.String(),
7
- middle_name: Type.Optional(Type.String()),
8
- last_name: Type.String(),
9
- client_phone_numbers: Type.Array(phoneNumberSchema),
10
- client_email_addresses: Type.Array(emailAddressSchema),
11
- });
12
- export const personModelSpec = entityUtils.getModelSpec(personSchema, { isAuditable: true });
@@ -1,12 +0,0 @@
1
- import { entityUtils } from "@loomcore/common/utils";
2
- import { Type } from "@sinclair/typebox";
3
- import { agentSchema } from "./agent.model.js";
4
- import { premiumSchema } from "./premium.model.js";
5
- export const policySchema = Type.Object({
6
- client_id: Type.Number(),
7
- amount: Type.Number(),
8
- frequency: Type.String(),
9
- agents: Type.Optional(Type.Array(agentSchema)),
10
- policy_premiums: Type.Optional(Type.Array(premiumSchema))
11
- });
12
- export const policyModelSpec = entityUtils.getModelSpec(policySchema, { isAuditable: true });
@@ -1,12 +0,0 @@
1
- import type { IAuditable, IEntity } from "@loomcore/common/models";
2
- import { IDistrictModel } from "./district.model.js";
3
- export interface ISchoolModel extends IEntity, IAuditable {
4
- name: string;
5
- district_id: number;
6
- district?: IDistrictModel;
7
- }
8
- export declare const schoolSchema: import("@sinclair/typebox").TObject<{
9
- name: import("@sinclair/typebox").TString;
10
- district_id: import("@sinclair/typebox").TNumber;
11
- }>;
12
- export declare const schoolModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,8 +0,0 @@
1
- import type { IAuditable, IEntity } from "@loomcore/common/models";
2
- export interface IStateModel extends IEntity, IAuditable {
3
- name: string;
4
- }
5
- export declare const stateSchema: import("@sinclair/typebox").TObject<{
6
- name: import("@sinclair/typebox").TString;
7
- }>;
8
- export declare const stateModelSpec: import("@loomcore/common/models").IModelSpec<import("@sinclair/typebox").TSchema>;
@@ -1,6 +0,0 @@
1
- import { entityUtils } from "@loomcore/common/utils";
2
- import { Type } from "@sinclair/typebox";
3
- export const stateSchema = Type.Object({
4
- name: Type.String(),
5
- });
6
- export const stateModelSpec = entityUtils.getModelSpec(stateSchema, { isAuditable: true });