@tailor-platform/erp-kit 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/README.md +196 -28
  2. package/dist/cli.js +894 -0
  3. package/package.json +65 -8
  4. package/rules/app-compose/backend/auth.md +78 -0
  5. package/rules/app-compose/frontend/auth.md +55 -0
  6. package/rules/app-compose/frontend/component.md +55 -0
  7. package/rules/app-compose/frontend/page.md +86 -0
  8. package/rules/app-compose/frontend/screen-detailview.md +112 -0
  9. package/rules/app-compose/frontend/screen-form.md +145 -0
  10. package/rules/app-compose/frontend/screen-listview.md +159 -0
  11. package/rules/app-compose/structure.md +32 -0
  12. package/rules/module-development/commands.md +54 -0
  13. package/rules/module-development/cross-module-type-injection.md +28 -0
  14. package/rules/module-development/dependency-modules.md +24 -0
  15. package/rules/module-development/errors.md +12 -0
  16. package/rules/module-development/executors.md +67 -0
  17. package/rules/module-development/exports.md +13 -0
  18. package/rules/module-development/models.md +34 -0
  19. package/rules/module-development/structure.md +27 -0
  20. package/rules/module-development/sync-vs-async-operations.md +83 -0
  21. package/rules/module-development/testing.md +43 -0
  22. package/rules/sdk-best-practices/db-relations.md +74 -0
  23. package/rules/sdk-best-practices/sdk-docs.md +14 -0
  24. package/schemas/app-compose/actors.yml +34 -0
  25. package/schemas/app-compose/business-flow.yml +50 -0
  26. package/schemas/app-compose/requirements.yml +33 -0
  27. package/schemas/app-compose/resolver.yml +47 -0
  28. package/schemas/app-compose/screen.yml +81 -0
  29. package/schemas/app-compose/story.yml +67 -0
  30. package/schemas/module/command.yml +52 -0
  31. package/schemas/module/feature.yml +58 -0
  32. package/schemas/module/model.yml +70 -0
  33. package/schemas/module/module.yml +50 -0
  34. package/skills/1-module-docs/SKILL.md +107 -0
  35. package/skills/2-module-feature-breakdown/SKILL.md +66 -0
  36. package/skills/3-module-doc-review/SKILL.md +230 -0
  37. package/skills/4-module-tdd-implementation/SKILL.md +56 -0
  38. package/skills/5-module-implementation-review/SKILL.md +400 -0
  39. package/skills/app-compose-1-requirement-analysis/SKILL.md +85 -0
  40. package/skills/app-compose-2-requirements-breakdown/SKILL.md +88 -0
  41. package/skills/app-compose-3-doc-review/SKILL.md +112 -0
  42. package/skills/app-compose-4-design-mock/SKILL.md +248 -0
  43. package/skills/app-compose-5-design-mock-review/SKILL.md +283 -0
  44. package/skills/app-compose-6-implementation-spec/SKILL.md +122 -0
  45. package/skills/mock-scenario/SKILL.md +118 -0
  46. package/src/app.ts +1 -0
  47. package/src/cli.ts +120 -0
  48. package/src/commands/check.test.ts +30 -0
  49. package/src/commands/check.ts +66 -0
  50. package/src/commands/init.test.ts +77 -0
  51. package/src/commands/init.ts +87 -0
  52. package/src/commands/mock/index.ts +53 -0
  53. package/src/commands/mock/start.ts +179 -0
  54. package/src/commands/mock/validate.test.ts +185 -0
  55. package/src/commands/mock/validate.ts +198 -0
  56. package/src/commands/scaffold.test.ts +76 -0
  57. package/src/commands/scaffold.ts +119 -0
  58. package/src/commands/sync-check.test.ts +125 -0
  59. package/src/commands/sync-check.ts +182 -0
  60. package/src/integration.test.ts +63 -0
  61. package/src/mdschema.ts +48 -0
  62. package/src/mockServer.ts +55 -0
  63. package/src/module.ts +86 -0
  64. package/src/modules/accounting/.gitkeep +0 -0
  65. package/src/modules/coa-management/.gitkeep +0 -0
  66. package/src/modules/inventory/.gitkeep +0 -0
  67. package/src/modules/manufacturing/.gitkeep +0 -0
  68. package/src/modules/primitives/README.md +39 -0
  69. package/src/modules/primitives/command/activateCategory.test.ts +75 -0
  70. package/src/modules/primitives/command/activateCategory.ts +50 -0
  71. package/src/modules/primitives/command/activateCurrency.test.ts +70 -0
  72. package/src/modules/primitives/command/activateCurrency.ts +50 -0
  73. package/src/modules/primitives/command/activateUnit.test.ts +53 -0
  74. package/src/modules/primitives/command/activateUnit.ts +50 -0
  75. package/src/modules/primitives/command/convertAmount.test.ts +275 -0
  76. package/src/modules/primitives/command/convertAmount.ts +126 -0
  77. package/src/modules/primitives/command/convertQuantity.test.ts +219 -0
  78. package/src/modules/primitives/command/convertQuantity.ts +73 -0
  79. package/src/modules/primitives/command/createCategory.test.ts +126 -0
  80. package/src/modules/primitives/command/createCategory.ts +89 -0
  81. package/src/modules/primitives/command/createCurrency.test.ts +191 -0
  82. package/src/modules/primitives/command/createCurrency.ts +77 -0
  83. package/src/modules/primitives/command/createExchangeRate.test.ts +216 -0
  84. package/src/modules/primitives/command/createExchangeRate.ts +91 -0
  85. package/src/modules/primitives/command/createUnit.test.ts +214 -0
  86. package/src/modules/primitives/command/createUnit.ts +88 -0
  87. package/src/modules/primitives/command/deactivateCategory.test.ts +97 -0
  88. package/src/modules/primitives/command/deactivateCategory.ts +62 -0
  89. package/src/modules/primitives/command/deactivateCurrency.test.ts +85 -0
  90. package/src/modules/primitives/command/deactivateCurrency.ts +55 -0
  91. package/src/modules/primitives/command/deactivateUnit.test.ts +78 -0
  92. package/src/modules/primitives/command/deactivateUnit.ts +62 -0
  93. package/src/modules/primitives/command/setBaseCurrency.test.ts +98 -0
  94. package/src/modules/primitives/command/setBaseCurrency.ts +74 -0
  95. package/src/modules/primitives/command/setReferenceUnit.test.ts +108 -0
  96. package/src/modules/primitives/command/setReferenceUnit.ts +84 -0
  97. package/src/modules/primitives/db/currency.ts +30 -0
  98. package/src/modules/primitives/db/exchangeRate.ts +28 -0
  99. package/src/modules/primitives/db/unit.ts +32 -0
  100. package/src/modules/primitives/db/uomCategory.ts +32 -0
  101. package/src/modules/primitives/docs/commands/ActivateCategory.md +34 -0
  102. package/src/modules/primitives/docs/commands/ActivateCurrency.md +33 -0
  103. package/src/modules/primitives/docs/commands/ActivateUnit.md +34 -0
  104. package/src/modules/primitives/docs/commands/ConvertAmount.md +50 -0
  105. package/src/modules/primitives/docs/commands/ConvertQuantity.md +43 -0
  106. package/src/modules/primitives/docs/commands/CreateCategory.md +44 -0
  107. package/src/modules/primitives/docs/commands/CreateCurrency.md +47 -0
  108. package/src/modules/primitives/docs/commands/CreateExchangeRate.md +48 -0
  109. package/src/modules/primitives/docs/commands/CreateUnit.md +48 -0
  110. package/src/modules/primitives/docs/commands/DeactivateCategory.md +38 -0
  111. package/src/modules/primitives/docs/commands/DeactivateCurrency.md +38 -0
  112. package/src/modules/primitives/docs/commands/DeactivateUnit.md +38 -0
  113. package/src/modules/primitives/docs/commands/SetBaseCurrency.md +39 -0
  114. package/src/modules/primitives/docs/commands/SetReferenceUnit.md +43 -0
  115. package/src/modules/primitives/docs/features/currency-definitions.md +55 -0
  116. package/src/modules/primitives/docs/features/exchange-rates.md +61 -0
  117. package/src/modules/primitives/docs/features/unit-conversion.md +66 -0
  118. package/src/modules/primitives/docs/features/uom-categories.md +52 -0
  119. package/src/modules/primitives/docs/models/Currency.md +45 -0
  120. package/src/modules/primitives/docs/models/ExchangeRate.md +33 -0
  121. package/src/modules/primitives/docs/models/Unit.md +46 -0
  122. package/src/modules/primitives/docs/models/UoMCategory.md +44 -0
  123. package/src/modules/primitives/generated/kysely-tailordb.ts +95 -0
  124. package/src/modules/primitives/index.ts +40 -0
  125. package/src/modules/primitives/lib/errors.ts +138 -0
  126. package/src/modules/primitives/lib/types.ts +20 -0
  127. package/src/modules/primitives/module.ts +66 -0
  128. package/src/modules/primitives/permissions.ts +18 -0
  129. package/src/modules/primitives/tailor.config.ts +11 -0
  130. package/src/modules/primitives/testing/fixtures.ts +161 -0
  131. package/src/modules/product-management/.gitkeep +0 -0
  132. package/src/modules/purchase/.gitkeep +0 -0
  133. package/src/modules/sales/.gitkeep +0 -0
  134. package/src/modules/shared/createContext.test.ts +39 -0
  135. package/src/modules/shared/createContext.ts +15 -0
  136. package/src/modules/shared/defineCommand.test.ts +42 -0
  137. package/src/modules/shared/defineCommand.ts +19 -0
  138. package/src/modules/shared/definePermissions.test.ts +146 -0
  139. package/src/modules/shared/definePermissions.ts +94 -0
  140. package/src/modules/shared/entityTypes.ts +15 -0
  141. package/src/modules/shared/errors.ts +22 -0
  142. package/src/modules/shared/index.ts +1 -0
  143. package/src/modules/shared/internal.ts +13 -0
  144. package/src/modules/shared/requirePermission.test.ts +47 -0
  145. package/src/modules/shared/requirePermission.ts +8 -0
  146. package/src/modules/shared/types.ts +4 -0
  147. package/src/modules/supplier-management/.gitkeep +0 -0
  148. package/src/modules/supplier-portal/.gitkeep +0 -0
  149. package/src/modules/testing/index.ts +120 -0
  150. package/src/modules/user-management/README.md +38 -0
  151. package/src/modules/user-management/command/activateUser.test.ts +112 -0
  152. package/src/modules/user-management/command/activateUser.ts +67 -0
  153. package/src/modules/user-management/command/assignPermissionToRole.test.ts +119 -0
  154. package/src/modules/user-management/command/assignPermissionToRole.ts +87 -0
  155. package/src/modules/user-management/command/assignRoleToUser.test.ts +162 -0
  156. package/src/modules/user-management/command/assignRoleToUser.ts +93 -0
  157. package/src/modules/user-management/command/createPermission.test.ts +143 -0
  158. package/src/modules/user-management/command/createPermission.ts +66 -0
  159. package/src/modules/user-management/command/createRole.test.ts +115 -0
  160. package/src/modules/user-management/command/createRole.ts +52 -0
  161. package/src/modules/user-management/command/createUser.test.ts +198 -0
  162. package/src/modules/user-management/command/createUser.ts +85 -0
  163. package/src/modules/user-management/command/deactivateUser.test.ts +112 -0
  164. package/src/modules/user-management/command/deactivateUser.ts +67 -0
  165. package/src/modules/user-management/command/logAuditEvent.test.ts +179 -0
  166. package/src/modules/user-management/command/logAuditEvent.ts +59 -0
  167. package/src/modules/user-management/command/reactivateUser.test.ts +115 -0
  168. package/src/modules/user-management/command/reactivateUser.ts +67 -0
  169. package/src/modules/user-management/command/revokePermissionFromRole.test.ts +112 -0
  170. package/src/modules/user-management/command/revokePermissionFromRole.ts +81 -0
  171. package/src/modules/user-management/command/revokeRoleFromUser.test.ts +112 -0
  172. package/src/modules/user-management/command/revokeRoleFromUser.ts +81 -0
  173. package/src/modules/user-management/db/auditEvent.ts +47 -0
  174. package/src/modules/user-management/db/permission.ts +31 -0
  175. package/src/modules/user-management/db/role.ts +28 -0
  176. package/src/modules/user-management/db/rolePermission.ts +44 -0
  177. package/src/modules/user-management/db/user.ts +38 -0
  178. package/src/modules/user-management/db/userRole.ts +44 -0
  179. package/src/modules/user-management/docs/commands/ActivateUser.md +36 -0
  180. package/src/modules/user-management/docs/commands/AssignPermissionToRole.md +39 -0
  181. package/src/modules/user-management/docs/commands/AssignRoleToUser.md +43 -0
  182. package/src/modules/user-management/docs/commands/CreatePermission.md +35 -0
  183. package/src/modules/user-management/docs/commands/CreateRole.md +35 -0
  184. package/src/modules/user-management/docs/commands/CreateUser.md +41 -0
  185. package/src/modules/user-management/docs/commands/DeactivateUser.md +38 -0
  186. package/src/modules/user-management/docs/commands/LogAuditEvent.md +37 -0
  187. package/src/modules/user-management/docs/commands/ReactivateUser.md +37 -0
  188. package/src/modules/user-management/docs/commands/RevokePermissionFromRole.md +40 -0
  189. package/src/modules/user-management/docs/commands/RevokeRoleFromUser.md +40 -0
  190. package/src/modules/user-management/docs/features/audit-trail.md +80 -0
  191. package/src/modules/user-management/docs/features/role-based-access-control.md +76 -0
  192. package/src/modules/user-management/docs/features/user-account-management.md +64 -0
  193. package/src/modules/user-management/docs/models/AuditEvent.md +34 -0
  194. package/src/modules/user-management/docs/models/Permission.md +31 -0
  195. package/src/modules/user-management/docs/models/Role.md +31 -0
  196. package/src/modules/user-management/docs/models/RolePermission.md +33 -0
  197. package/src/modules/user-management/docs/models/User.md +47 -0
  198. package/src/modules/user-management/docs/models/UserRole.md +34 -0
  199. package/src/modules/user-management/docs/plans/2026-01-30-flattened-permissions-design.md +52 -0
  200. package/src/modules/user-management/executor/recomputeOnRolePermissionChange.ts +61 -0
  201. package/src/modules/user-management/generated/enums.ts +24 -0
  202. package/src/modules/user-management/generated/kysely-tailordb.ts +112 -0
  203. package/src/modules/user-management/index.ts +32 -0
  204. package/src/modules/user-management/lib/errors.ts +81 -0
  205. package/src/modules/user-management/lib/recomputeUserPermissions.ts +53 -0
  206. package/src/modules/user-management/lib/types.ts +31 -0
  207. package/src/modules/user-management/module.ts +77 -0
  208. package/src/modules/user-management/permissions.ts +15 -0
  209. package/src/modules/user-management/tailor.config.ts +11 -0
  210. package/src/modules/user-management/testing/fixtures.ts +98 -0
  211. package/src/schemas.ts +25 -0
  212. package/src/testing.ts +10 -0
  213. package/src/util.ts +3 -0
