@tailor-platform/erp-kit 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +80 -12
- package/dist/cli.js +1070 -450
- package/package.json +11 -8
- package/schemas/app-compose/business-flow.yml +3 -0
- package/schemas/app-compose/story.yml +1 -1
- package/schemas/module/model.yml +5 -0
- package/skills/{app-compose-1-requirement-analysis → erp-kit-app-1-requirements}/SKILL.md +8 -14
- package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/SKILL.md +6 -13
- package/skills/{app-compose-3-doc-review → erp-kit-app-3-doc-review}/SKILL.md +2 -6
- package/skills/{app-compose-6-implementation-spec → erp-kit-app-4-impl-spec}/SKILL.md +11 -22
- package/skills/erp-kit-app-5-implementation/SKILL.md +149 -0
- package/skills/erp-kit-app-5-implementation/references/backend.md +232 -0
- package/skills/erp-kit-app-5-implementation/references/frontend.md +242 -0
- package/skills/{mock-scenario → erp-kit-mock-scenario}/SKILL.md +1 -1
- package/skills/{1-module-docs → erp-kit-module-1-docs}/SKILL.md +2 -2
- package/skills/{2-module-feature-breakdown → erp-kit-module-2-feature-breakdown}/SKILL.md +13 -9
- package/skills/erp-kit-module-2-feature-breakdown/references/naming.md +59 -0
- package/skills/{3-module-doc-review → erp-kit-module-3-doc-review}/SKILL.md +83 -25
- package/skills/erp-kit-module-4-tdd/SKILL.md +94 -0
- package/skills/erp-kit-module-4-tdd/references/cross-module-dependency.md +133 -0
- package/skills/{4-module-tdd-implementation → erp-kit-module-4-tdd}/references/db-relations.md +5 -1
- package/skills/{4-module-tdd-implementation → erp-kit-module-4-tdd}/references/exports.md +1 -1
- package/skills/erp-kit-module-4-tdd/references/generated-code.md +32 -0
- package/skills/{5-module-implementation-review → erp-kit-module-5-impl-review}/SKILL.md +46 -44
- package/skills/erp-kit-module-5-impl-review/references/commands.md +62 -0
- package/skills/erp-kit-module-5-impl-review/references/errors.md +10 -0
- package/skills/{5-module-implementation-review → erp-kit-module-5-impl-review}/references/testing.md +1 -1
- package/skills/erp-kit-module-shared/SKILL.md +16 -0
- package/skills/erp-kit-module-shared/references/commands.md +203 -0
- package/skills/erp-kit-module-shared/references/errors.md +35 -0
- package/skills/erp-kit-module-shared/references/queries.md +168 -0
- package/skills/erp-kit-module-shared/references/structure.md +36 -0
- package/skills/{3-module-doc-review → erp-kit-module-shared}/references/testing.md +4 -3
- package/skills/erp-kit-update/SKILL.md +64 -0
- package/src/cli.doc.test.ts +65 -0
- package/src/cli.ts +3 -35
- package/src/commands/app/index.ts +3 -3
- package/src/commands/check.test.ts +1 -1
- package/src/commands/check.ts +2 -2
- package/src/commands/index.ts +73 -0
- package/src/commands/init.test.ts +22 -5
- package/src/commands/init.ts +25 -16
- package/src/commands/license.ts +193 -0
- package/src/commands/mock/index.ts +2 -2
- package/src/commands/mock/start.ts +1 -1
- package/src/commands/mock/validate.test.ts +1 -1
- package/src/commands/module/generate.ts +35 -0
- package/src/commands/module/index.ts +6 -4
- package/src/commands/module/list.test.ts +7 -12
- package/src/commands/module/list.ts +1 -1
- package/src/commands/scaffold-templates.ts +65 -0
- package/src/commands/scaffold.test.ts +92 -2
- package/src/commands/scaffold.ts +22 -2
- package/src/commands/sync-check.test.ts +60 -1
- package/src/commands/sync-check.ts +35 -2
- package/src/generator/generate-code.test.ts +200 -0
- package/src/generator/generate-code.ts +260 -0
- package/src/generator/parse-command-doc.test.ts +159 -0
- package/src/generator/parse-command-doc.ts +116 -0
- package/src/integration.test.ts +2 -2
- package/src/module.ts +44 -6
- package/src/modules/item-management/README.md +38 -0
- package/src/modules/item-management/command/activateItem.generated.ts +6 -0
- package/src/modules/item-management/command/activateItem.test.ts +76 -0
- package/src/modules/item-management/command/activateItem.ts +42 -0
- package/src/modules/item-management/command/assignItemToTaxonomy.generated.ts +6 -0
- package/src/modules/item-management/command/assignItemToTaxonomy.test.ts +88 -0
- package/src/modules/item-management/command/assignItemToTaxonomy.ts +63 -0
- package/src/modules/item-management/command/createItem.generated.ts +6 -0
- package/src/modules/item-management/command/createItem.test.ts +152 -0
- package/src/modules/item-management/command/createItem.ts +72 -0
- package/src/modules/item-management/command/createTaxonomyNode.generated.ts +6 -0
- package/src/modules/item-management/command/createTaxonomyNode.test.ts +126 -0
- package/src/modules/item-management/command/createTaxonomyNode.ts +70 -0
- package/src/modules/item-management/command/deactivateItem.generated.ts +6 -0
- package/src/modules/item-management/command/deactivateItem.test.ts +76 -0
- package/src/modules/item-management/command/deactivateItem.ts +42 -0
- package/src/modules/item-management/command/deleteItem.generated.ts +6 -0
- package/src/modules/item-management/command/deleteItem.test.ts +61 -0
- package/src/modules/item-management/command/deleteItem.ts +38 -0
- package/src/modules/item-management/command/deleteTaxonomyNode.generated.ts +6 -0
- package/src/modules/item-management/command/deleteTaxonomyNode.test.ts +73 -0
- package/src/modules/item-management/command/deleteTaxonomyNode.ts +50 -0
- package/src/modules/item-management/command/moveTaxonomyNode.generated.ts +6 -0
- package/src/modules/item-management/command/moveTaxonomyNode.test.ts +136 -0
- package/src/modules/item-management/command/moveTaxonomyNode.ts +85 -0
- package/src/modules/item-management/command/reactivateItem.generated.ts +6 -0
- package/src/modules/item-management/command/reactivateItem.test.ts +76 -0
- package/src/modules/item-management/command/reactivateItem.ts +42 -0
- package/src/modules/item-management/command/removeItemFromTaxonomy.generated.ts +6 -0
- package/src/modules/item-management/command/removeItemFromTaxonomy.test.ts +43 -0
- package/src/modules/item-management/command/removeItemFromTaxonomy.ts +30 -0
- package/src/modules/item-management/command/updateItem.generated.ts +6 -0
- package/src/modules/item-management/command/updateItem.test.ts +178 -0
- package/src/modules/item-management/command/updateItem.ts +103 -0
- package/src/modules/item-management/command/updateTaxonomyNode.generated.ts +6 -0
- package/src/modules/item-management/command/updateTaxonomyNode.test.ts +88 -0
- package/src/modules/item-management/command/updateTaxonomyNode.ts +62 -0
- package/src/modules/item-management/db/item.ts +47 -0
- package/src/modules/item-management/db/itemTaxonomyAssignment.ts +49 -0
- package/src/modules/item-management/db/taxonomyNode.ts +34 -0
- package/src/modules/item-management/docs/commands/ActivateItem.md +32 -0
- package/src/modules/item-management/docs/commands/AssignItemToTaxonomy.md +38 -0
- package/src/modules/item-management/docs/commands/CreateItem.md +44 -0
- package/src/modules/item-management/docs/commands/CreateTaxonomyNode.md +44 -0
- package/src/modules/item-management/docs/commands/DeactivateItem.md +34 -0
- package/src/modules/item-management/docs/commands/DeleteItem.md +35 -0
- package/src/modules/item-management/docs/commands/DeleteTaxonomyNode.md +39 -0
- package/src/modules/item-management/docs/commands/MoveTaxonomyNode.md +45 -0
- package/src/modules/item-management/docs/commands/ReactivateItem.md +34 -0
- package/src/modules/item-management/docs/commands/RemoveItemFromTaxonomy.md +30 -0
- package/src/modules/item-management/docs/commands/UpdateItem.md +55 -0
- package/src/modules/item-management/docs/commands/UpdateTaxonomyNode.md +36 -0
- package/src/modules/item-management/docs/features/item-lifecycle.md +60 -0
- package/src/modules/item-management/docs/features/item-taxonomy.md +65 -0
- package/src/modules/item-management/docs/models/ItemTaxonomyAssignment.md +36 -0
- package/src/modules/item-management/docs/models/TaxonomyNode.md +47 -0
- package/src/modules/item-management/docs/models/item.md +59 -0
- package/src/modules/item-management/docs/queries/CalculateNodeDepth.md +36 -0
- package/src/modules/item-management/docs/queries/CalculateSubtreeDepth.md +40 -0
- package/src/modules/item-management/docs/queries/DetectCircularReference.md +41 -0
- package/src/modules/item-management/docs/queries/GetItem.md +38 -0
- package/src/modules/item-management/docs/queries/GetItemTaxonomyAssignment.md +29 -0
- package/src/modules/item-management/docs/queries/GetTaxonomyNode.md +35 -0
- package/src/modules/item-management/docs/queries/GetTaxonomyNodeAssignments.md +29 -0
- package/src/modules/item-management/docs/queries/GetTaxonomyNodeChildren.md +29 -0
- package/src/modules/item-management/generated/enums.ts +9 -0
- package/src/modules/item-management/generated/kysely-tailordb.ts +62 -0
- package/src/modules/item-management/index.ts +53 -0
- package/src/modules/item-management/lib/_db_deps.ts +13 -0
- package/src/modules/item-management/lib/errors.generated.ts +117 -0
- package/src/modules/item-management/lib/permissions.generated.ts +17 -0
- package/src/modules/item-management/lib/types.ts +19 -0
- package/src/modules/item-management/module.ts +97 -0
- package/src/modules/item-management/query/calculateNodeDepth.generated.ts +5 -0
- package/src/modules/item-management/query/calculateNodeDepth.test.ts +56 -0
- package/src/modules/item-management/query/calculateNodeDepth.ts +28 -0
- package/src/modules/item-management/query/calculateSubtreeDepth.generated.ts +5 -0
- package/src/modules/item-management/query/calculateSubtreeDepth.test.ts +75 -0
- package/src/modules/item-management/query/calculateSubtreeDepth.ts +29 -0
- package/src/modules/item-management/query/detectCircularReference.generated.ts +5 -0
- package/src/modules/item-management/query/detectCircularReference.test.ts +61 -0
- package/src/modules/item-management/query/detectCircularReference.ts +32 -0
- package/src/modules/item-management/query/getItem.generated.ts +5 -0
- package/src/modules/item-management/query/getItem.test.ts +67 -0
- package/src/modules/item-management/query/getItem.ts +20 -0
- package/src/modules/item-management/query/getItemTaxonomyAssignment.generated.ts +5 -0
- package/src/modules/item-management/query/getItemTaxonomyAssignment.test.ts +25 -0
- package/src/modules/item-management/query/getItemTaxonomyAssignment.ts +18 -0
- package/src/modules/item-management/query/getTaxonomyNode.generated.ts +5 -0
- package/src/modules/item-management/query/getTaxonomyNode.test.ts +47 -0
- package/src/modules/item-management/query/getTaxonomyNode.ts +18 -0
- package/src/modules/item-management/query/getTaxonomyNodeAssignments.generated.ts +5 -0
- package/src/modules/item-management/query/getTaxonomyNodeAssignments.test.ts +25 -0
- package/src/modules/item-management/query/getTaxonomyNodeAssignments.ts +16 -0
- package/src/modules/item-management/query/getTaxonomyNodeChildren.generated.ts +5 -0
- package/src/modules/item-management/query/getTaxonomyNodeChildren.test.ts +34 -0
- package/src/modules/item-management/query/getTaxonomyNodeChildren.ts +16 -0
- package/src/modules/item-management/tailor.config.ts +11 -0
- package/src/modules/item-management/testing/fixtures.ts +81 -0
- package/src/modules/primitives/command/activateCategory.generated.ts +6 -0
- package/src/modules/primitives/command/activateCategory.test.ts +11 -29
- package/src/modules/primitives/command/activateCategory.ts +27 -34
- package/src/modules/primitives/command/activateCurrency.generated.ts +6 -0
- package/src/modules/primitives/command/activateCurrency.test.ts +11 -29
- package/src/modules/primitives/command/activateCurrency.ts +27 -34
- package/src/modules/primitives/command/activateUnit.generated.ts +6 -0
- package/src/modules/primitives/command/activateUnit.test.ts +11 -15
- package/src/modules/primitives/command/activateUnit.ts +27 -34
- package/src/modules/primitives/command/createCategory.generated.ts +6 -0
- package/src/modules/primitives/command/createCategory.test.ts +27 -39
- package/src/modules/primitives/command/createCategory.ts +53 -62
- package/src/modules/primitives/command/createCurrency.generated.ts +6 -0
- package/src/modules/primitives/command/createCurrency.test.ts +78 -71
- package/src/modules/primitives/command/createCurrency.ts +43 -48
- package/src/modules/primitives/command/createExchangeRate.generated.ts +6 -0
- package/src/modules/primitives/command/createExchangeRate.test.ts +101 -100
- package/src/modules/primitives/command/createExchangeRate.ts +50 -59
- package/src/modules/primitives/command/createUnit.generated.ts +6 -0
- package/src/modules/primitives/command/createUnit.test.ts +92 -95
- package/src/modules/primitives/command/createUnit.ts +54 -57
- package/src/modules/primitives/command/deactivateCategory.generated.ts +6 -0
- package/src/modules/primitives/command/deactivateCategory.test.ts +27 -28
- package/src/modules/primitives/command/deactivateCategory.ts +43 -50
- package/src/modules/primitives/command/deactivateCurrency.generated.ts +6 -0
- package/src/modules/primitives/command/deactivateCurrency.test.ts +23 -38
- package/src/modules/primitives/command/deactivateCurrency.ts +31 -38
- package/src/modules/primitives/command/deactivateUnit.generated.ts +6 -0
- package/src/modules/primitives/command/deactivateUnit.test.ts +27 -23
- package/src/modules/primitives/command/deactivateUnit.ts +39 -49
- package/src/modules/primitives/command/setBaseCurrency.generated.ts +6 -0
- package/src/modules/primitives/command/setBaseCurrency.test.ts +40 -33
- package/src/modules/primitives/command/setBaseCurrency.ts +43 -50
- package/src/modules/primitives/command/setReferenceUnit.generated.ts +6 -0
- package/src/modules/primitives/command/setReferenceUnit.test.ts +39 -35
- package/src/modules/primitives/command/setReferenceUnit.ts +46 -59
- package/src/modules/primitives/db/unit.ts +13 -3
- package/src/modules/primitives/docs/commands/ActivateCategory.md +1 -2
- package/src/modules/primitives/docs/commands/ActivateCurrency.md +1 -2
- package/src/modules/primitives/docs/commands/ActivateUnit.md +1 -2
- package/src/modules/primitives/docs/commands/CreateCategory.md +1 -4
- package/src/modules/primitives/docs/commands/CreateCurrency.md +3 -4
- package/src/modules/primitives/docs/commands/CreateExchangeRate.md +4 -5
- package/src/modules/primitives/docs/commands/CreateUnit.md +5 -5
- package/src/modules/primitives/docs/commands/DeactivateCategory.md +2 -3
- package/src/modules/primitives/docs/commands/DeactivateCurrency.md +2 -3
- package/src/modules/primitives/docs/commands/DeactivateUnit.md +2 -3
- package/src/modules/primitives/docs/commands/SetBaseCurrency.md +2 -3
- package/src/modules/primitives/docs/commands/SetReferenceUnit.md +2 -3
- package/src/modules/primitives/docs/queries/ConvertAmount.md +3 -5
- package/src/modules/primitives/docs/queries/ConvertQuantity.md +3 -5
- package/src/modules/primitives/docs/queries/GetBaseCurrency.md +32 -0
- package/src/modules/primitives/docs/queries/GetCurrency.md +36 -0
- package/src/modules/primitives/docs/queries/GetUnit.md +36 -0
- package/src/modules/primitives/docs/queries/GetUoMCategory.md +36 -0
- package/src/modules/primitives/docs/queries/ListUnitsByCategory.md +26 -0
- package/src/modules/primitives/generated/kysely-tailordb.ts +24 -45
- package/src/modules/primitives/index.ts +15 -4
- package/src/modules/primitives/lib/errors.generated.ts +112 -0
- package/src/modules/primitives/{permissions.ts → lib/permissions.generated.ts} +9 -8
- package/src/modules/primitives/module.ts +37 -27
- package/src/modules/primitives/query/convertAmount.generated.ts +5 -0
- package/src/modules/primitives/query/convertAmount.test.ts +2 -2
- package/src/modules/primitives/query/convertAmount.ts +27 -28
- package/src/modules/primitives/query/convertQuantity.generated.ts +5 -0
- package/src/modules/primitives/query/convertQuantity.test.ts +6 -2
- package/src/modules/primitives/query/convertQuantity.ts +49 -57
- package/src/modules/primitives/query/getBaseCurrency.generated.ts +5 -0
- package/src/modules/primitives/query/getBaseCurrency.test.ts +28 -0
- package/src/modules/primitives/query/getBaseCurrency.ts +16 -0
- package/src/modules/primitives/query/getCurrency.generated.ts +5 -0
- package/src/modules/primitives/query/getCurrency.test.ts +47 -0
- package/src/modules/primitives/query/getCurrency.ts +18 -0
- package/src/modules/primitives/query/getUnit.generated.ts +5 -0
- package/src/modules/primitives/query/getUnit.test.ts +47 -0
- package/src/modules/primitives/query/getUnit.ts +18 -0
- package/src/modules/primitives/query/getUoMCategory.generated.ts +5 -0
- package/src/modules/primitives/query/getUoMCategory.test.ts +47 -0
- package/src/modules/primitives/query/getUoMCategory.ts +18 -0
- package/src/modules/primitives/query/listUnitsByCategory.generated.ts +5 -0
- package/src/modules/primitives/query/listUnitsByCategory.ts +16 -0
- package/src/modules/primitives/tailor.config.ts +3 -3
- package/src/modules/shared/defineCommand.test.ts +23 -10
- package/src/modules/shared/defineCommand.ts +23 -10
- package/src/modules/shared/internal.ts +1 -0
- package/src/modules/shared/requirePermission.test.ts +22 -21
- package/src/modules/shared/requirePermission.ts +8 -2
- package/src/modules/shared/result.ts +12 -0
- package/src/modules/testing/index.ts +36 -11
- package/src/modules/user-management/command/activateUser.generated.ts +6 -0
- package/src/modules/user-management/command/activateUser.test.ts +27 -27
- package/src/modules/user-management/command/activateUser.ts +40 -48
- package/src/modules/user-management/command/assignPermissionToRole.generated.ts +6 -0
- package/src/modules/user-management/command/assignPermissionToRole.test.ts +42 -43
- package/src/modules/user-management/command/assignPermissionToRole.ts +59 -62
- package/src/modules/user-management/command/assignRoleToUser.generated.ts +6 -0
- package/src/modules/user-management/command/assignRoleToUser.test.ts +70 -63
- package/src/modules/user-management/command/assignRoleToUser.ts +63 -66
- package/src/modules/user-management/command/createPermission.generated.ts +6 -0
- package/src/modules/user-management/command/createPermission.test.ts +45 -38
- package/src/modules/user-management/command/createPermission.ts +42 -46
- package/src/modules/user-management/command/createRole.generated.ts +6 -0
- package/src/modules/user-management/command/createRole.test.ts +30 -29
- package/src/modules/user-management/command/createRole.ts +33 -33
- package/src/modules/user-management/command/createUser.generated.ts +6 -0
- package/src/modules/user-management/command/createUser.test.ts +64 -42
- package/src/modules/user-management/command/createUser.ts +54 -56
- package/src/modules/user-management/command/deactivateUser.generated.ts +6 -0
- package/src/modules/user-management/command/deactivateUser.test.ts +27 -27
- package/src/modules/user-management/command/deactivateUser.ts +40 -48
- package/src/modules/user-management/command/logAuditEvent.generated.ts +6 -0
- package/src/modules/user-management/command/logAuditEvent.test.ts +50 -42
- package/src/modules/user-management/command/logAuditEvent.ts +25 -28
- package/src/modules/user-management/command/reactivateUser.generated.ts +6 -0
- package/src/modules/user-management/command/reactivateUser.test.ts +31 -27
- package/src/modules/user-management/command/reactivateUser.ts +40 -48
- package/src/modules/user-management/command/revokePermissionFromRole.generated.ts +6 -0
- package/src/modules/user-management/command/revokePermissionFromRole.test.ts +52 -51
- package/src/modules/user-management/command/revokePermissionFromRole.ts +60 -57
- package/src/modules/user-management/command/revokeRoleFromUser.generated.ts +6 -0
- package/src/modules/user-management/command/revokeRoleFromUser.test.ts +53 -48
- package/src/modules/user-management/command/revokeRoleFromUser.ts +58 -57
- package/src/modules/user-management/docs/commands/CreatePermission.md +2 -2
- package/src/modules/user-management/docs/commands/CreateRole.md +1 -1
- package/src/modules/user-management/generated/enums.ts +11 -11
- package/src/modules/user-management/generated/kysely-tailordb.ts +27 -56
- package/src/modules/user-management/index.ts +2 -2
- package/src/modules/user-management/lib/errors.generated.ts +67 -0
- package/src/modules/user-management/{permissions.ts → lib/permissions.generated.ts} +8 -7
- package/src/modules/user-management/module.ts +22 -22
- package/src/modules/user-management/tailor.config.ts +3 -3
- package/src/schemas.ts +1 -1
- package/skills/1-module-docs/references/structure.md +0 -22
- package/skills/2-module-feature-breakdown/references/commands.md +0 -48
- package/skills/2-module-feature-breakdown/references/structure.md +0 -22
- package/skills/3-module-doc-review/references/commands.md +0 -54
- package/skills/3-module-doc-review/references/models.md +0 -29
- package/skills/4-module-tdd-implementation/SKILL.md +0 -74
- package/skills/4-module-tdd-implementation/references/commands.md +0 -45
- package/skills/4-module-tdd-implementation/references/errors.md +0 -7
- package/skills/4-module-tdd-implementation/references/models.md +0 -30
- package/skills/4-module-tdd-implementation/references/structure.md +0 -22
- package/skills/4-module-tdd-implementation/references/testing.md +0 -37
- package/skills/5-module-implementation-review/references/commands.md +0 -45
- package/skills/5-module-implementation-review/references/errors.md +0 -7
- package/skills/5-module-implementation-review/references/exports.md +0 -8
- package/skills/5-module-implementation-review/references/models.md +0 -30
- package/skills/app-compose-1-requirement-analysis/references/structure.md +0 -27
- package/skills/app-compose-2-requirements-breakdown/references/screen-detailview.md +0 -106
- package/skills/app-compose-2-requirements-breakdown/references/screen-form.md +0 -139
- package/skills/app-compose-2-requirements-breakdown/references/screen-listview.md +0 -153
- package/skills/app-compose-2-requirements-breakdown/references/structure.md +0 -27
- package/skills/app-compose-3-doc-review/references/structure.md +0 -27
- package/skills/app-compose-4-design-mock/SKILL.md +0 -256
- package/skills/app-compose-4-design-mock/references/component.md +0 -50
- package/skills/app-compose-4-design-mock/references/screen-detailview.md +0 -106
- package/skills/app-compose-4-design-mock/references/screen-form.md +0 -139
- package/skills/app-compose-4-design-mock/references/screen-listview.md +0 -153
- package/skills/app-compose-4-design-mock/references/structure.md +0 -27
- package/skills/app-compose-5-design-mock-review/SKILL.md +0 -290
- package/skills/app-compose-5-design-mock-review/references/component.md +0 -50
- package/skills/app-compose-5-design-mock-review/references/screen-detailview.md +0 -106
- package/skills/app-compose-5-design-mock-review/references/screen-form.md +0 -139
- package/skills/app-compose-5-design-mock-review/references/screen-listview.md +0 -153
- package/skills/app-compose-6-implementation-spec/references/auth.md +0 -72
- package/skills/app-compose-6-implementation-spec/references/structure.md +0 -27
- package/src/modules/primitives/lib/errors.ts +0 -138
- package/src/modules/user-management/lib/errors.ts +0 -81
- /package/skills/{2-module-feature-breakdown → erp-kit-module-4-tdd}/references/models.md +0 -0
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# Module Directory Structure
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
src/
|
|
5
|
-
├── db/ # Database models (one file per model)
|
|
6
|
-
├── executor/ # Async executors (record triggers, job functions)
|
|
7
|
-
├── command/ # Domain commands + tests (*.test.ts co-located)
|
|
8
|
-
├── lib/ # Internal shared code (errors.ts, types.ts)
|
|
9
|
-
├── testing/ # Test fixtures and helpers
|
|
10
|
-
├── generated/ # Auto-generated code (do not edit)
|
|
11
|
-
├── index.ts # Public exports
|
|
12
|
-
└── module.ts # Module definition
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Rules
|
|
16
|
-
|
|
17
|
-
- `db/`: Only documentable model definitions, no helpers
|
|
18
|
-
- `executor/`: Async executors as factory functions (see executors.md)
|
|
19
|
-
- `command/`: Domain commands + co-located tests, no utilities
|
|
20
|
-
- `lib/`: Internal errors and types (not documented)
|
|
21
|
-
- `testing/`: Fixtures for tests only
|
|
22
|
-
- Run `pnpm generate` after modifying `db/` models
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Testing Patterns
|
|
2
|
-
|
|
3
|
-
## Test Coverage Goal
|
|
4
|
-
|
|
5
|
-
Tests should cover all paths in the corresponding `docs/commands/*.md`:
|
|
6
|
-
|
|
7
|
-
- **Process Flow**: Each branch in the mermaid flowchart = one test case
|
|
8
|
-
- **Error Scenarios**: Each error code listed = one test case
|
|
9
|
-
- **Idempotent paths**: If flowchart shows "Already exists? → Return existing"
|
|
10
|
-
|
|
11
|
-
## Mock Database
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
const { db, spies } = createMockDb<DB>();
|
|
15
|
-
|
|
16
|
-
// Single return
|
|
17
|
-
spies.select.mockReturnValue(entity);
|
|
18
|
-
|
|
19
|
-
// Sequential returns (in query execution order)
|
|
20
|
-
spies.select.mockReturnValueOnce(first).mockReturnValueOnce(second);
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Custom Fields Passthrough
|
|
24
|
-
|
|
25
|
-
For `makeCreateX` factory commands, add one test verifying custom fields reach `.values()`:
|
|
26
|
-
|
|
27
|
-
- Instantiate with concrete type: `makeCreateX<{ myField: string }>()`
|
|
28
|
-
- Assert with `spies.values`: `expect(spies.values).toHaveBeenNthCalledWith(1, expect.objectContaining({ myField: "value" }))`
|
|
29
|
-
- Use `toHaveBeenNthCalledWith(n, ...)` when multiple inserts occur (e.g., audit events)
|
|
30
|
-
|
|
31
|
-
## Fixtures (`src/testing/fixtures.ts`)
|
|
32
|
-
|
|
33
|
-
- Import `Schema` from `lib/types` (not `Namespace` from generated code)
|
|
34
|
-
- Pattern: `export const baseEntity = { ... } as const satisfies Entity<Schema>`
|
|
35
|
-
- Fixed IDs for traceability: `"entity-1"`
|
|
36
|
-
- Consistent timestamp: `new Date("2024-01-01T00:00:00.000Z")`
|
|
37
|
-
- `updatedAt: null` for base fixtures
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# Command Implementation
|
|
2
|
-
|
|
3
|
-
## Dual Function Pattern
|
|
4
|
-
|
|
5
|
-
Two functions per operation: internal `_fn` and public `fn`.
|
|
6
|
-
|
|
7
|
-
**Internal function (`_myFunction`):**
|
|
8
|
-
|
|
9
|
-
- Takes concrete `DB` type from `generated/kysely-tailordb`
|
|
10
|
-
- Return type uses `Schema` from `lib/types`: `Promise<{ entity: Entity<Schema> }>`
|
|
11
|
-
- Contains actual implementation
|
|
12
|
-
|
|
13
|
-
**Public function (`myFunction`):**
|
|
14
|
-
|
|
15
|
-
- Generic signature: `<T extends { Entity: object }>(db: Kysely<T>, ...)`
|
|
16
|
-
- Return type uses generic `T`: `Promise<{ entity: Entity<T> }>`
|
|
17
|
-
- Delegates to internal with type casting: `_fn(db as unknown as DB, ...) as unknown as Result`
|
|
18
|
-
|
|
19
|
-
## Implementation Considerations
|
|
20
|
-
|
|
21
|
-
- **Validation**: Check referenced entities exist before operating
|
|
22
|
-
- **Idempotency**: For assign/revoke, return existing instead of throwing
|
|
23
|
-
- **Return format**: Wrap in object `{ entity }` not just `entity`
|
|
24
|
-
|
|
25
|
-
## Conventions
|
|
26
|
-
|
|
27
|
-
- Input types: exported interfaces (`export interface MyFunctionInput`)
|
|
28
|
-
- Use `.executeTakeFirst()` for single results
|
|
29
|
-
- Include JSDoc: `/** Function: name \n Description */`
|
|
30
|
-
|
|
31
|
-
## State Transitions
|
|
32
|
-
|
|
33
|
-
For commands that transition between statuses, accept `from?: string[]` with a default:
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
from?: string[]; // Default: ["ACTIVE"]
|
|
37
|
-
|
|
38
|
-
const validFromStatuses = input.from ?? ["ACTIVE"];
|
|
39
|
-
if (!validFromStatuses.includes(user.status)) {
|
|
40
|
-
throw new InvalidStatusTransitionError(user.status, targetStatus);
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
- Default `from` contains the base valid source status
|
|
45
|
-
- Parent modules can override to allow transitions from additional statuses
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# Database Models
|
|
2
|
-
|
|
3
|
-
## Factory Function Pattern
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
export function createEntityType(params: {
|
|
7
|
-
fields?: Record<string, unknown>;
|
|
8
|
-
additionalStatuses?: string[];
|
|
9
|
-
});
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
- Include `...db.fields.timestamps()`
|
|
13
|
-
- Use `.description()` for field docs
|
|
14
|
-
- Apply permissions at model level
|
|
15
|
-
|
|
16
|
-
## Stateful Model Enums
|
|
17
|
-
|
|
18
|
-
Status enums are tied to the module's state machine. Base module defines core statuses; parent callers can only **extend, not replace**.
|
|
19
|
-
|
|
20
|
-
```typescript
|
|
21
|
-
// Good: extension only
|
|
22
|
-
const BASE_STATUSES = ["PENDING", "ACTIVE", "INACTIVE"] as const;
|
|
23
|
-
const statuses = [...BASE_STATUSES, ...(params.additionalStatuses ?? [])];
|
|
24
|
-
|
|
25
|
-
// Bad: allows replacement
|
|
26
|
-
const statuses = params.statuses ?? ["PENDING", "ACTIVE", "INACTIVE"];
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
- Name parameter `additionalX` to signal extension-only
|
|
30
|
-
- Parent modules handle their additional status transitions
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Application Directory Structure
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
{app_name}/
|
|
5
|
-
├── backend/
|
|
6
|
-
│ ├── src/
|
|
7
|
-
│ │ ├── modules.ts # Declaring module usage
|
|
8
|
-
│ │ ├── modules/
|
|
9
|
-
│ │ │ └── {module-name}/ # Module-specific directory
|
|
10
|
-
│ │ │ ├── resolvers/ # API Definition to expose graphql apis
|
|
11
|
-
│ │ │ └── executors/ # PubSub Automation (one file per declaration)
|
|
12
|
-
│ │ └── generated/ # Auto-generated code (do not edit)
|
|
13
|
-
│ └── tailor.config.ts # tailor application config
|
|
14
|
-
│
|
|
15
|
-
└── frontend/
|
|
16
|
-
└── src/
|
|
17
|
-
├── pages/ # File-based routing (auto-discovered by Vite plugin)
|
|
18
|
-
│ └── {page-path}/
|
|
19
|
-
│ ├── page.tsx
|
|
20
|
-
│ └── {page-path}/
|
|
21
|
-
│ ├── components/
|
|
22
|
-
│ └── page.tsx
|
|
23
|
-
├── components/
|
|
24
|
-
│ └── ui/ # Generic UI components
|
|
25
|
-
├── graphql/ # gql.tada settings
|
|
26
|
-
└── providers/ # react providers
|
|
27
|
-
```
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
# DetailView Screen Implementation
|
|
2
|
-
|
|
3
|
-
Implementation pattern for screens with `Screen Type: DetailView`.
|
|
4
|
-
Assumes `page.md` and `component.md` rules.
|
|
5
|
-
|
|
6
|
-
## File Structure
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
{screen-path}/[id]/
|
|
10
|
-
├── components/
|
|
11
|
-
│ ├── {screen-name}-detail.tsx # Main content (left column)
|
|
12
|
-
│ └── {screen-name}-actions.tsx # Action sidebar (right column)
|
|
13
|
-
├── edit/
|
|
14
|
-
│ ├── components/
|
|
15
|
-
│ │ └── edit-{screen-name}-form.tsx
|
|
16
|
-
│ └── page.tsx
|
|
17
|
-
└── page.tsx
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Layout
|
|
21
|
-
|
|
22
|
-
- Two-column layout: main content on the left, actions on the right.
|
|
23
|
-
|
|
24
|
-
```tsx
|
|
25
|
-
const ResourcePage = () => {
|
|
26
|
-
const { id } = useParams();
|
|
27
|
-
const [{ data, error, fetching }, reexecuteQuery] = useQuery({
|
|
28
|
-
query: ResourceQuery,
|
|
29
|
-
variables: { id: id! },
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
if (fetching) return <Loading />;
|
|
33
|
-
if (error || !data?.resource) return <ErrorFallback ... />;
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<Layout columns={2} title="Resource Detail">
|
|
37
|
-
<Layout.Column>
|
|
38
|
-
<ResourceDetail resource={data.resource} />
|
|
39
|
-
</Layout.Column>
|
|
40
|
-
<Layout.Column>
|
|
41
|
-
<ResourceActions resource={data.resource} />
|
|
42
|
-
</Layout.Column>
|
|
43
|
-
</Layout>
|
|
44
|
-
);
|
|
45
|
-
};
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Left Column: Detail Component
|
|
49
|
-
|
|
50
|
-
Stack `DescriptionCard` and related tables vertically with `space-y-6`.
|
|
51
|
-
|
|
52
|
-
- `DescriptionCard` (`@tailor-platform/app-shell`): renders key-value fields declaratively.
|
|
53
|
-
- Complex content (tables, timelines): wrap in `<div className="rounded-lg border bg-card p-6">`.
|
|
54
|
-
|
|
55
|
-
### DescriptionCard
|
|
56
|
-
|
|
57
|
-
```tsx
|
|
58
|
-
<DescriptionCard
|
|
59
|
-
data={resource}
|
|
60
|
-
title="Overview"
|
|
61
|
-
columns={3}
|
|
62
|
-
fields={[
|
|
63
|
-
{ key: "name", label: "Name", meta: { copyable: true } },
|
|
64
|
-
{
|
|
65
|
-
key: "status",
|
|
66
|
-
label: "Status",
|
|
67
|
-
type: "badge",
|
|
68
|
-
meta: { badgeVariantMap: { ACTIVE: "success", PENDING: "warning" } },
|
|
69
|
-
},
|
|
70
|
-
{ type: "divider" },
|
|
71
|
-
{
|
|
72
|
-
key: "createdAt",
|
|
73
|
-
label: "Created At",
|
|
74
|
-
type: "date",
|
|
75
|
-
meta: { dateFormat: "medium" },
|
|
76
|
-
},
|
|
77
|
-
]}
|
|
78
|
-
/>
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
Field types: `"text"` (default), `"badge"`, `"money"`, `"date"`, `"link"`, `"address"`, `"reference"`, `"divider"`
|
|
82
|
-
|
|
83
|
-
## Right Column: Actions Component
|
|
84
|
-
|
|
85
|
-
Wrap in a `Card` component. Use `Button variant="ghost"` for each action item.
|
|
86
|
-
|
|
87
|
-
```tsx
|
|
88
|
-
<Card>
|
|
89
|
-
<CardHeader>
|
|
90
|
-
<CardTitle>Actions</CardTitle>
|
|
91
|
-
</CardHeader>
|
|
92
|
-
<CardContent className="space-y-2">
|
|
93
|
-
<Button variant="ghost" className="w-full justify-start gap-2" asChild>
|
|
94
|
-
<Link to="edit">✎ Edit</Link>
|
|
95
|
-
</Button>
|
|
96
|
-
<Button variant="ghost" className="w-full justify-start gap-2" onClick={handler}>
|
|
97
|
-
✓ Approve
|
|
98
|
-
</Button>
|
|
99
|
-
</CardContent>
|
|
100
|
-
</Card>
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
- Navigation: `<Button variant="ghost" asChild><Link to="...">`
|
|
104
|
-
- Mutation: `<Button variant="ghost" onClick={handler}>` with custom resolvers (see `backend/resolvers.md`)
|
|
105
|
-
- Conditional: show/hide based on status
|
|
106
|
-
- Multiple cards: stack with `<div className="space-y-6">`
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# Form Screen Implementation
|
|
2
|
-
|
|
3
|
-
Implementation pattern for screens with `Screen Type: Form`.
|
|
4
|
-
Assumes `page.md` and `component.md` rules.
|
|
5
|
-
|
|
6
|
-
## File Structure
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
{screen-path}/
|
|
10
|
-
├── components/
|
|
11
|
-
│ └── {screen-name}-form.tsx # Form component with validation
|
|
12
|
-
└── page.tsx
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Page Component (page.tsx)
|
|
16
|
-
|
|
17
|
-
Form pages delegate mutation logic to the form component.
|
|
18
|
-
|
|
19
|
-
```tsx
|
|
20
|
-
const ScreenNamePage = () => (
|
|
21
|
-
<Layout columns={1} title="Screen Title">
|
|
22
|
-
<Layout.Column>
|
|
23
|
-
<ScreenNameForm />
|
|
24
|
-
</Layout.Column>
|
|
25
|
-
</Layout>
|
|
26
|
-
);
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
For edit forms that need existing data, co-locate data fetching in the page component:
|
|
30
|
-
|
|
31
|
-
```tsx
|
|
32
|
-
const EditPage = () => {
|
|
33
|
-
const { id } = useParams();
|
|
34
|
-
const [{ data, error, fetching }] = useQuery({
|
|
35
|
-
query: ResourceQuery,
|
|
36
|
-
variables: { id: id! },
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
if (fetching) return <Loading />;
|
|
40
|
-
if (error || !data?.resource) return <ErrorFallback ... />;
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<Layout columns={1} title="Edit Resource">
|
|
44
|
-
<Layout.Column>
|
|
45
|
-
<EditResourceForm resource={data.resource} />
|
|
46
|
-
</Layout.Column>
|
|
47
|
-
</Layout>
|
|
48
|
-
);
|
|
49
|
-
};
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Form Component (components/{screen-name}-form.tsx)
|
|
53
|
-
|
|
54
|
-
### Technology Stack
|
|
55
|
-
|
|
56
|
-
- `react-hook-form` — form state management
|
|
57
|
-
- `zod` + `@hookform/resolvers/zod` — validation
|
|
58
|
-
- `useMutation` (urql) — GraphQL mutation
|
|
59
|
-
- `useNavigate` (@tailor-platform/app-shell) — post-submit navigation
|
|
60
|
-
|
|
61
|
-
### Pattern
|
|
62
|
-
|
|
63
|
-
```tsx
|
|
64
|
-
const formSchema = z.object({
|
|
65
|
-
title: z.string().min(1, "Title is required"),
|
|
66
|
-
description: z.string().optional(),
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
type FormValues = z.infer<typeof formSchema>;
|
|
70
|
-
|
|
71
|
-
export const ScreenNameForm = () => {
|
|
72
|
-
const navigate = useNavigate();
|
|
73
|
-
const [, createResource] = useMutation(CreateMutation);
|
|
74
|
-
|
|
75
|
-
const form = useForm<FormValues>({
|
|
76
|
-
resolver: zodResolver(formSchema),
|
|
77
|
-
defaultValues: { title: "", description: "" },
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const onSubmit = (values: FormValues) => {
|
|
81
|
-
void createResource({ input: values }).then((result) => {
|
|
82
|
-
if (!result.error) {
|
|
83
|
-
void navigate("..");
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
return (
|
|
89
|
-
<Form {...form}>
|
|
90
|
-
<form onSubmit={(e) => void form.handleSubmit(onSubmit)(e)} className="max-w-md space-y-4">
|
|
91
|
-
<FormField
|
|
92
|
-
control={form.control}
|
|
93
|
-
name="title"
|
|
94
|
-
render={({ field }) => (
|
|
95
|
-
<FormItem>
|
|
96
|
-
<FormLabel>Title</FormLabel>
|
|
97
|
-
<FormControl>
|
|
98
|
-
<Input placeholder="Enter title" {...field} />
|
|
99
|
-
</FormControl>
|
|
100
|
-
<FormMessage />
|
|
101
|
-
</FormItem>
|
|
102
|
-
)}
|
|
103
|
-
/>
|
|
104
|
-
<div className="flex gap-2">
|
|
105
|
-
<Button type="submit">Create</Button>
|
|
106
|
-
<Button type="button" variant="outline" onClick={() => void navigate("..")}>
|
|
107
|
-
Cancel
|
|
108
|
-
</Button>
|
|
109
|
-
</div>
|
|
110
|
-
</form>
|
|
111
|
-
</Form>
|
|
112
|
-
);
|
|
113
|
-
};
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## Field Type Mapping
|
|
117
|
-
|
|
118
|
-
| Field Type | Component | Zod Schema |
|
|
119
|
-
| ---------- | ------------------------------ | ------------------------------- |
|
|
120
|
-
| Text | `<Input />` | `z.string()` |
|
|
121
|
-
| Textarea | `<textarea className="..." />` | `z.string()` |
|
|
122
|
-
| Dropdown | `<Select />` | `z.string()` or `z.enum([...])` |
|
|
123
|
-
| Date | `<Input type="date" />` | `z.string()` (ISO format) |
|
|
124
|
-
| Number | `<Input type="number" />` | `z.coerce.number()` |
|
|
125
|
-
| Email | `<Input type="email" />` | `z.string().email()` |
|
|
126
|
-
| Checkbox | `<Checkbox />` | `z.boolean()` |
|
|
127
|
-
| Radio | `<RadioGroup />` | `z.enum([...])` |
|
|
128
|
-
|
|
129
|
-
## Validation Mapping
|
|
130
|
-
|
|
131
|
-
- **Required: Yes** → `.min(1, "Field is required")` (string) / `.positive()` (number)
|
|
132
|
-
- **Required: No** → `.optional()`
|
|
133
|
-
|
|
134
|
-
## Key Points
|
|
135
|
-
|
|
136
|
-
- Set `defaultValues` for all fields (empty string, false, etc.)
|
|
137
|
-
- Navigate to `".."` after successful mutation
|
|
138
|
-
- Cancel button must use `type="button"` to prevent form submit
|
|
139
|
-
- For edit forms, accept fragment data as props and pre-fill `defaultValues`
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
# ListView Screen Implementation
|
|
2
|
-
|
|
3
|
-
Implementation pattern for screens with `Screen Type: ListView`.
|
|
4
|
-
Assumes `page.md` and `component.md` rules.
|
|
5
|
-
|
|
6
|
-
## File Structure
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
{screen-path}/
|
|
10
|
-
├── components/
|
|
11
|
-
│ └── {screen-name}-table.tsx # Table component with fragments
|
|
12
|
-
└── page.tsx
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Page Component (page.tsx)
|
|
16
|
-
|
|
17
|
-
Data fetching and `Layout` must be co-located in the same page component.
|
|
18
|
-
Do NOT split into an inner Content component — `Layout` requires `Layout.Column` as direct children.
|
|
19
|
-
|
|
20
|
-
```tsx
|
|
21
|
-
const ResourcesQuery = graphql(
|
|
22
|
-
`
|
|
23
|
-
query Resources {
|
|
24
|
-
resources {
|
|
25
|
-
...ResourceTable
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
`,
|
|
29
|
-
[ResourceTableFragment],
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
const ResourcesPage = () => {
|
|
33
|
-
const [{ data, error, fetching }, reexecuteQuery] = useQuery({
|
|
34
|
-
query: ResourcesQuery,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
if (fetching) return <Loading />;
|
|
38
|
-
|
|
39
|
-
if (error || !data) {
|
|
40
|
-
return (
|
|
41
|
-
<ErrorFallback
|
|
42
|
-
title="Failed to load resources"
|
|
43
|
-
message="An error occurred while fetching the list."
|
|
44
|
-
onReset={() => reexecuteQuery({ requestPolicy: "network-only" })}
|
|
45
|
-
/>
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<Layout
|
|
51
|
-
columns={1}
|
|
52
|
-
title="Resources"
|
|
53
|
-
actions={[
|
|
54
|
-
<Button key="create" asChild>
|
|
55
|
-
<Link to="create">Create</Link>
|
|
56
|
-
</Button>,
|
|
57
|
-
]}
|
|
58
|
-
>
|
|
59
|
-
<Layout.Column>
|
|
60
|
-
<ResourceTable data={data.resources} />
|
|
61
|
-
</Layout.Column>
|
|
62
|
-
</Layout>
|
|
63
|
-
);
|
|
64
|
-
};
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Table Component (components/{screen-name}-table.tsx)
|
|
68
|
-
|
|
69
|
-
### Fragment Collocation
|
|
70
|
-
|
|
71
|
-
Define a row fragment and a table fragment wrapping the Connection type.
|
|
72
|
-
|
|
73
|
-
```tsx
|
|
74
|
-
const ResourceRowFragment = graphql(`
|
|
75
|
-
fragment ResourceRow on Resource {
|
|
76
|
-
id
|
|
77
|
-
title
|
|
78
|
-
status
|
|
79
|
-
createdAt
|
|
80
|
-
}
|
|
81
|
-
`);
|
|
82
|
-
|
|
83
|
-
export const ResourceTableFragment = graphql(
|
|
84
|
-
`
|
|
85
|
-
fragment ResourceTable on ResourceConnection {
|
|
86
|
-
edges {
|
|
87
|
-
node {
|
|
88
|
-
...ResourceRow
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
`,
|
|
93
|
-
[ResourceRowFragment],
|
|
94
|
-
);
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Row Component
|
|
98
|
-
|
|
99
|
-
```tsx
|
|
100
|
-
const ResourceRow = ({ resource: resourceFragment }: ResourceRowProps) => {
|
|
101
|
-
const resource = readFragment(ResourceRowFragment, resourceFragment);
|
|
102
|
-
return (
|
|
103
|
-
<TableRow>
|
|
104
|
-
<TableCell>{resource.title}</TableCell>
|
|
105
|
-
<TableCell>
|
|
106
|
-
<Badge variant={resource.status === "ACTIVE" ? "default" : "secondary"}>
|
|
107
|
-
{resource.status}
|
|
108
|
-
</Badge>
|
|
109
|
-
</TableCell>
|
|
110
|
-
<TableCell>
|
|
111
|
-
<Button variant="ghost" size="sm" asChild>
|
|
112
|
-
<Link to={resource.id}>View</Link>
|
|
113
|
-
</Button>
|
|
114
|
-
</TableCell>
|
|
115
|
-
</TableRow>
|
|
116
|
-
);
|
|
117
|
-
};
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### Empty State
|
|
121
|
-
|
|
122
|
-
```tsx
|
|
123
|
-
if (connection.edges.length === 0) {
|
|
124
|
-
return (
|
|
125
|
-
<EmptyState
|
|
126
|
-
title="No resources"
|
|
127
|
-
message="Get started by creating a new resource."
|
|
128
|
-
action={
|
|
129
|
-
<Button asChild>
|
|
130
|
-
<Link to="create">Create</Link>
|
|
131
|
-
</Button>
|
|
132
|
-
}
|
|
133
|
-
/>
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## Column Property Mapping
|
|
139
|
-
|
|
140
|
-
| Property | Implementation |
|
|
141
|
-
| --------------- | ----------------------------------------------------------- |
|
|
142
|
-
| Hideable: Yes | Column visibility state to toggle show/hide |
|
|
143
|
-
| Sortable: Yes | Sort icon on `<TableHead>` + onClick to toggle query vars |
|
|
144
|
-
| Filterable: Yes | Filter UI above table (`<Select />`) |
|
|
145
|
-
| Searchable: Yes | Search input above table (`<Input placeholder="Search" />`) |
|
|
146
|
-
|
|
147
|
-
## Key Points
|
|
148
|
-
|
|
149
|
-
- Use `<Badge />` for status columns
|
|
150
|
-
- Format dates with `toLocaleDateString()`
|
|
151
|
-
- Use `<EmptyState />` with Create action for empty lists
|
|
152
|
-
- Add a View button per row to navigate to the detail page
|
|
153
|
-
- Iterate data using Connection type `edges.node` pattern
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Application Directory Structure
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
{app_name}/
|
|
5
|
-
├── backend/
|
|
6
|
-
│ ├── src/
|
|
7
|
-
│ │ ├── modules.ts # Declaring module usage
|
|
8
|
-
│ │ ├── modules/
|
|
9
|
-
│ │ │ └── {module-name}/ # Module-specific directory
|
|
10
|
-
│ │ │ ├── resolvers/ # API Definition to expose graphql apis
|
|
11
|
-
│ │ │ └── executors/ # PubSub Automation (one file per declaration)
|
|
12
|
-
│ │ └── generated/ # Auto-generated code (do not edit)
|
|
13
|
-
│ └── tailor.config.ts # tailor application config
|
|
14
|
-
│
|
|
15
|
-
└── frontend/
|
|
16
|
-
└── src/
|
|
17
|
-
├── pages/ # File-based routing (auto-discovered by Vite plugin)
|
|
18
|
-
│ └── {page-path}/
|
|
19
|
-
│ ├── page.tsx
|
|
20
|
-
│ └── {page-path}/
|
|
21
|
-
│ ├── components/
|
|
22
|
-
│ └── page.tsx
|
|
23
|
-
├── components/
|
|
24
|
-
│ └── ui/ # Generic UI components
|
|
25
|
-
├── graphql/ # gql.tada settings
|
|
26
|
-
└── providers/ # react providers
|
|
27
|
-
```
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Application Directory Structure
|
|
2
|
-
|
|
3
|
-
```
|
|
4
|
-
{app_name}/
|
|
5
|
-
├── backend/
|
|
6
|
-
│ ├── src/
|
|
7
|
-
│ │ ├── modules.ts # Declaring module usage
|
|
8
|
-
│ │ ├── modules/
|
|
9
|
-
│ │ │ └── {module-name}/ # Module-specific directory
|
|
10
|
-
│ │ │ ├── resolvers/ # API Definition to expose graphql apis
|
|
11
|
-
│ │ │ └── executors/ # PubSub Automation (one file per declaration)
|
|
12
|
-
│ │ └── generated/ # Auto-generated code (do not edit)
|
|
13
|
-
│ └── tailor.config.ts # tailor application config
|
|
14
|
-
│
|
|
15
|
-
└── frontend/
|
|
16
|
-
└── src/
|
|
17
|
-
├── pages/ # File-based routing (auto-discovered by Vite plugin)
|
|
18
|
-
│ └── {page-path}/
|
|
19
|
-
│ ├── page.tsx
|
|
20
|
-
│ └── {page-path}/
|
|
21
|
-
│ ├── components/
|
|
22
|
-
│ └── page.tsx
|
|
23
|
-
├── components/
|
|
24
|
-
│ └── ui/ # Generic UI components
|
|
25
|
-
├── graphql/ # gql.tada settings
|
|
26
|
-
└── providers/ # react providers
|
|
27
|
-
```
|