@@ -0,0 +1,52 @@
1
+ # UoM Categories
2
+
3
+ ## Overview
4
+
5
+ UoM Categories organize units of measure into logical groupings where conversions are meaningful. Each category has a designated reference unit that serves as the base for all conversion calculations within that category. Units can only be converted to other units within the same category.
6
+
7
+ This feature enables businesses to define their measurement standards while maintaining mathematical consistency across all unit conversions.
8
+
9
+ ## Business Purpose
10
+
11
+ Organizations need to track quantities in various units depending on context - purchasing in bulk units, selling in retail units, and managing inventory in standardized units. UoM Categories ensure that:
12
+
13
+ - Conversions only occur between compatible units (you cannot convert kilograms to liters)
14
+ - A single source of truth exists for conversion factors via the reference unit
15
+ - New units can be added without updating relationships to every other unit
16
+ - Mathematical precision is maintained through a single conversion path
17
+
18
+ ## Process Flow
19
+
20
+ ```mermaid
21
+ flowchart TD
22
+ A[Create Category] --> B{Has Reference Unit?}
23
+ B -->|No| C[Create Reference Unit]
24
+ C --> D[Set as Category Reference]
25
+ B -->|Yes| E[Add Additional Units]
26
+ D --> E
27
+ E --> F[Define Conversion Factor]
28
+ F --> G{More Units?}
29
+ G -->|Yes| E
30
+ G -->|No| H[Category Ready]
31
+ H --> I[Products Can Reference Units]
32
+ ```
33
+
34
+ ## Scenario Patterns
35
+
36
+ - **Initial Setup**: Administrator creates standard categories (Unit, Weight, Volume, Length, Time) with reference units during system initialization
37
+ - **Industry-Specific Units**: Manufacturing adds custom units like "Pallet" or "Roll" to the Unit category with appropriate conversion factors
38
+ - **Regional Adaptation**: Business operating in multiple regions adds both metric and imperial units to Weight and Length categories
39
+ - **Precision Requirements**: Pharmaceutical company creates units with high decimal precision for precise dosage tracking
40
+
41
+ ## Test Cases
42
+
43
+ - Creating a category without a reference unit should fail or prompt for reference unit creation
44
+ - Setting a reference unit should automatically set its conversion factor to 1.0
45
+ - Deleting a reference unit should be prevented if other units exist in the category
46
+ - Category names must be unique within the system
47
+ - Deactivating a category should prevent new products from using its units
48
+
49
+ ## Reference Links
50
+
51
+ - [Odoo Units of Measure Documentation](https://www.odoo.com/documentation/19.0/applications/inventory_and_mrp/inventory/product_management/configure/uom.html)
52
+ - [ISO 80000 Quantities and Units Standard](https://www.iso.org/standard/76921.html)
@@ -0,0 +1,45 @@
1
+ # Currency
2
+
3
+ ## Description
4
+
5
+ Currency defines a monetary unit available for use across the ERP system. Each currency contains the ISO 4217 code, display symbol, name, and decimal precision. One currency is designated as the base currency for the organization, serving as the default for reporting and consolidation.
6
+
7
+ Examples: USD (US Dollar), EUR (Euro), JPY (Japanese Yen).
8
+
9
+ ## Domain Model Definitions
10
+
11
+ ### Model type
12
+
13
+ Stateful
14
+
15
+ #### State Transitions
16
+
17
+ ```mermaid
18
+ stateDiagram-v2
19
+ [*] --> Active: create
20
+ Active --> Inactive: deactivate
21
+ Inactive --> Active: activate
22
+ note right of Active: Base currency cannot be deactivated
23
+ ```
24
+
25
+ ### Command Definitions
26
+
27
+ - [createCurrency](../commands/CreateCurrency.md)
28
+ - [activateCurrency](../commands/ActivateCurrency.md)
29
+ - [deactivateCurrency](../commands/DeactivateCurrency.md)
30
+ - [setBaseCurrency](../commands/SetBaseCurrency.md)
31
+
32
+ ### Models
33
+
34
+ - Currency
35
+
36
+ ### Invariants
37
+
38
+ - ISO 4217 code must be unique across all currencies
39
+ - Only one currency can be designated as base currency
40
+ - Base currency cannot be deactivated
41
+
42
+ ### Relationships
43
+
44
+ - **Referenced By Exchange Rates**: Currency is referenced as source or target in ExchangeRate records
45
+ - **Referenced By Transactions**: Currency is used in sales, purchase, and accounting transactions
@@ -0,0 +1,33 @@
1
+ # ExchangeRate
2
+
3
+ ## Description
4
+
5
+ ExchangeRate maintains the conversion ratio between a currency pair with an effective date. Each rate record specifies the source currency, target currency, rate value, and the date from which it applies. The system uses these rates to convert monetary amounts for transactions, reporting, and consolidation.
6
+
7
+ Rates are date-based to support historical accuracy - a transaction from last month uses last month's rate, not today's rate.
8
+
9
+ ## Domain Model Definitions
10
+
11
+ ### Model type
12
+
13
+ AppendOnly
14
+
15
+ ### Command Definitions
16
+
17
+ - [createExchangeRate](../commands/CreateExchangeRate.md)
18
+ - [convertAmount](../commands/ConvertAmount.md)
19
+
20
+ ### Models
21
+
22
+ - ExchangeRate
23
+
24
+ ### Invariants
25
+
26
+ - Rate must be a positive decimal value
27
+ - Source and target currencies must be different
28
+ - Effective date is required for all rate records
29
+
30
+ ### Relationships
31
+
32
+ - **Belongs To Source Currency**: Each rate has exactly one source currency
33
+ - **Belongs To Target Currency**: Each rate has exactly one target currency
@@ -0,0 +1,46 @@
1
+ # Unit
2
+
3
+ ## Description
4
+
5
+ Unit defines an individual unit of measure with its symbol, display name, and conversion factor relative to its category's reference unit. Units support configurable rounding precision for business operations.
6
+
7
+ Examples: kg (kilogram), lb (pound), ea (each), dz (dozen).
8
+
9
+ ## Domain Model Definitions
10
+
11
+ ### Model type
12
+
13
+ Stateful
14
+
15
+ #### State Transitions
16
+
17
+ ```mermaid
18
+ stateDiagram-v2
19
+ [*] --> Active: create
20
+ Active --> Inactive: deactivate
21
+ Inactive --> Active: activate
22
+ note right of Active: Reference unit cannot be deactivated
23
+ ```
24
+
25
+ ### Command Definitions
26
+
27
+ - [createUnit](../commands/CreateUnit.md)
28
+ - [activateUnit](../commands/ActivateUnit.md)
29
+ - [deactivateUnit](../commands/DeactivateUnit.md)
30
+ - [convertQuantity](../commands/ConvertQuantity.md)
31
+
32
+ ### Models
33
+
34
+ - Unit
35
+
36
+ ### Invariants
37
+
38
+ - Conversion factor must be a positive value
39
+ - Reference unit has conversion factor of 1.0
40
+ - Symbol must be unique within the category
41
+ - Reference unit cannot be deactivated
42
+
43
+ ### Relationships
44
+
45
+ - **Belongs To Category**: Each unit belongs to exactly one UoMCategory
46
+ - **May Be Reference Unit**: A unit may be designated as its category's reference unit
@@ -0,0 +1,44 @@
1
+ # UoMCategory
2
+
3
+ ## Description
4
+
5
+ UoMCategory organizes units of measure into logical groupings where conversions are meaningful. Each category has a designated reference unit that serves as the base for all conversion calculations within that category. Units can only be converted to other units within the same category.
6
+
7
+ Examples: Unit, Weight, Volume, Length, Time.
8
+
9
+ ## Domain Model Definitions
10
+
11
+ ### Model type
12
+
13
+ Stateful
14
+
15
+ #### State Transitions
16
+
17
+ ```mermaid
18
+ stateDiagram-v2
19
+ [*] --> Active: create
20
+ Active --> Inactive: deactivate
21
+ Inactive --> Active: activate
22
+ ```
23
+
24
+ ### Command Definitions
25
+
26
+ - [createCategory](../commands/CreateCategory.md)
27
+ - [activateCategory](../commands/ActivateCategory.md)
28
+ - [deactivateCategory](../commands/DeactivateCategory.md)
29
+ - [setReferenceUnit](../commands/SetReferenceUnit.md)
30
+
31
+ ### Models
32
+
33
+ - UoMCategory
34
+
35
+ ### Invariants
36
+
37
+ - Category name must be unique
38
+ - Reference unit must belong to this category
39
+ - Category cannot be deactivated while it has active units
40
+
41
+ ### Relationships
42
+
43
+ - **Has Many Units**: A category contains multiple units (one-to-many)
44
+ - **Has One Reference Unit**: Each category designates one unit as the reference unit for conversions
@@ -0,0 +1,95 @@
1
+ import {
2
+ type ColumnType,
3
+ Kysely,
4
+ type KyselyConfig,
5
+ type Transaction as KyselyTransaction,
6
+ type Insertable as KyselyInsertable,
7
+ type Selectable as KyselySelectable,
8
+ type Updateable as KyselyUpdateable,
9
+ } from "kysely";
10
+ import { TailordbDialect } from "@tailor-platform/function-kysely-tailordb";
11
+
12
+ type Timestamp = ColumnType<Date, Date | string, Date | string>;
13
+ type Generated<T> =
14
+ T extends ColumnType<infer S, infer I, infer U>
15
+ ? ColumnType<S, I | undefined, U>
16
+ : ColumnType<T, T | undefined, T>;
17
+
18
+ export interface Namespace {
19
+ "main-db": {
20
+ Currency: {
21
+ id: Generated<string>;
22
+ code: string;
23
+ name: string;
24
+ symbol: string;
25
+ decimalPlaces: number;
26
+ isBaseCurrency: boolean;
27
+ isActive: boolean;
28
+ createdAt: Generated<Timestamp>;
29
+ updatedAt: Timestamp | null;
30
+ };
31
+
32
+ ExchangeRate: {
33
+ id: Generated<string>;
34
+ sourceCurrencyId: string;
35
+ targetCurrencyId: string;
36
+ rate: number;
37
+ effectiveDate: Timestamp;
38
+ createdAt: Generated<Timestamp>;
39
+ updatedAt: Timestamp | null;
40
+ };
41
+
42
+ Unit: {
43
+ id: Generated<string>;
44
+ name: string;
45
+ symbol: string;
46
+ categoryId: string;
47
+ conversionFactor: number;
48
+ roundingPrecision: number;
49
+ isActive: boolean;
50
+ createdAt: Generated<Timestamp>;
51
+ updatedAt: Timestamp | null;
52
+ };
53
+
54
+ UoMCategory: {
55
+ id: Generated<string>;
56
+ name: string;
57
+ description: string | null;
58
+ referenceUnitId: string | null;
59
+ isActive: boolean;
60
+ createdAt: Generated<Timestamp>;
61
+ updatedAt: Timestamp | null;
62
+ };
63
+ };
64
+ }
65
+
66
+ export function getDB<const N extends keyof Namespace>(
67
+ namespace: N,
68
+ kyselyConfig?: Omit<KyselyConfig, "dialect">,
69
+ ): Kysely<Namespace[N]> {
70
+ const client = new tailordb.Client({ namespace });
71
+ return new Kysely<Namespace[N]>({
72
+ dialect: new TailordbDialect(client),
73
+ ...kyselyConfig,
74
+ });
75
+ }
76
+
77
+ export type DB<N extends keyof Namespace = keyof Namespace> = ReturnType<typeof getDB<N>>;
78
+
79
+ export type Transaction<K extends keyof Namespace | DB = keyof Namespace> =
80
+ K extends DB<infer N>
81
+ ? KyselyTransaction<Namespace[N]>
82
+ : K extends keyof Namespace
83
+ ? KyselyTransaction<Namespace[K]>
84
+ : never;
85
+
86
+ type TableName = {
87
+ [N in keyof Namespace]: keyof Namespace[N];
88
+ }[keyof Namespace];
89
+ export type Table<T extends TableName> = {
90
+ [N in keyof Namespace]: T extends keyof Namespace[N] ? Namespace[N][T] : never;
91
+ }[keyof Namespace];
92
+
93
+ export type Insertable<T extends keyof Namespace[keyof Namespace]> = KyselyInsertable<Table<T>>;
94
+ export type Selectable<T extends keyof Namespace[keyof Namespace]> = KyselySelectable<Table<T>>;
95
+ export type Updateable<T extends keyof Namespace[keyof Namespace]> = KyselyUpdateable<Table<T>>;
@@ -0,0 +1,40 @@
1
+ export { defineModule } from "./module";
2
+ export { permissions, own, all } from "./permissions";
3
+
4
+ // errors
5
+ export {
6
+ UoMCategoryNotFoundError,
7
+ UnitNotFoundError,
8
+ IncompatibleUnitsError,
9
+ InactiveUnitError,
10
+ CurrencyNotFoundError,
11
+ InactiveCurrencyError,
12
+ ExchangeRateNotFoundError,
13
+ CannotDeactivateReferenceUnitError,
14
+ CategoryNotActiveError,
15
+ DuplicateUnitSymbolError,
16
+ InvalidConversionFactorError,
17
+ InvalidRoundingPrecisionError,
18
+ DuplicateCategoryNameError,
19
+ CategoryHasActiveUnitsError,
20
+ UnitNotInCategoryError,
21
+ InvalidISOCodeError,
22
+ DuplicateCurrencyCodeError,
23
+ InvalidDecimalPlacesError,
24
+ CannotDeactivateBaseCurrencyError,
25
+ CannotSetInactiveAsBaseCurrencyError,
26
+ SameCurrencyPairError,
27
+ InvalidExchangeRateError,
28
+ } from "./lib/errors";
29
+
30
+ // input types
31
+ export { type ConvertQuantityInput } from "./command/convertQuantity";
32
+ export { type ActivateCategoryInput } from "./command/activateCategory";
33
+ export { type DeactivateCategoryInput } from "./command/deactivateCategory";
34
+ export { type SetReferenceUnitInput } from "./command/setReferenceUnit";
35
+ export { type ActivateUnitInput } from "./command/activateUnit";
36
+ export { type DeactivateUnitInput } from "./command/deactivateUnit";
37
+ export { type ConvertAmountInput } from "./command/convertAmount";
38
+ export { type ActivateCurrencyInput } from "./command/activateCurrency";
39
+ export { type DeactivateCurrencyInput } from "./command/deactivateCurrency";
40
+ export { type SetBaseCurrencyInput } from "./command/setBaseCurrency";
@@ -0,0 +1,138 @@
1
+ import { createDomainError } from "../../shared/internal";
2
+
3
+ export const UoMCategoryNotFoundError = createDomainError(
4
+ "UoMCategoryNotFoundError",
5
+ "UOM_CATEGORY_NOT_FOUND",
6
+ (identifier: string) => `UoM category not found: ${identifier}`,
7
+ );
8
+
9
+ export const UnitNotFoundError = createDomainError(
10
+ "UnitNotFoundError",
11
+ "UNIT_NOT_FOUND",
12
+ (symbol: string) => `Unit not found: ${symbol}`,
13
+ );
14
+
15
+ export const IncompatibleUnitsError = createDomainError(
16
+ "IncompatibleUnitsError",
17
+ "INCOMPATIBLE_UNITS",
18
+ (sourceSymbol: string, targetSymbol: string) =>
19
+ `Cannot convert between incompatible units: ${sourceSymbol} and ${targetSymbol} belong to different categories`,
20
+ );
21
+
22
+ export const InactiveUnitError = createDomainError(
23
+ "InactiveUnitError",
24
+ "INACTIVE_UNIT",
25
+ (symbol: string) => `Unit is inactive: ${symbol}`,
26
+ );
27
+
28
+ export const CurrencyNotFoundError = createDomainError(
29
+ "CurrencyNotFoundError",
30
+ "CURRENCY_NOT_FOUND",
31
+ (code: string) => `Currency not found: ${code}`,
32
+ );
33
+
34
+ export const InactiveCurrencyError = createDomainError(
35
+ "InactiveCurrencyError",
36
+ "INACTIVE_CURRENCY",
37
+ (code: string) => `Currency is inactive: ${code}`,
38
+ );
39
+
40
+ export const ExchangeRateNotFoundError = createDomainError(
41
+ "ExchangeRateNotFoundError",
42
+ "EXCHANGE_RATE_NOT_FOUND",
43
+ (sourceCode: string, targetCode: string, date: string) =>
44
+ `No exchange rate found for ${sourceCode} to ${targetCode} on or before ${date}`,
45
+ );
46
+
47
+ export const CannotDeactivateReferenceUnitError = createDomainError(
48
+ "CannotDeactivateReferenceUnitError",
49
+ "CANNOT_DEACTIVATE_REFERENCE_UNIT",
50
+ (unitId: string) => `Cannot deactivate reference unit: ${unitId}. Change reference unit first.`,
51
+ );
52
+
53
+ export const CategoryNotActiveError = createDomainError(
54
+ "CategoryNotActiveError",
55
+ "CATEGORY_NOT_ACTIVE",
56
+ (categoryId: string) => `Category is not active: ${categoryId}`,
57
+ );
58
+
59
+ export const DuplicateUnitSymbolError = createDomainError(
60
+ "DuplicateUnitSymbolError",
61
+ "DUPLICATE_UNIT_SYMBOL",
62
+ (symbol: string, categoryId: string) =>
63
+ `Unit with symbol "${symbol}" already exists in category ${categoryId}`,
64
+ );
65
+
66
+ export const InvalidConversionFactorError = createDomainError(
67
+ "InvalidConversionFactorError",
68
+ "INVALID_CONVERSION_FACTOR",
69
+ (factor: number) => `Conversion factor must be positive: ${factor}`,
70
+ );
71
+
72
+ export const InvalidRoundingPrecisionError = createDomainError(
73
+ "InvalidRoundingPrecisionError",
74
+ "INVALID_ROUNDING_PRECISION",
75
+ (precision: number) => `Rounding precision must be non-negative: ${precision}`,
76
+ );
77
+
78
+ export const DuplicateCategoryNameError = createDomainError(
79
+ "DuplicateCategoryNameError",
80
+ "DUPLICATE_CATEGORY_NAME",
81
+ (name: string) => `Category with name "${name}" already exists`,
82
+ );
83
+
84
+ export const CategoryHasActiveUnitsError = createDomainError(
85
+ "CategoryHasActiveUnitsError",
86
+ "CATEGORY_HAS_ACTIVE_UNITS",
87
+ (categoryId: string) => `Cannot deactivate category ${categoryId}: has active units`,
88
+ );
89
+
90
+ export const UnitNotInCategoryError = createDomainError(
91
+ "UnitNotInCategoryError",
92
+ "UNIT_NOT_IN_CATEGORY",
93
+ (unitId: string, categoryId: string) =>
94
+ `Unit ${unitId} does not belong to category ${categoryId}`,
95
+ );
96
+
97
+ export const InvalidISOCodeError = createDomainError(
98
+ "InvalidISOCodeError",
99
+ "INVALID_ISO_CODE",
100
+ (code: string) => `Invalid ISO 4217 code: "${code}". Must be exactly 3 uppercase letters.`,
101
+ );
102
+
103
+ export const DuplicateCurrencyCodeError = createDomainError(
104
+ "DuplicateCurrencyCodeError",
105
+ "DUPLICATE_CURRENCY_CODE",
106
+ (code: string) => `Currency with code "${code}" already exists`,
107
+ );
108
+
109
+ export const InvalidDecimalPlacesError = createDomainError(
110
+ "InvalidDecimalPlacesError",
111
+ "INVALID_DECIMAL_PLACES",
112
+ (decimalPlaces: number) => `Decimal places must be between 0 and 4: ${decimalPlaces}`,
113
+ );
114
+
115
+ export const CannotDeactivateBaseCurrencyError = createDomainError(
116
+ "CannotDeactivateBaseCurrencyError",
117
+ "CANNOT_DEACTIVATE_BASE_CURRENCY",
118
+ (currencyId: string) =>
119
+ `Cannot deactivate base currency: ${currencyId}. Change base currency first.`,
120
+ );
121
+
122
+ export const CannotSetInactiveAsBaseCurrencyError = createDomainError(
123
+ "CannotSetInactiveAsBaseCurrencyError",
124
+ "CANNOT_SET_INACTIVE_AS_BASE_CURRENCY",
125
+ (currencyId: string) => `Cannot set inactive currency as base: ${currencyId}. Activate it first.`,
126
+ );
127
+
128
+ export const SameCurrencyPairError = createDomainError(
129
+ "SameCurrencyPairError",
130
+ "SAME_CURRENCY_PAIR",
131
+ (currencyId: string) => `Source and target currency cannot be the same: ${currencyId}`,
132
+ );
133
+
134
+ export const InvalidExchangeRateError = createDomainError(
135
+ "InvalidExchangeRateError",
136
+ "INVALID_EXCHANGE_RATE",
137
+ (rate: number) => `Exchange rate must be positive: ${rate}`,
138
+ );
@@ -0,0 +1,20 @@
1
+ import type { InferSchema, Selectable, Insertable, Updateable } from "../../shared/internal";
2
+ import type { DB } from "../generated/kysely-tailordb";
3
+
4
+ export type Schema = InferSchema<DB>;
5
+
6
+ export type UoMCategory<T extends { UoMCategory: object }> = Selectable<T["UoMCategory"]>;
7
+ export type UoMCategoryCreate<T extends { UoMCategory: object }> = Insertable<T["UoMCategory"]>;
8
+ export type UoMCategoryUpdate<T extends { UoMCategory: object }> = Updateable<T["UoMCategory"]>;
9
+
10
+ export type Unit<T extends { Unit: object }> = Selectable<T["Unit"]>;
11
+ export type UnitCreate<T extends { Unit: object }> = Insertable<T["Unit"]>;
12
+ export type UnitUpdate<T extends { Unit: object }> = Updateable<T["Unit"]>;
13
+
14
+ export type Currency<T extends { Currency: object }> = Selectable<T["Currency"]>;
15
+ export type CurrencyCreate<T extends { Currency: object }> = Insertable<T["Currency"]>;
16
+ export type CurrencyUpdate<T extends { Currency: object }> = Updateable<T["Currency"]>;
17
+
18
+ export type ExchangeRate<T extends { ExchangeRate: object }> = Selectable<T["ExchangeRate"]>;
19
+ export type ExchangeRateCreate<T extends { ExchangeRate: object }> = Insertable<T["ExchangeRate"]>;
20
+ export type ExchangeRateUpdate<T extends { ExchangeRate: object }> = Updateable<T["ExchangeRate"]>;
@@ -0,0 +1,66 @@
1
+ import { type TailorAnyDBField } from "@tailor-platform/sdk";
2
+ import { type EmptyFields, type FieldsToInsertable } from "../shared/internal";
3
+ import { makeCreateCategory } from "./command/createCategory";
4
+ import { makeCreateCurrency } from "./command/createCurrency";
5
+ import { makeCreateUnit } from "./command/createUnit";
6
+ import { makeCreateExchangeRate } from "./command/createExchangeRate";
7
+ import { activateCategory } from "./command/activateCategory";
8
+ import { deactivateCategory } from "./command/deactivateCategory";
9
+ import { activateUnit } from "./command/activateUnit";
10
+ import { deactivateUnit } from "./command/deactivateUnit";
11
+ import { setReferenceUnit } from "./command/setReferenceUnit";
12
+ import { convertQuantity } from "./command/convertQuantity";
13
+ import { activateCurrency } from "./command/activateCurrency";
14
+ import { deactivateCurrency } from "./command/deactivateCurrency";
15
+ import { setBaseCurrency } from "./command/setBaseCurrency";
16
+ import { convertAmount } from "./command/convertAmount";
17
+ import { createUoMCategoryType, CreateUoMCategoryTypeParams } from "./db/uomCategory";
18
+ import { createUnitType, CreateUnitTypeParams } from "./db/unit";
19
+ import { createCurrencyType, CreateCurrencyTypeParams } from "./db/currency";
20
+ import { createExchangeRateType, CreateExchangeRateTypeParams } from "./db/exchangeRate";
21
+
22
+ export interface DefineModuleParams<
23
+ CatF extends Record<string, TailorAnyDBField>,
24
+ UnitF extends Record<string, TailorAnyDBField>,
25
+ CurF extends Record<string, TailorAnyDBField>,
26
+ ERF extends Record<string, TailorAnyDBField>,
27
+ > {
28
+ uomCategory?: CreateUoMCategoryTypeParams<CatF>;
29
+ unit?: CreateUnitTypeParams<UnitF>;
30
+ currency?: CreateCurrencyTypeParams<CurF>;
31
+ exchangeRate?: CreateExchangeRateTypeParams<ERF>;
32
+ }
33
+
34
+ export const defineModule = <
35
+ const CatF extends Record<string, TailorAnyDBField> = EmptyFields,
36
+ const UnitF extends Record<string, TailorAnyDBField> = EmptyFields,
37
+ const CurF extends Record<string, TailorAnyDBField> = EmptyFields,
38
+ const ERF extends Record<string, TailorAnyDBField> = EmptyFields,
39
+ >(
40
+ params: DefineModuleParams<CatF, UnitF, CurF, ERF>,
41
+ ) => {
42
+ const uomCategory = createUoMCategoryType(params.uomCategory ?? {});
43
+ const unit = createUnitType(params.unit ?? {});
44
+ const currency = createCurrencyType(params.currency ?? {});
45
+ const exchangeRate = createExchangeRateType(params.exchangeRate ?? {});
46
+
47
+ return {
48
+ db: { uomCategory, unit, currency, exchangeRate },
49
+ commands: {
50
+ createCategory: makeCreateCategory<FieldsToInsertable<CatF>, FieldsToInsertable<UnitF>>(),
51
+ createCurrency: makeCreateCurrency<FieldsToInsertable<CurF>>(),
52
+ createUnit: makeCreateUnit<FieldsToInsertable<UnitF>>(),
53
+ createExchangeRate: makeCreateExchangeRate<FieldsToInsertable<ERF>>(),
54
+ activateCategory,
55
+ deactivateCategory,
56
+ activateUnit,
57
+ deactivateUnit,
58
+ setReferenceUnit,
59
+ convertQuantity,
60
+ activateCurrency,
61
+ deactivateCurrency,
62
+ setBaseCurrency,
63
+ convertAmount,
64
+ },
65
+ };
66
+ };
@@ -0,0 +1,18 @@
1
+ import { definePermissions } from "../shared/internal";
2
+
3
+ export const { permissions, own, all } = definePermissions("primitives", [
4
+ "convertQuantity",
5
+ "createCategory",
6
+ "activateCategory",
7
+ "deactivateCategory",
8
+ "setReferenceUnit",
9
+ "createUnit",
10
+ "activateUnit",
11
+ "deactivateUnit",
12
+ "convertAmount",
13
+ "createCurrency",
14
+ "activateCurrency",
15
+ "deactivateCurrency",
16
+ "setBaseCurrency",
17
+ "createExchangeRate",
18
+ ] as const);
@@ -0,0 +1,11 @@
1
+ import { defineConfig, defineGenerators } from "@tailor-platform/sdk";
2
+
3
+ export default defineConfig({
4
+ name: "primitives",
5
+ db: { "main-db": { files: [`./src/db/*.ts`] } },
6
+ });
7
+
8
+ export const generators = defineGenerators(
9
+ ["@tailor-platform/kysely-type", { distPath: `./src/generated/kysely-tailordb.ts` }],
10
+ ["@tailor-platform/enum-constants", { distPath: "./src/generated/enums.ts" }],
11
+ );