From 39e08a419912e4a37304ff1303548bcdc9f8bb90 Mon Sep 17 00:00:00 2001
From: Michael Haufe
Date: Wed, 23 Oct 2024 20:48:24 +0000
Subject: [PATCH] - styling: datatables now have striped rows - refactor:
renamed enpoints to align with ReqType enum - refactor: parent component
properties moved to Belongs relations
---
components/WorkboxDataView.vue | 109 --
components/XDataTable.vue | 2 +-
middleware/org-solution-check.global.ts | 4 +-
migrations/.snapshot-cathedral.json | 1592 ++++++++---------
migrations/Migration20241020164456.ts | 236 +++
migrations/Migration20241022160037.ts | 104 ++
pages/index.client.vue | 4 +-
pages/new-organization.vue | 4 +-
.../[solution-slug]/edit-entry.client.vue | 4 +-
.../environment/assumptions.client.vue | 10 +-
.../environment/components.client.vue | 10 +-
.../environment/constraints.client.vue | 12 +-
.../environment/effects.client.vue | 10 +-
.../environment/glossary.client.vue | 10 +-
.../environment/invariants.client.vue | 10 +-
.../goals/functionality.client.vue | 10 +-
.../goals/limitations.client.vue | 10 +-
.../goals/obstacles.client.vue | 10 +-
.../[solution-slug]/goals/outcomes.client.vue | 10 +-
.../goals/rationale.client.vue | 12 +-
.../goals/scenarios.client.vue | 16 +-
.../goals/stakeholders.client.vue | 24 +-
.../[solution-slug]/index.client.vue | 6 +-
.../project/roles-personnel.client.vue | 10 +-
.../system/components.client.vue | 19 +-
.../system/functionality.client.vue | 12 +-
.../system/scenarios.client.vue | 54 +-
.../[solution-slug]/workbox.client.vue | 110 +-
.../[organization-slug]/edit-entry.client.vue | 4 +-
pages/o/[organization-slug]/index.client.vue | 8 +-
.../new-solution.client.vue | 6 +-
pages/o/[organization-slug]/users.vue | 2 +-
server/api/appusers/[id].delete.ts | 3 +-
.../[id].delete.ts | 0
.../{assumptions => assumption}/[id].get.ts | 1 -
.../{assumptions => assumption}/[id].put.ts | 2 +-
.../{assumptions => assumption}/index.get.ts | 0
.../{assumptions => assumption}/index.post.ts | 0
server/api/audit-log/deleted.get.ts | 3 +-
server/api/auth/[...].ts | 2 +-
.../[id].delete.ts | 0
.../{constraints => constraint}/[id].get.ts | 1 -
.../{constraints => constraint}/[id].put.ts | 2 +-
.../{constraints => constraint}/index.get.ts | 0
.../{constraints => constraint}/index.post.ts | 0
server/api/{effects => effect}/[id].delete.ts | 0
server/api/{effects => effect}/[id].get.ts | 1 -
server/api/{effects => effect}/[id].put.ts | 2 +-
server/api/{effects => effect}/index.get.ts | 0
server/api/{effects => effect}/index.post.ts | 0
.../[id].delete.ts | 0
.../[id].get.ts | 2 -
.../[id].put.ts | 22 +-
.../index.get.ts | 0
.../index.post.ts | 6 +-
.../[id].delete.ts | 0
.../[id].get.ts | 1 -
.../[id].put.ts | 2 +-
.../index.get.ts | 0
.../index.post.ts | 0
.../[id].delete.ts | 0
.../[id].get.ts | 1 -
.../[id].put.ts | 2 +-
.../index.get.ts | 0
.../index.post.ts | 7 +-
.../{invariants => invariant}/[id].delete.ts | 0
.../api/{invariants => invariant}/[id].get.ts | 1 -
.../api/{invariants => invariant}/[id].put.ts | 2 +-
.../{invariants => invariant}/index.get.ts | 0
.../{invariants => invariant}/index.post.ts | 0
.../[id].delete.ts | 0
.../[id].get.ts | 1 -
.../[id].put.ts | 2 +-
.../index.get.ts | 0
.../index.post.ts | 0
server/api/{limits => limit}/[id].delete.ts | 0
server/api/{limits => limit}/[id].get.ts | 1 -
server/api/{limits => limit}/[id].put.ts | 2 +-
server/api/{limits => limit}/index.get.ts | 0
server/api/{limits => limit}/index.post.ts | 0
.../[id].delete.ts | 0
.../[id].get.ts | 1 -
.../[id].put.ts | 0
.../index.get.ts | 0
.../index.post.ts | 0
.../{obstacles => obstacle}/[id].delete.ts | 0
.../api/{obstacles => obstacle}/[id].get.ts | 1 -
.../api/{obstacles => obstacle}/[id].put.ts | 2 +-
.../api/{obstacles => obstacle}/index.get.ts | 0
.../api/{obstacles => obstacle}/index.post.ts | 0
.../[id].delete.ts | 0
.../[id].get.ts | 0
.../[id].put.ts | 2 +-
.../index.get.ts | 0
.../index.post.ts | 0
.../api/{outcomes => outcome}/[id].delete.ts | 0
server/api/{outcomes => outcome}/[id].get.ts | 1 -
server/api/{outcomes => outcome}/[id].put.ts | 2 +-
server/api/{outcomes => outcome}/index.get.ts | 0
.../api/{outcomes => outcome}/index.post.ts | 0
server/api/parse-requirement/follows.get.ts | 30 +
.../index.get.ts | 1 -
.../index.post.ts | 27 +-
server/api/{persons => person}/[id].delete.ts | 0
server/api/{persons => person}/[id].get.ts | 1 -
server/api/{persons => person}/[id].put.ts | 2 +-
server/api/{persons => person}/index.get.ts | 0
server/api/{persons => person}/index.post.ts | 0
.../{solutions => solution}/[id].delete.ts | 0
.../api/{solutions => solution}/[id].get.ts | 0
.../api/{solutions => solution}/[id].put.ts | 2 +-
.../api/{solutions => solution}/index.get.ts | 0
.../api/{solutions => solution}/index.post.ts | 1 -
.../[id].delete.ts | 0
.../{stakeholders => stakeholder}/[id].get.ts | 1 -
.../{stakeholders => stakeholder}/[id].put.ts | 24 +-
.../index.get.ts | 0
.../index.post.ts | 8 +-
.../[id].delete.ts | 0
.../[id].get.ts | 1 -
.../[id].put.ts | 27 +-
server/api/system-component/index.get.ts | 42 +
.../index.post.ts | 10 +-
server/api/system-components/index.get.ts | 23 -
.../{use-cases => use-case}/[id].delete.ts | 0
.../api/{use-cases => use-case}/[id].get.ts | 1 -
.../api/{use-cases => use-case}/[id].put.ts | 20 +-
.../api/{use-cases => use-case}/index.get.ts | 8 +-
.../api/{use-cases => use-case}/index.post.ts | 12 +-
.../[id].delete.ts | 0
.../{user-stories => user-story}/[id].get.ts | 1 -
.../{user-stories => user-story}/[id].put.ts | 20 +-
.../{user-stories => user-story}/index.get.ts | 2 +-
.../index.post.ts | 12 +-
server/domain/application/AuditLog.ts | 8 +-
server/domain/relations/Characterizes.ts | 2 +-
.../domain/relations/RequirementRelation.ts | 6 +-
server/domain/relations/index.ts | 1 -
.../requirements/EnvironmentComponent.ts | 11 +-
server/domain/requirements/GlossaryTerm.ts | 11 +-
.../domain/requirements/ParsedRequirement.ts | 8 +-
server/domain/requirements/ReqType.ts | 4 +
server/domain/requirements/Stakeholder.ts | 7 -
server/domain/requirements/SystemComponent.ts | 7 -
server/domain/types/index.ts | 12 +-
server/utils/findAllSolutionRequirements.ts | 45 +-
server/utils/groupBy.ts | 10 +
utils/snakeCaseToSlug.ts | 7 +
utils/snakeCaseToTitle.ts | 8 +
149 files changed, 1623 insertions(+), 1322 deletions(-)
delete mode 100644 components/WorkboxDataView.vue
create mode 100644 migrations/Migration20241020164456.ts
create mode 100644 migrations/Migration20241022160037.ts
rename server/api/{assumptions => assumption}/[id].delete.ts (100%)
rename server/api/{assumptions => assumption}/[id].get.ts (93%)
rename server/api/{assumptions => assumption}/[id].put.ts (96%)
rename server/api/{assumptions => assumption}/index.get.ts (100%)
rename server/api/{assumptions => assumption}/index.post.ts (100%)
rename server/api/{constraints => constraint}/[id].delete.ts (100%)
rename server/api/{constraints => constraint}/[id].get.ts (93%)
rename server/api/{constraints => constraint}/[id].put.ts (96%)
rename server/api/{constraints => constraint}/index.get.ts (100%)
rename server/api/{constraints => constraint}/index.post.ts (100%)
rename server/api/{effects => effect}/[id].delete.ts (100%)
rename server/api/{effects => effect}/[id].get.ts (92%)
rename server/api/{effects => effect}/[id].put.ts (96%)
rename server/api/{effects => effect}/index.get.ts (100%)
rename server/api/{effects => effect}/index.post.ts (100%)
rename server/api/{environment-components => environment-component}/[id].delete.ts (100%)
rename server/api/{environment-components => environment-component}/[id].get.ts (84%)
rename server/api/{environment-components => environment-component}/[id].put.ts (64%)
rename server/api/{environment-components => environment-component}/index.get.ts (100%)
rename server/api/{environment-components => environment-component}/index.post.ts (89%)
rename server/api/{functional-behaviors => functional-behavior}/[id].delete.ts (100%)
rename server/api/{functional-behaviors => functional-behavior}/[id].get.ts (93%)
rename server/api/{functional-behaviors => functional-behavior}/[id].put.ts (96%)
rename server/api/{functional-behaviors => functional-behavior}/index.get.ts (100%)
rename server/api/{functional-behaviors => functional-behavior}/index.post.ts (100%)
rename server/api/{glossary-terms => glossary-term}/[id].delete.ts (100%)
rename server/api/{glossary-terms => glossary-term}/[id].get.ts (93%)
rename server/api/{glossary-terms => glossary-term}/[id].put.ts (96%)
rename server/api/{glossary-terms => glossary-term}/index.get.ts (100%)
rename server/api/{glossary-terms => glossary-term}/index.post.ts (76%)
rename server/api/{invariants => invariant}/[id].delete.ts (100%)
rename server/api/{invariants => invariant}/[id].get.ts (93%)
rename server/api/{invariants => invariant}/[id].put.ts (96%)
rename server/api/{invariants => invariant}/index.get.ts (100%)
rename server/api/{invariants => invariant}/index.post.ts (100%)
rename server/api/{justifications => justification}/[id].delete.ts (100%)
rename server/api/{justifications => justification}/[id].get.ts (93%)
rename server/api/{justifications => justification}/[id].put.ts (96%)
rename server/api/{justifications => justification}/index.get.ts (100%)
rename server/api/{justifications => justification}/index.post.ts (100%)
rename server/api/{limits => limit}/[id].delete.ts (100%)
rename server/api/{limits => limit}/[id].get.ts (92%)
rename server/api/{limits => limit}/[id].put.ts (96%)
rename server/api/{limits => limit}/index.get.ts (100%)
rename server/api/{limits => limit}/index.post.ts (100%)
rename server/api/{non-functional-behaviors => non-functional-behavior}/[id].delete.ts (100%)
rename server/api/{non-functional-behaviors => non-functional-behavior}/[id].get.ts (93%)
rename server/api/{non-functional-behaviors => non-functional-behavior}/[id].put.ts (100%)
rename server/api/{non-functional-behaviors => non-functional-behavior}/index.get.ts (100%)
rename server/api/{non-functional-behaviors => non-functional-behavior}/index.post.ts (100%)
rename server/api/{obstacles => obstacle}/[id].delete.ts (100%)
rename server/api/{obstacles => obstacle}/[id].get.ts (92%)
rename server/api/{obstacles => obstacle}/[id].put.ts (96%)
rename server/api/{obstacles => obstacle}/index.get.ts (100%)
rename server/api/{obstacles => obstacle}/index.post.ts (100%)
rename server/api/{organizations => organization}/[id].delete.ts (100%)
rename server/api/{organizations => organization}/[id].get.ts (100%)
rename server/api/{organizations => organization}/[id].put.ts (94%)
rename server/api/{organizations => organization}/index.get.ts (100%)
rename server/api/{organizations => organization}/index.post.ts (100%)
rename server/api/{outcomes => outcome}/[id].delete.ts (100%)
rename server/api/{outcomes => outcome}/[id].get.ts (92%)
rename server/api/{outcomes => outcome}/[id].put.ts (96%)
rename server/api/{outcomes => outcome}/index.get.ts (100%)
rename server/api/{outcomes => outcome}/index.post.ts (100%)
create mode 100644 server/api/parse-requirement/follows.get.ts
rename server/api/{parse-requirements => parse-requirement}/index.get.ts (92%)
rename server/api/{parse-requirements => parse-requirement}/index.post.ts (92%)
rename server/api/{persons => person}/[id].delete.ts (100%)
rename server/api/{persons => person}/[id].get.ts (92%)
rename server/api/{persons => person}/[id].put.ts (96%)
rename server/api/{persons => person}/index.get.ts (100%)
rename server/api/{persons => person}/index.post.ts (100%)
rename server/api/{solutions => solution}/[id].delete.ts (100%)
rename server/api/{solutions => solution}/[id].get.ts (100%)
rename server/api/{solutions => solution}/[id].put.ts (94%)
rename server/api/{solutions => solution}/index.get.ts (100%)
rename server/api/{solutions => solution}/index.post.ts (94%)
rename server/api/{stakeholders => stakeholder}/[id].delete.ts (100%)
rename server/api/{stakeholders => stakeholder}/[id].get.ts (93%)
rename server/api/{stakeholders => stakeholder}/[id].put.ts (67%)
rename server/api/{stakeholders => stakeholder}/index.get.ts (100%)
rename server/api/{stakeholders => stakeholder}/index.post.ts (88%)
rename server/api/{system-components => system-component}/[id].delete.ts (100%)
rename server/api/{system-components => system-component}/[id].get.ts (93%)
rename server/api/{system-components => system-component}/[id].put.ts (50%)
create mode 100644 server/api/system-component/index.get.ts
rename server/api/{system-components => system-component}/index.post.ts (75%)
delete mode 100644 server/api/system-components/index.get.ts
rename server/api/{use-cases => use-case}/[id].delete.ts (100%)
rename server/api/{use-cases => use-case}/[id].get.ts (92%)
rename server/api/{use-cases => use-case}/[id].put.ts (82%)
rename server/api/{use-cases => use-case}/index.get.ts (82%)
rename server/api/{use-cases => use-case}/index.post.ts (77%)
rename server/api/{user-stories => user-story}/[id].delete.ts (100%)
rename server/api/{user-stories => user-story}/[id].get.ts (92%)
rename server/api/{user-stories => user-story}/[id].put.ts (77%)
rename server/api/{user-stories => user-story}/index.get.ts (92%)
rename server/api/{user-stories => user-story}/index.post.ts (71%)
create mode 100644 server/utils/groupBy.ts
create mode 100644 utils/snakeCaseToSlug.ts
create mode 100644 utils/snakeCaseToTitle.ts
diff --git a/components/WorkboxDataView.vue b/components/WorkboxDataView.vue
deleted file mode 100644
index 75d72785..00000000
--- a/components/WorkboxDataView.vue
+++ /dev/null
@@ -1,109 +0,0 @@
-
-
-
-
-
-
-
-
- {{ camelCaseToTitle(requirements.type) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/components/XDataTable.vue b/components/XDataTable.vue
index 161b718d..2374d8a3 100644
--- a/components/XDataTable.vue
+++ b/components/XDataTable.vue
@@ -183,7 +183,7 @@ const onEditDialogCancel = () => {
+ :loading="props.loading" stripedRows>
diff --git a/middleware/org-solution-check.global.ts b/middleware/org-solution-check.global.ts
index e83757be..8576375c 100644
--- a/middleware/org-solution-check.global.ts
+++ b/middleware/org-solution-check.global.ts
@@ -7,14 +7,14 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
const { organizationslug, solutionslug } = to.params
if (organizationslug) {
- const organizations = await $fetch('/api/organizations', {
+ const organizations = await $fetch('/api/organization', {
query: { slug: organizationslug }
})
if (!(organizations ?? []).length) {
return navigateTo('/')
} else if (solutionslug) {
- const solutions = await $fetch('/api/solutions', {
+ const solutions = await $fetch('/api/solution', {
query: {
organizationSlug: organizationslug,
slug: solutionslug
diff --git a/migrations/.snapshot-cathedral.json b/migrations/.snapshot-cathedral.json
index 3f44f3d9..ce4f994f 100644
--- a/migrations/.snapshot-cathedral.json
+++ b/migrations/.snapshot-cathedral.json
@@ -1,840 +1,774 @@
{
- "namespaces": [
- "public"
- ],
- "name": "public",
- "tables": [
+ "namespaces": [
+ "public"
+ ],
+ "name": "public",
+ "tables": [
+ {
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "mappedType": "uuid"
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(254)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "length": 254,
+ "mappedType": "string"
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar(254)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "length": 254,
+ "mappedType": "string"
+ },
+ "creation_date": {
+ "name": "creation_date",
+ "type": "timestamptz",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "length": 6,
+ "mappedType": "datetime"
+ },
+ "last_login_date": {
+ "name": "last_login_date",
+ "type": "timestamptz",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "length": 6,
+ "mappedType": "datetime"
+ },
+ "is_system_admin": {
+ "name": "is_system_admin",
+ "type": "boolean",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "mappedType": "boolean"
+ }
+ },
+ "name": "app_user",
+ "schema": "public",
+ "indexes": [
+ {
+ "keyName": "app_user_pkey",
+ "columnNames": [
+ "id"
+ ],
+ "composite": false,
+ "constraint": true,
+ "primary": true,
+ "unique": true
+ }
+ ],
+ "checks": [],
+ "foreignKeys": {},
+ "nativeEnums": {}
+ },
+ {
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "mappedType": "uuid"
+ },
+ "entity_id": {
+ "name": "entity_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "mappedType": "uuid"
+ },
+ "entity_name": {
+ "name": "entity_name",
+ "type": "varchar(255)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "length": 255,
+ "mappedType": "string"
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "enumItems": [
+ "create",
+ "update",
+ "delete",
+ "update_early",
+ "delete_early"
+ ],
+ "mappedType": "enum"
+ },
+ "entity": {
+ "name": "entity",
+ "type": "jsonb",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "mappedType": "json"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamptz",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "length": 6,
+ "mappedType": "datetime"
+ }
+ },
+ "name": "audit_log",
+ "schema": "public",
+ "indexes": [
+ {
+ "keyName": "audit_log_pkey",
+ "columnNames": [
+ "id"
+ ],
+ "composite": false,
+ "constraint": true,
+ "primary": true,
+ "unique": true
+ }
+ ],
+ "checks": [],
+ "foreignKeys": {},
+ "nativeEnums": {}
+ },
+ {
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "mappedType": "uuid"
+ },
+ "req_type": {
+ "name": "req_type",
+ "type": "text",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "enumItems": [
+ "actor",
+ "assumption",
+ "behavior",
+ "component",
+ "constraint",
+ "effect",
+ "environment_component",
+ "example",
+ "functional_behavior",
+ "functionality",
+ "glossary_term",
+ "goal",
+ "hint",
+ "invariant",
+ "justification",
+ "limit",
+ "meta_requirement",
+ "noise",
+ "non_functional_behavior",
+ "obstacle",
+ "organization",
+ "outcome",
+ "parsed_requirement",
+ "person",
+ "product",
+ "requirement",
+ "responsibility",
+ "role",
+ "scenario",
+ "silence",
+ "solution",
+ "stakeholder",
+ "system_component",
+ "task",
+ "test_case",
+ "use_case",
+ "user_story"
+ ],
+ "mappedType": "enum"
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar(100)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "length": 100,
+ "mappedType": "string"
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar(1000)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "length": 1000,
+ "mappedType": "string"
+ },
+ "last_modified": {
+ "name": "last_modified",
+ "type": "timestamptz",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "length": 6,
+ "default": "now()",
+ "mappedType": "datetime"
+ },
+ "modified_by_id": {
+ "name": "modified_by_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "default": "'ac594919-50e3-438a-b9bc-efb8a8654243'",
+ "mappedType": "uuid"
+ },
+ "is_silence": {
+ "name": "is_silence",
+ "type": "boolean",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "default": "false",
+ "mappedType": "boolean"
+ },
+ "priority": {
+ "name": "priority",
+ "type": "text",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "enumItems": [
+ "MUST",
+ "SHOULD",
+ "COULD",
+ "WONT"
+ ],
+ "mappedType": "enum"
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar(254)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "length": 254,
+ "mappedType": "string"
+ },
+ "primary_actor_id": {
+ "name": "primary_actor_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "uuid"
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar(255)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "length": 255,
+ "mappedType": "string"
+ },
+ "segmentation": {
+ "name": "segmentation",
+ "type": "text",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "enumItems": [
+ "Client",
+ "Vendor"
+ ],
+ "mappedType": "enum"
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "enumItems": [
+ "Business Rule",
+ "Physical Law",
+ "Engineering Decision",
+ "Key Stakeholder",
+ "Shadow Influencer",
+ "Fellow Traveler",
+ "Observer"
+ ],
+ "mappedType": "enum"
+ },
+ "availability": {
+ "name": "availability",
+ "type": "int",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "integer"
+ },
+ "influence": {
+ "name": "influence",
+ "type": "int",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "integer"
+ },
+ "scope": {
+ "name": "scope",
+ "type": "varchar(255)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "length": 255,
+ "mappedType": "string"
+ },
+ "level": {
+ "name": "level",
+ "type": "varchar(255)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "length": 255,
+ "mappedType": "string"
+ },
+ "goal_in_context": {
+ "name": "goal_in_context",
+ "type": "varchar(255)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "length": 255,
+ "mappedType": "string"
+ },
+ "precondition_id": {
+ "name": "precondition_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "uuid"
+ },
+ "trigger_id": {
+ "name": "trigger_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "uuid"
+ },
+ "main_success_scenario": {
+ "name": "main_success_scenario",
+ "type": "varchar(255)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "length": 255,
+ "mappedType": "string"
+ },
+ "success_guarantee_id": {
+ "name": "success_guarantee_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "uuid"
+ },
+ "extensions": {
+ "name": "extensions",
+ "type": "varchar(255)",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "length": 255,
+ "mappedType": "string"
+ },
+ "functional_behavior_id": {
+ "name": "functional_behavior_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "uuid"
+ },
+ "outcome_id": {
+ "name": "outcome_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "uuid"
+ }
+ },
+ "name": "requirement",
+ "schema": "public",
+ "indexes": [
{
- "columns": {
- "id": {
- "name": "id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "uuid"
- },
- "name": {
- "name": "name",
- "type": "varchar(254)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "length": 254,
- "mappedType": "string"
- },
- "email": {
- "name": "email",
- "type": "varchar(254)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "length": 254,
- "mappedType": "string"
- },
- "creation_date": {
- "name": "creation_date",
- "type": "timestamptz",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "length": 6,
- "mappedType": "datetime"
- },
- "last_login_date": {
- "name": "last_login_date",
- "type": "timestamptz",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "length": 6,
- "mappedType": "datetime"
- },
- "is_system_admin": {
- "name": "is_system_admin",
- "type": "boolean",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "boolean"
- }
- },
- "name": "app_user",
- "schema": "public",
- "indexes": [
- {
- "keyName": "app_user_pkey",
- "columnNames": [
- "id"
- ],
- "composite": false,
- "constraint": true,
- "primary": true,
- "unique": true
- }
- ],
- "checks": [],
- "foreignKeys": {},
- "nativeEnums": {}
+ "columnNames": [
+ "req_type"
+ ],
+ "composite": false,
+ "keyName": "requirement_req_type_index",
+ "constraint": false,
+ "primary": false,
+ "unique": false
},
{
- "columns": {
- "id": {
- "name": "id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "uuid"
- },
- "entity_id": {
- "name": "entity_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "uuid"
- },
- "entity_name": {
- "name": "entity_name",
- "type": "varchar(255)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "length": 255,
- "mappedType": "string"
- },
- "type": {
- "name": "type",
- "type": "text",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "enumItems": [
- "create",
- "update",
- "delete",
- "update_early",
- "delete_early"
- ],
- "mappedType": "enum"
- },
- "entity": {
- "name": "entity",
- "type": "jsonb",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "json"
- },
- "created_at": {
- "name": "created_at",
- "type": "timestamptz",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "length": 6,
- "mappedType": "datetime"
- }
- },
- "name": "audit_log",
- "schema": "public",
- "indexes": [
- {
- "keyName": "audit_log_pkey",
- "columnNames": [
- "id"
- ],
- "composite": false,
- "constraint": true,
- "primary": true,
- "unique": true
- }
- ],
- "checks": [],
- "foreignKeys": {},
- "nativeEnums": {}
+ "columnNames": [
+ "slug"
+ ],
+ "composite": false,
+ "keyName": "requirement_slug_unique",
+ "constraint": true,
+ "primary": false,
+ "unique": true
+ },
+ {
+ "keyName": "requirement_pkey",
+ "columnNames": [
+ "id"
+ ],
+ "composite": false,
+ "constraint": true,
+ "primary": true,
+ "unique": true
+ }
+ ],
+ "checks": [],
+ "foreignKeys": {
+ "requirement_modified_by_id_foreign": {
+ "constraintName": "requirement_modified_by_id_foreign",
+ "columnNames": [
+ "modified_by_id"
+ ],
+ "localTableName": "public.requirement",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.app_user",
+ "updateRule": "cascade"
+ },
+ "requirement_primary_actor_id_foreign": {
+ "constraintName": "requirement_primary_actor_id_foreign",
+ "columnNames": [
+ "primary_actor_id"
+ ],
+ "localTableName": "public.requirement",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.requirement",
+ "deleteRule": "set null",
+ "updateRule": "cascade"
},
+ "requirement_precondition_id_foreign": {
+ "constraintName": "requirement_precondition_id_foreign",
+ "columnNames": [
+ "precondition_id"
+ ],
+ "localTableName": "public.requirement",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.requirement",
+ "deleteRule": "set null",
+ "updateRule": "cascade"
+ },
+ "requirement_success_guarantee_id_foreign": {
+ "constraintName": "requirement_success_guarantee_id_foreign",
+ "columnNames": [
+ "success_guarantee_id"
+ ],
+ "localTableName": "public.requirement",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.requirement",
+ "deleteRule": "set null",
+ "updateRule": "cascade"
+ },
+ "requirement_functional_behavior_id_foreign": {
+ "constraintName": "requirement_functional_behavior_id_foreign",
+ "columnNames": [
+ "functional_behavior_id"
+ ],
+ "localTableName": "public.requirement",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.requirement",
+ "deleteRule": "set null",
+ "updateRule": "cascade"
+ },
+ "requirement_outcome_id_foreign": {
+ "constraintName": "requirement_outcome_id_foreign",
+ "columnNames": [
+ "outcome_id"
+ ],
+ "localTableName": "public.requirement",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.requirement",
+ "deleteRule": "set null",
+ "updateRule": "cascade"
+ }
+ },
+ "nativeEnums": {}
+ },
+ {
+ "columns": {
+ "app_user_id": {
+ "name": "app_user_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "mappedType": "uuid"
+ },
+ "organization_id": {
+ "name": "organization_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "mappedType": "uuid"
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "enumItems": [
+ "Organization Admin",
+ "Organization Contributor",
+ "Organization Reader"
+ ],
+ "mappedType": "enum"
+ }
+ },
+ "name": "app_user_organization_role",
+ "schema": "public",
+ "indexes": [
{
- "columns": {
- "id": {
- "name": "id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "uuid"
- },
- "req_type": {
- "name": "req_type",
- "type": "text",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "enumItems": [
- "actor",
- "assumption",
- "behavior",
- "component",
- "constraint",
- "effect",
- "environment_component",
- "example",
- "functional_behavior",
- "functionality",
- "glossary_term",
- "goal",
- "hint",
- "invariant",
- "justification",
- "limit",
- "meta_requirement",
- "noise",
- "non_functional_behavior",
- "obstacle",
- "organization",
- "outcome",
- "parsed_requirement",
- "person",
- "product",
- "requirement",
- "responsibility",
- "role",
- "scenario",
- "silence",
- "solution",
- "stakeholder",
- "system_component",
- "task",
- "test_case",
- "use_case",
- "user_story"
- ],
- "mappedType": "enum"
- },
- "name": {
- "name": "name",
- "type": "varchar(100)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "length": 100,
- "mappedType": "string"
- },
- "description": {
- "name": "description",
- "type": "varchar(1000)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "length": 1000,
- "mappedType": "string"
- },
- "last_modified": {
- "name": "last_modified",
- "type": "timestamptz",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "length": 6,
- "default": "now()",
- "mappedType": "datetime"
- },
- "modified_by_id": {
- "name": "modified_by_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "default": "'ac594919-50e3-438a-b9bc-efb8a8654243'",
- "mappedType": "uuid"
- },
- "is_silence": {
- "name": "is_silence",
- "type": "boolean",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "default": "false",
- "mappedType": "boolean"
- },
- "priority": {
- "name": "priority",
- "type": "text",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "enumItems": [
- "MUST",
- "SHOULD",
- "COULD",
- "WONT"
- ],
- "mappedType": "enum"
- },
- "parent_component_id": {
- "name": "parent_component_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "uuid"
- },
- "email": {
- "name": "email",
- "type": "varchar(254)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "length": 254,
- "mappedType": "string"
- },
- "primary_actor_id": {
- "name": "primary_actor_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "uuid"
- },
- "slug": {
- "name": "slug",
- "type": "varchar(255)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "length": 255,
- "mappedType": "string"
- },
- "segmentation": {
- "name": "segmentation",
- "type": "text",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "enumItems": [
- "Client",
- "Vendor"
- ],
- "mappedType": "enum"
- },
- "category": {
- "name": "category",
- "type": "text",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "enumItems": [
- "Business Rule",
- "Physical Law",
- "Engineering Decision",
- "Key Stakeholder",
- "Shadow Influencer",
- "Fellow Traveler",
- "Observer"
- ],
- "mappedType": "enum"
- },
- "availability": {
- "name": "availability",
- "type": "int",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "integer"
- },
- "influence": {
- "name": "influence",
- "type": "int",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "integer"
- },
- "parent_component_1_id": {
- "name": "parent_component_1_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "uuid"
- },
- "scope": {
- "name": "scope",
- "type": "varchar(255)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "length": 255,
- "mappedType": "string"
- },
- "level": {
- "name": "level",
- "type": "varchar(255)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "length": 255,
- "mappedType": "string"
- },
- "goal_in_context": {
- "name": "goal_in_context",
- "type": "varchar(255)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "length": 255,
- "mappedType": "string"
- },
- "precondition_id": {
- "name": "precondition_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "uuid"
- },
- "trigger_id": {
- "name": "trigger_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "uuid"
- },
- "main_success_scenario": {
- "name": "main_success_scenario",
- "type": "varchar(255)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "length": 255,
- "mappedType": "string"
- },
- "success_guarantee_id": {
- "name": "success_guarantee_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "uuid"
- },
- "extensions": {
- "name": "extensions",
- "type": "varchar(255)",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "length": 255,
- "mappedType": "string"
- },
- "functional_behavior_id": {
- "name": "functional_behavior_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "uuid"
- },
- "outcome_id": {
- "name": "outcome_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "uuid"
- }
- },
- "name": "requirement",
- "schema": "public",
- "indexes": [
- {
- "columnNames": [
- "req_type"
- ],
- "composite": false,
- "keyName": "requirement_req_type_index",
- "constraint": false,
- "primary": false,
- "unique": false
- },
- {
- "columnNames": [
- "slug"
- ],
- "composite": false,
- "keyName": "requirement_slug_unique",
- "constraint": true,
- "primary": false,
- "unique": true
- },
- {
- "keyName": "requirement_pkey",
- "columnNames": [
- "id"
- ],
- "composite": false,
- "constraint": true,
- "primary": true,
- "unique": true
- }
- ],
- "checks": [],
- "foreignKeys": {
- "requirement_modified_by_id_foreign": {
- "constraintName": "requirement_modified_by_id_foreign",
- "columnNames": [
- "modified_by_id"
- ],
- "localTableName": "public.requirement",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.app_user",
- "updateRule": "cascade"
- },
- "requirement_parent_component_id_foreign": {
- "constraintName": "requirement_parent_component_id_foreign",
- "columnNames": [
- "parent_component_id"
- ],
- "localTableName": "public.requirement",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "deleteRule": "set null",
- "updateRule": "cascade"
- },
- "requirement_primary_actor_id_foreign": {
- "constraintName": "requirement_primary_actor_id_foreign",
- "columnNames": [
- "primary_actor_id"
- ],
- "localTableName": "public.requirement",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "deleteRule": "set null",
- "updateRule": "cascade"
- },
- "requirement_parent_component_1_id_foreign": {
- "constraintName": "requirement_parent_component_1_id_foreign",
- "columnNames": [
- "parent_component_1_id"
- ],
- "localTableName": "public.requirement",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "deleteRule": "set null",
- "updateRule": "cascade"
- },
- "requirement_precondition_id_foreign": {
- "constraintName": "requirement_precondition_id_foreign",
- "columnNames": [
- "precondition_id"
- ],
- "localTableName": "public.requirement",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "deleteRule": "set null",
- "updateRule": "cascade"
- },
- "requirement_success_guarantee_id_foreign": {
- "constraintName": "requirement_success_guarantee_id_foreign",
- "columnNames": [
- "success_guarantee_id"
- ],
- "localTableName": "public.requirement",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "deleteRule": "set null",
- "updateRule": "cascade"
- },
- "requirement_functional_behavior_id_foreign": {
- "constraintName": "requirement_functional_behavior_id_foreign",
- "columnNames": [
- "functional_behavior_id"
- ],
- "localTableName": "public.requirement",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "deleteRule": "set null",
- "updateRule": "cascade"
- },
- "requirement_outcome_id_foreign": {
- "constraintName": "requirement_outcome_id_foreign",
- "columnNames": [
- "outcome_id"
- ],
- "localTableName": "public.requirement",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "deleteRule": "set null",
- "updateRule": "cascade"
- }
- },
- "nativeEnums": {}
+ "keyName": "app_user_organization_role_pkey",
+ "columnNames": [
+ "app_user_id",
+ "organization_id",
+ "role"
+ ],
+ "composite": true,
+ "constraint": true,
+ "primary": true,
+ "unique": true
+ }
+ ],
+ "checks": [],
+ "foreignKeys": {
+ "app_user_organization_role_app_user_id_foreign": {
+ "constraintName": "app_user_organization_role_app_user_id_foreign",
+ "columnNames": [
+ "app_user_id"
+ ],
+ "localTableName": "public.app_user_organization_role",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.app_user",
+ "updateRule": "cascade"
},
+ "app_user_organization_role_organization_id_foreign": {
+ "constraintName": "app_user_organization_role_organization_id_foreign",
+ "columnNames": [
+ "organization_id"
+ ],
+ "localTableName": "public.app_user_organization_role",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.requirement",
+ "updateRule": "cascade"
+ }
+ },
+ "nativeEnums": {}
+ },
+ {
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "mappedType": "uuid"
+ },
+ "left_id": {
+ "name": "left_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "uuid"
+ },
+ "right_id": {
+ "name": "right_id",
+ "type": "uuid",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": true,
+ "mappedType": "uuid"
+ },
+ "rel_type": {
+ "name": "rel_type",
+ "type": "text",
+ "unsigned": false,
+ "autoincrement": false,
+ "primary": false,
+ "nullable": false,
+ "enumItems": [
+ "belongs",
+ "characterizes",
+ "constrains",
+ "contradicts",
+ "details",
+ "disjoins",
+ "duplicates",
+ "excepts",
+ "explains",
+ "extends",
+ "follows",
+ "repeats",
+ "shares"
+ ],
+ "mappedType": "enum"
+ }
+ },
+ "name": "requirement_relation",
+ "schema": "public",
+ "indexes": [
{
- "columns": {
- "app_user_id": {
- "name": "app_user_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "uuid"
- },
- "organization_id": {
- "name": "organization_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "uuid"
- },
- "role": {
- "name": "role",
- "type": "text",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "enumItems": [
- "Organization Admin",
- "Organization Contributor",
- "Organization Reader"
- ],
- "mappedType": "enum"
- }
- },
- "name": "app_user_organization_role",
- "schema": "public",
- "indexes": [
- {
- "keyName": "app_user_organization_role_pkey",
- "columnNames": [
- "app_user_id",
- "organization_id",
- "role"
- ],
- "composite": true,
- "constraint": true,
- "primary": true,
- "unique": true
- }
- ],
- "checks": [],
- "foreignKeys": {
- "app_user_organization_role_app_user_id_foreign": {
- "constraintName": "app_user_organization_role_app_user_id_foreign",
- "columnNames": [
- "app_user_id"
- ],
- "localTableName": "public.app_user_organization_role",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.app_user",
- "updateRule": "cascade"
- },
- "app_user_organization_role_organization_id_foreign": {
- "constraintName": "app_user_organization_role_organization_id_foreign",
- "columnNames": [
- "organization_id"
- ],
- "localTableName": "public.app_user_organization_role",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "updateRule": "cascade"
- }
- },
- "nativeEnums": {}
+ "columnNames": [
+ "rel_type"
+ ],
+ "composite": false,
+ "keyName": "requirement_relation_rel_type_index",
+ "constraint": false,
+ "primary": false,
+ "unique": false
},
{
- "columns": {
- "id": {
- "name": "id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "uuid"
- },
- "left_id": {
- "name": "left_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "uuid"
- },
- "right_id": {
- "name": "right_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "mappedType": "uuid"
- },
- "rel_type": {
- "name": "rel_type",
- "type": "text",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": false,
- "enumItems": [
- "belongs",
- "characterizes",
- "constrains",
- "contradicts",
- "details",
- "disjoins",
- "duplicates",
- "excepts",
- "explains",
- "extends",
- "follows",
- "repeats",
- "shares"
- ],
- "mappedType": "enum"
- },
- "left_1_id": {
- "name": "left_1_id",
- "type": "uuid",
- "unsigned": false,
- "autoincrement": false,
- "primary": false,
- "nullable": true,
- "mappedType": "uuid"
- }
- },
- "name": "requirement_relation",
- "schema": "public",
- "indexes": [
- {
- "columnNames": [
- "rel_type"
- ],
- "composite": false,
- "keyName": "requirement_relation_rel_type_index",
- "constraint": false,
- "primary": false,
- "unique": false
- },
- {
- "keyName": "requirement_relation_pkey",
- "columnNames": [
- "id"
- ],
- "composite": false,
- "constraint": true,
- "primary": true,
- "unique": true
- }
- ],
- "checks": [],
- "foreignKeys": {
- "requirement_relation_left_id_foreign": {
- "constraintName": "requirement_relation_left_id_foreign",
- "columnNames": [
- "left_id"
- ],
- "localTableName": "public.requirement_relation",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "updateRule": "cascade"
- },
- "requirement_relation_right_id_foreign": {
- "constraintName": "requirement_relation_right_id_foreign",
- "columnNames": [
- "right_id"
- ],
- "localTableName": "public.requirement_relation",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "updateRule": "cascade"
- },
- "requirement_relation_left_1_id_foreign": {
- "constraintName": "requirement_relation_left_1_id_foreign",
- "columnNames": [
- "left_1_id"
- ],
- "localTableName": "public.requirement_relation",
- "referencedColumnNames": [
- "id"
- ],
- "referencedTableName": "public.requirement",
- "deleteRule": "set null",
- "updateRule": "cascade"
- }
- },
- "nativeEnums": {}
+ "keyName": "requirement_relation_pkey",
+ "columnNames": [
+ "id"
+ ],
+ "composite": false,
+ "constraint": true,
+ "primary": true,
+ "unique": true
+ }
+ ],
+ "checks": [],
+ "foreignKeys": {
+ "requirement_relation_left_id_foreign": {
+ "constraintName": "requirement_relation_left_id_foreign",
+ "columnNames": [
+ "left_id"
+ ],
+ "localTableName": "public.requirement_relation",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.requirement",
+ "deleteRule": "cascade"
+ },
+ "requirement_relation_right_id_foreign": {
+ "constraintName": "requirement_relation_right_id_foreign",
+ "columnNames": [
+ "right_id"
+ ],
+ "localTableName": "public.requirement_relation",
+ "referencedColumnNames": [
+ "id"
+ ],
+ "referencedTableName": "public.requirement",
+ "deleteRule": "cascade"
}
- ],
- "nativeEnums": {}
-}
\ No newline at end of file
+ },
+ "nativeEnums": {}
+ }
+ ],
+ "nativeEnums": {}
+}
diff --git a/migrations/Migration20241020164456.ts b/migrations/Migration20241020164456.ts
new file mode 100644
index 00000000..4962102f
--- /dev/null
+++ b/migrations/Migration20241020164456.ts
@@ -0,0 +1,236 @@
+import { Migration } from '@mikro-orm/migrations';
+
+export class Migration20241020164456 extends Migration {
+
+ override async up(): Promise {
+ this.addSql(`alter table "app_user_organization_role" drop constraint if exists "app_user_organization_role_organization_id_foreign";`);
+
+ this.addSql(`alter table "solution" drop constraint if exists "solution_organization_id_foreign";`);
+
+ this.addSql(`alter table "requirement" drop constraint if exists "requirement_solution_id_foreign";`);
+
+ this.addSql(`alter table "requirement" drop constraint if exists "requirement_req_type_check";`);
+
+ this.addSql(`alter table "requirement" drop constraint if exists "requirement_follows_id_foreign";`);
+
+ this.addSql(`alter table "app_user_organization_role" drop constraint if exists "app_user_organization_role_organization_id_foreign";`);
+
+ this.addSql(`alter table "requirement" add column "slug" varchar(255) null;`);
+ this.addSql(`alter table "requirement" alter column "name" type varchar(100) using ("name"::varchar(100));`);
+ this.addSql(`alter table "requirement" add constraint "requirement_req_type_check" check("req_type" in ('actor', 'assumption', 'behavior', 'component', 'constraint', 'effect', 'environment_component', 'example', 'functional_behavior', 'functionality', 'glossary_term', 'goal', 'hint', 'invariant', 'justification', 'limit', 'meta_requirement', 'noise', 'non_functional_behavior', 'obstacle', 'organization', 'outcome', 'parsed_requirement', 'person', 'product', 'requirement', 'responsibility', 'role', 'scenario', 'silence', 'solution', 'stakeholder', 'system_component', 'task', 'test_case', 'use_case', 'user_story'));`);
+ this.addSql(`alter table "requirement" rename column "statement" to "description";`);
+ this.addSql(`alter table "requirement" add constraint "requirement_slug_unique" unique ("slug");`);
+
+ // Postgres v16 does not support uuid v7
+ // source: https://gist.github.com/fabiolimace/515a0440e3e40efeb234e12644a6a346#file-uuidv7-sql
+ this.addSql(`
+ create or replace function uuid7() returns uuid as $$
+ declare
+ begin
+ return uuid7(clock_timestamp());
+ end $$ language plpgsql;
+
+ create or replace function uuid7(p_timestamp timestamp with time zone) returns uuid as $$
+ declare
+
+ v_time double precision := null;
+
+ v_unix_t bigint := null;
+ v_rand_a bigint := null;
+ v_rand_b bigint := null;
+
+ v_unix_t_hex varchar := null;
+ v_rand_a_hex varchar := null;
+ v_rand_b_hex varchar := null;
+
+ c_milli double precision := 10^3; -- 1 000
+ c_micro double precision := 10^6; -- 1 000 000
+ c_scale double precision := 4.096; -- 4.0 * (1024 / 1000)
+
+ c_version bigint := x'0000000000007000'::bigint; -- RFC-9562 version: b'0111...'
+ c_variant bigint := x'8000000000000000'::bigint; -- RFC-9562 variant: b'10xx...'
+
+ begin
+
+ v_time := extract(epoch from p_timestamp);
+
+ v_unix_t := trunc(v_time * c_milli);
+ v_rand_a := trunc((v_time * c_micro - v_unix_t * c_milli) * c_scale);
+ v_rand_b := trunc(random() * 2^30)::bigint << 32 | trunc(random() * 2^32)::bigint;
+
+ v_unix_t_hex := lpad(to_hex(v_unix_t), 12, '0');
+ v_rand_a_hex := lpad(to_hex((v_rand_a | c_version)::bigint), 4, '0');
+ v_rand_b_hex := lpad(to_hex((v_rand_b | c_variant)::bigint), 16, '0');
+
+ return (v_unix_t_hex || v_rand_a_hex || v_rand_b_hex)::uuid;
+
+ end $$ language plpgsql;
+ `);
+
+ this.addSql(`alter table "requirement_relation" drop constraint if exists "requirement_relation_left_id_unique";`);
+ this.addSql(`alter table "requirement_relation" drop constraint if exists "requirement_relation_right_id_unique";`);
+ this.addSql(`alter table "requirement_relation" drop constraint if exists "requirement_relation_left_1_id_unique";`);
+
+ // Copy records from "organization" table to "requirement" table
+ this.addSql(`
+ insert into "requirement" (id, description, name, slug, req_type, solution_id)
+ select id, description, name, slug, 'organization' as req_type, '00000000-0000-0000-0000-000000000000' as solution_id
+ from "organization";
+ `);
+
+ // Copy records from "solution" table to "requirement" table
+ // Note the abuse of "organization_id" as "solution_id"
+ // this is because it will later be generalized to the "requirement_relation" table as "belongs"
+ this.addSql(`
+ insert into "requirement" (id, description, name, slug, req_type, solution_id)
+ select id, description, name, slug, 'solution' as req_type, organization_id as solution_id
+ from "solution";
+ `);
+
+ // Migrate non-null "follows_id" entries to "requirement_relation" table
+ this.addSql(`
+ insert into "requirement_relation" (id, left_id, right_id, rel_type)
+ select uuid7(), id, follows_id, 'follows'
+ from "requirement"
+ where follows_id is not null;
+ `);
+
+ // Migrate "solution_id" entries to "requirement_relation" table, ignoring empty UUIDs and NULLs
+ this.addSql(`
+ insert into "requirement_relation" (id, left_id, right_id, rel_type)
+ select uuid7(), id, solution_id, 'belongs'
+ from "requirement"
+ where solution_id is not null and solution_id != '00000000-0000-0000-0000-000000000000';
+ `);
+
+ this.addSql(`drop table if exists "organization" cascade;`);
+ this.addSql(`drop table if exists "solution" cascade;`);
+
+ this.addSql(`drop function uuid7();`);
+
+ this.addSql(`alter table "requirement" drop column "solution_id", drop column "follows_id";`);
+
+ this.addSql(`alter table "app_user_organization_role" add constraint "app_user_organization_role_organization_id_foreign" foreign key ("organization_id") references "requirement" ("id") on update cascade;`);
+ }
+
+ override async down(): Promise {
+ // Recreate "organization" and "solution" tables
+ this.addSql(`
+ create table "organization" (
+ id uuid primary key,
+ name varchar(255) not null,
+ description text,
+ slug varchar(255) unique
+ );
+ `);
+
+ this.addSql(`
+ create table "solution" (
+ id uuid primary key,
+ name varchar(255) not null,
+ description text,
+ slug varchar(255) unique,
+ organization_id uuid references "organization" ("id") on delete set null
+ );
+ `);
+
+ // Restore "solution_id" and "follows_id" columns to the "requirement" table
+ this.addSql(`alter table "requirement" add column "solution_id" uuid;`);
+ this.addSql(`alter table "requirement" add column "follows_id" uuid;`);
+
+ // Migrate "belongs" relationships back to "solution_id" column
+ this.addSql(`
+ update "requirement" r
+ set solution_id = rr.right_id
+ from "requirement_relation" rr
+ where rr.left_id = r.id and rr.rel_type = 'belongs';
+ `);
+
+ // Migrate "follows" relationships back to "follows_id" column
+ this.addSql(`
+ update "requirement" r
+ set follows_id = rr.right_id
+ from "requirement_relation" rr
+ where rr.left_id = r.id and rr.rel_type = 'follows';
+ `);
+
+ // Insert back data into "organization" table
+ this.addSql(`
+ insert into "organization" (id, name, description, slug)
+ select id, name, description, slug
+ from "requirement"
+ where req_type = 'organization';
+ `);
+
+ // Insert back data into "solution" table
+ this.addSql(`
+ insert into "solution" (id, name, description, slug, organization_id)
+ select id, name, description, slug, solution_id
+ from "requirement"
+ where req_type = 'solution';
+ `);
+
+ // Drop the "requirement_relation" entries related to follows and belongs
+ this.addSql(`
+ delete from "requirement_relation"
+ where rel_type in ('follows', 'belongs');
+ `);
+
+ // Drop constraints and columns added to the "requirement" table
+ this.addSql(`alter table "requirement" drop constraint if exists "requirement_slug_unique";`);
+ this.addSql(`alter table "requirement" drop column if exists "slug";`);
+ this.addSql(`alter table "requirement" rename column "description" to "statement";`);
+
+ // Restore original length of the "name" column
+ this.addSql(`alter table "requirement" alter column "name" type varchar(255) using ("name"::varchar(255));`);
+
+ // Drop the added req_type check constraint
+ this.addSql(`alter table "requirement" drop constraint if exists "requirement_req_type_check";`);
+
+ // Drop the re-created foreign key constraint on "app_user_organization_role"
+ this.addSql(`
+ alter table "app_user_organization_role" drop constraint if exists "app_user_organization_role_organization_id_foreign";
+ `);
+
+ // Restore the original foreign key constraints
+ this.addSql(`
+ alter table "app_user_organization_role"
+ add constraint "app_user_organization_role_organization_id_foreign"
+ foreign key ("organization_id") references "organization" ("id") on update cascade;
+ `);
+
+ this.addSql(`
+ alter table "solution"
+ add constraint "solution_organization_id_foreign"
+ foreign key ("organization_id") references "organization" ("id") on delete set null;
+ `);
+
+ this.addSql(`
+ alter table "requirement"
+ add constraint "requirement_solution_id_foreign"
+ foreign key ("solution_id") references "solution" ("id") on delete set null;
+ `);
+
+ this.addSql(`
+ alter table "requirement"
+ add constraint "requirement_follows_id_foreign"
+ foreign key ("follows_id") references "requirement" ("id") on delete set null;
+ `);
+
+ // Recreate unique constraints for "requirement_relation" if they existed before
+ this.addSql(`
+ alter table "requirement_relation"
+ add constraint "requirement_relation_left_id_unique" unique ("left_id");
+ `);
+
+ this.addSql(`
+ alter table "requirement_relation"
+ add constraint "requirement_relation_right_id_unique" unique ("right_id");
+ `);
+
+ this.addSql(`
+ alter table "requirement_relation"
+ add constraint "requirement_relation_left_1_id_unique" unique ("left_id");
+ `);
+ }
+}
diff --git a/migrations/Migration20241022160037.ts b/migrations/Migration20241022160037.ts
new file mode 100644
index 00000000..dcc921ea
--- /dev/null
+++ b/migrations/Migration20241022160037.ts
@@ -0,0 +1,104 @@
+import { Migration } from '@mikro-orm/migrations';
+
+export class Migration20241022160037 extends Migration {
+
+ override async up(): Promise {
+ this.addSql(`alter table "requirement" drop constraint "requirement_parent_component_id_foreign";`);
+ this.addSql(`alter table "requirement" drop constraint "requirement_parent_component_1_id_foreign";`);
+
+ this.addSql(`alter table "requirement_relation" drop constraint "requirement_relation_left_1_id_foreign";`);
+ this.addSql(`alter table "requirement_relation" drop constraint "requirement_relation_left_id_foreign";`);
+ this.addSql(`alter table "requirement_relation" drop constraint "requirement_relation_right_id_foreign";`);
+
+ // Postgres v16 does not support uuid v7
+ // source: https://gist.github.com/fabiolimace/515a0440e3e40efeb234e12644a6a346#file-uuidv7-sql
+ this.addSql(`
+ create or replace function uuid7() returns uuid as $$
+ declare
+ begin
+ return uuid7(clock_timestamp());
+ end $$ language plpgsql;
+
+ create or replace function uuid7(p_timestamp timestamp with time zone) returns uuid as $$
+ declare
+
+ v_time double precision := null;
+
+ v_unix_t bigint := null;
+ v_rand_a bigint := null;
+ v_rand_b bigint := null;
+
+ v_unix_t_hex varchar := null;
+ v_rand_a_hex varchar := null;
+ v_rand_b_hex varchar := null;
+
+ c_milli double precision := 10^3; -- 1 000
+ c_micro double precision := 10^6; -- 1 000 000
+ c_scale double precision := 4.096; -- 4.0 * (1024 / 1000)
+
+ c_version bigint := x'0000000000007000'::bigint; -- RFC-9562 version: b'0111...'
+ c_variant bigint := x'8000000000000000'::bigint; -- RFC-9562 variant: b'10xx...'
+
+ begin
+
+ v_time := extract(epoch from p_timestamp);
+
+ v_unix_t := trunc(v_time * c_milli);
+ v_rand_a := trunc((v_time * c_micro - v_unix_t * c_milli) * c_scale);
+ v_rand_b := trunc(random() * 2^30)::bigint << 32 | trunc(random() * 2^32)::bigint;
+
+ v_unix_t_hex := lpad(to_hex(v_unix_t), 12, '0');
+ v_rand_a_hex := lpad(to_hex((v_rand_a | c_version)::bigint), 4, '0');
+ v_rand_b_hex := lpad(to_hex((v_rand_b | c_variant)::bigint), 16, '0');
+
+ return (v_unix_t_hex || v_rand_a_hex || v_rand_b_hex)::uuid;
+
+ end $$ language plpgsql;
+ `);
+
+ // migrate non-null parent_component_id entries to "requirement_relation" table as rel_type = 'belongs'
+ this.addSql(`
+ insert into "requirement_relation" ("id", "left_id", "right_id", "rel_type")
+ select uuid7(), "id", "parent_component_id", 'belongs'
+ from "requirement"
+ where "parent_component_id" is not null;
+ `);
+
+ this.addSql(`drop function uuid7();`);
+
+ this.addSql(`alter table "requirement" drop column "parent_component_id", drop column "parent_component_1_id";`);
+
+ this.addSql(`alter table "requirement_relation" drop column "left_1_id";`);
+
+ this.addSql(`alter table "requirement_relation" alter column "left_id" drop default;`);
+ this.addSql(`alter table "requirement_relation" alter column "left_id" type uuid using ("left_id"::text::uuid);`);
+ this.addSql(`alter table "requirement_relation" alter column "left_id" drop not null;`);
+ this.addSql(`alter table "requirement_relation" alter column "right_id" drop default;`);
+ this.addSql(`alter table "requirement_relation" alter column "right_id" type uuid using ("right_id"::text::uuid);`);
+ this.addSql(`alter table "requirement_relation" alter column "right_id" drop not null;`);
+ this.addSql(`alter table "requirement_relation" add constraint "requirement_relation_left_id_foreign" foreign key ("left_id") references "requirement" ("id") on delete cascade;`);
+ this.addSql(`alter table "requirement_relation" add constraint "requirement_relation_right_id_foreign" foreign key ("right_id") references "requirement" ("id") on delete cascade;`);
+ }
+
+ override async down(): Promise {
+ this.addSql(`alter table "requirement_relation" drop constraint "requirement_relation_left_id_foreign";`);
+ this.addSql(`alter table "requirement_relation" drop constraint "requirement_relation_right_id_foreign";`);
+
+ this.addSql(`alter table "requirement" add column "parent_component_id" uuid null, add column "parent_component_1_id" uuid null;`);
+
+ this.addSql(`alter table "requirement" add constraint "requirement_parent_component_id_foreign" foreign key ("parent_component_id") references "requirement" ("id") on update cascade on delete set null;`);
+ this.addSql(`alter table "requirement" add constraint "requirement_parent_component_1_id_foreign" foreign key ("parent_component_1_id") references "requirement" ("id") on update cascade on delete set null;`);
+
+ this.addSql(`alter table "requirement_relation" add column "left_1_id" uuid null;`);
+ this.addSql(`alter table "requirement_relation" alter column "left_id" drop default;`);
+ this.addSql(`alter table "requirement_relation" alter column "left_id" type uuid using ("left_id"::text::uuid);`);
+ this.addSql(`alter table "requirement_relation" alter column "left_id" set not null;`);
+ this.addSql(`alter table "requirement_relation" alter column "right_id" drop default;`);
+ this.addSql(`alter table "requirement_relation" alter column "right_id" type uuid using ("right_id"::text::uuid);`);
+ this.addSql(`alter table "requirement_relation" alter column "right_id" set not null;`);
+ this.addSql(`alter table "requirement_relation" add constraint "requirement_relation_left_1_id_foreign" foreign key ("left_1_id") references "requirement" ("id") on update cascade on delete set null;`);
+ this.addSql(`alter table "requirement_relation" add constraint "requirement_relation_left_id_foreign" foreign key ("left_id") references "requirement" ("id") on update cascade;`);
+ this.addSql(`alter table "requirement_relation" add constraint "requirement_relation_right_id_foreign" foreign key ("right_id") references "requirement" ("id") on update cascade;`);
+ }
+
+}
diff --git a/pages/index.client.vue b/pages/index.client.vue
index eccbd196..5b9fc983 100644
--- a/pages/index.client.vue
+++ b/pages/index.client.vue
@@ -2,7 +2,7 @@
definePageMeta({ name: 'Home' })
const router = useRouter(),
- { status, data: organizations, refresh, error: getOrgError } = await useFetch('/api/organizations'),
+ { status, data: organizations, refresh, error: getOrgError } = await useFetch('/api/organization'),
confirm = useConfirm(),
{ $eventBus } = useNuxtApp()
@@ -17,7 +17,7 @@ const handleDelete = async (organization: { id: string, name: string }) => {
rejectLabel: 'Cancel',
acceptLabel: 'Delete',
accept: async () => {
- await $fetch(`/api/organizations/${organization.id}`, {
+ await $fetch(`/api/organization/${organization.id}`, {
method: 'delete'
}).catch((e) => $eventBus.$emit('page-error', e))
refresh()
diff --git a/pages/new-organization.vue b/pages/new-organization.vue
index ee4aba56..2968cf8e 100644
--- a/pages/new-organization.vue
+++ b/pages/new-organization.vue
@@ -10,7 +10,7 @@ const router = useRouter(),
const createOrganization = async () => {
try {
- const organizationId = (await $fetch('/api/organizations', {
+ const organizationId = (await $fetch('/api/organization', {
method: 'post',
body: {
name: name.value,
@@ -19,7 +19,7 @@ const createOrganization = async () => {
}).catch((e) => $eventBus.$emit('page-error', e)));
if (organizationId) {
- const newOrganization = (await $fetch(`/api/organizations/${organizationId}`));
+ const newOrganization = (await $fetch(`/api/organization/${organizationId}`));
router.push({ name: 'Organization', params: { organizationslug: newOrganization?.slug } });
} else {
$eventBus.$emit('page-error', 'Failed to create organization. No organization ID returned.');
diff --git a/pages/o/[organization-slug]/[solution-slug]/edit-entry.client.vue b/pages/o/[organization-slug]/[solution-slug]/edit-entry.client.vue
index 9dbf57ab..00356b21 100644
--- a/pages/o/[organization-slug]/[solution-slug]/edit-entry.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/edit-entry.client.vue
@@ -6,7 +6,7 @@ const route = useRoute('Edit Solution'),
{ $eventBus } = useNuxtApp(),
{ organizationslug, solutionslug } = route.params,
router = useRouter(),
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions/`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution/`, {
query: {
organizationSlug: organizationslug,
slug: solutionslug
@@ -19,7 +19,7 @@ if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value);
const updateSolution = async () => {
- await $fetch(`/api/solutions/${solution.value.id}`, {
+ await $fetch(`/api/solution/${solution.value.id}`, {
method: 'PUT',
body: {
name: solution.value.name,
diff --git a/pages/o/[organization-slug]/[solution-slug]/environment/assumptions.client.vue b/pages/o/[organization-slug]/[solution-slug]/environment/assumptions.client.vue
index 1e059cd7..5158410f 100644
--- a/pages/o/[organization-slug]/[solution-slug]/environment/assumptions.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/environment/assumptions.client.vue
@@ -7,7 +7,7 @@ definePageMeta({ name: 'Assumptions' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Assumptions').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
organizationSlug: organizationslug,
slug: solutionslug
@@ -18,7 +18,7 @@ const { $eventBus } = useNuxtApp(),
if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value);
-const { data: assumptions, refresh, status, error: getAssumptionsError } = await useFetch(`/api/assumptions`, {
+const { data: assumptions, refresh, status, error: getAssumptionsError } = await useFetch(`/api/assumption`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -30,7 +30,7 @@ if (getAssumptionsError.value)
$eventBus.$emit('page-error', getAssumptionsError.value);
const onCreate = async (data: Assumption) => {
- await $fetch(`/api/assumptions`, {
+ await $fetch(`/api/assumption`, {
method: 'post',
body: {
name: data.name,
@@ -43,7 +43,7 @@ const onCreate = async (data: Assumption) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/assumptions/${id}`, {
+ await $fetch(`/api/assumption/${id}`, {
method: 'delete',
body: { solutionId }
})
@@ -53,7 +53,7 @@ const onDelete = async (id: string) => {
}
const onUpdate = async (data: Assumption) => {
- await $fetch(`/api/assumptions/${data.id}`, {
+ await $fetch(`/api/assumption/${data.id}`, {
method: 'put',
body: {
name: data.name,
diff --git a/pages/o/[organization-slug]/[solution-slug]/environment/components.client.vue b/pages/o/[organization-slug]/[solution-slug]/environment/components.client.vue
index af0b9661..6a659848 100644
--- a/pages/o/[organization-slug]/[solution-slug]/environment/components.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/environment/components.client.vue
@@ -6,14 +6,14 @@ definePageMeta({ name: 'Environment Components' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Environment Components').params,
- { data: solutions, error: getSolutionError } = await useFetch('/api/solutions', {
+ { data: solutions, error: getSolutionError } = await useFetch('/api/solution', {
query: {
slug: solutionslug,
organizationSlug: organizationslug
}
}),
solutionId = solutions.value?.[0].id,
- { data: environmentComponents, status, refresh, error: getEnvironmentComponentsError } = await useFetch(`/api/environment-components`, {
+ { data: environmentComponents, status, refresh, error: getEnvironmentComponentsError } = await useFetch(`/api/environment-component`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -28,7 +28,7 @@ if (getEnvironmentComponentsError.value)
$eventBus.$emit('page-error', getEnvironmentComponentsError.value)
const onCreate = async (data: EnvironmentComponent) => {
- await $fetch(`/api/environment-components`, {
+ await $fetch(`/api/environment-component`, {
method: 'POST',
body: {
name: data.name,
@@ -41,7 +41,7 @@ const onCreate = async (data: EnvironmentComponent) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/environment-components/${id}`, {
+ await $fetch(`/api/environment-component/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
@@ -49,7 +49,7 @@ const onDelete = async (id: string) => {
}
const onUpdate = async (data: EnvironmentComponent) => {
- await $fetch(`/api/environment-components/${data.id}`, {
+ await $fetch(`/api/environment-component/${data.id}`, {
method: 'PUT',
body: {
name: data.name,
diff --git a/pages/o/[organization-slug]/[solution-slug]/environment/constraints.client.vue b/pages/o/[organization-slug]/[solution-slug]/environment/constraints.client.vue
index d2661f06..656eec0c 100644
--- a/pages/o/[organization-slug]/[solution-slug]/environment/constraints.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/environment/constraints.client.vue
@@ -8,7 +8,7 @@ definePageMeta({ name: 'Constraints' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Constraints').params,
- { data: solutions, error: getSolutionError } = await useFetch('/api/solutions', {
+ { data: solutions, error: getSolutionError } = await useFetch('/api/solution', {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -16,7 +16,7 @@ const { $eventBus } = useNuxtApp(),
}),
solution = (solutions.value ?? [])[0],
solutionId = solution.id,
- { data: constraints, status, refresh, error: getConstraintsError } = await useFetch(`/api/constraints`, {
+ { data: constraints, status, refresh, error: getConstraintsError } = await useFetch(`/api/constraint`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -31,7 +31,7 @@ if (getConstraintsError.value)
$eventBus.$emit('page-error', getConstraintsError.value)
const onCreate = async (data: Constraint) => {
- await $fetch(`/api/constraints`, {
+ await $fetch(`/api/constraint`, {
method: 'POST',
body: {
name: data.name,
@@ -45,7 +45,7 @@ const onCreate = async (data: Constraint) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/constraints/${id}`, {
+ await $fetch(`/api/constraint/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
@@ -53,7 +53,7 @@ const onDelete = async (id: string) => {
}
const onUpdate = async (data: Constraint) => {
- await $fetch(`/api/constraints/${data.id}`, {
+ await $fetch(`/api/constraint/${data.id}`, {
method: 'PUT',
body: {
name: data.name,
@@ -71,7 +71,7 @@ const onUpdate = async (data: Constraint) => {
Environmental constraints are the limitations and obligations that
the environment imposes on the project and system.
- (`/api/effects`, {
+const { data: effects, refresh, status, error: getEffectsError } = await useFetch(`/api/effect`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -29,7 +29,7 @@ if (getEffectsError.value)
$eventBus.$emit('page-error', getEffectsError.value)
const onCreate = async (data: Effect) => {
- await $fetch(`/api/effects`, {
+ await $fetch(`/api/effect`, {
method: 'POST',
body: {
name: data.name,
@@ -41,7 +41,7 @@ const onCreate = async (data: Effect) => {
}
const onUpdate = async (data: Effect) => {
- await $fetch(`/api/effects/${data.id}`, {
+ await $fetch(`/api/effect/${data.id}`, {
method: 'PUT',
body: {
name: data.name,
@@ -54,7 +54,7 @@ const onUpdate = async (data: Effect) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/effects/${id}`, {
+ await $fetch(`/api/effect/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
diff --git a/pages/o/[organization-slug]/[solution-slug]/environment/glossary.client.vue b/pages/o/[organization-slug]/[solution-slug]/environment/glossary.client.vue
index d0fb567a..15ee76ac 100644
--- a/pages/o/[organization-slug]/[solution-slug]/environment/glossary.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/environment/glossary.client.vue
@@ -6,7 +6,7 @@ definePageMeta({ name: 'Glossary' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Glossary').params,
- { data: solutions, error: getSolutionError } = await useFetch('/api/solutions', {
+ { data: solutions, error: getSolutionError } = await useFetch('/api/solution', {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -17,7 +17,7 @@ const { $eventBus } = useNuxtApp(),
if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value);
-const { data: glossaryTerms, refresh, status, error: getGlossaryTermsError } = await useFetch(`/api/glossary-terms`, {
+const { data: glossaryTerms, refresh, status, error: getGlossaryTermsError } = await useFetch(`/api/glossary-term`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -29,7 +29,7 @@ if (getGlossaryTermsError.value)
$eventBus.$emit('page-error', getGlossaryTermsError.value)
const onCreate = async (data: GlossaryTerm) => {
- await $fetch(`/api/glossary-terms`, {
+ await $fetch(`/api/glossary-term`, {
method: 'POST',
body: {
name: data.name,
@@ -42,7 +42,7 @@ const onCreate = async (data: GlossaryTerm) => {
}
const onUpdate = async (data: GlossaryTerm) => {
- await $fetch(`/api/glossary-terms/${data.id}`, {
+ await $fetch(`/api/glossary-term/${data.id}`, {
method: 'PUT',
body: {
id: data.id,
@@ -56,7 +56,7 @@ const onUpdate = async (data: GlossaryTerm) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/glossary-terms/${id}`, {
+ await $fetch(`/api/glossary-term/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
diff --git a/pages/o/[organization-slug]/[solution-slug]/environment/invariants.client.vue b/pages/o/[organization-slug]/[solution-slug]/environment/invariants.client.vue
index 0fac8651..15787423 100644
--- a/pages/o/[organization-slug]/[solution-slug]/environment/invariants.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/environment/invariants.client.vue
@@ -6,7 +6,7 @@ definePageMeta({ name: 'Invariants' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Invariants').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -17,7 +17,7 @@ const { $eventBus } = useNuxtApp(),
if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value)
-const { data: invariants, refresh, status, error: getInvariantsError } = await useFetch(`/api/invariants`, {
+const { data: invariants, refresh, status, error: getInvariantsError } = await useFetch(`/api/invariant`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -29,7 +29,7 @@ if (getInvariantsError.value)
$eventBus.$emit('page-error', getInvariantsError.value)
const onCreate = async (data: Invariant) => {
- await useFetch(`/api/invariants`, {
+ await useFetch(`/api/invariant`, {
method: 'POST',
body: {
name: data.name,
@@ -42,7 +42,7 @@ const onCreate = async (data: Invariant) => {
}
const onUpdate = async (data: Invariant) => {
- await useFetch(`/api/invariants/${data.id}`, {
+ await useFetch(`/api/invariant/${data.id}`, {
method: 'PUT', body: {
id: data.id,
name: data.name,
@@ -55,7 +55,7 @@ const onUpdate = async (data: Invariant) => {
}
const onDelete = async (id: string) => {
- await useFetch(`/api/invariants/${id}`, {
+ await useFetch(`/api/invariant/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
diff --git a/pages/o/[organization-slug]/[solution-slug]/goals/functionality.client.vue b/pages/o/[organization-slug]/[solution-slug]/goals/functionality.client.vue
index e80c04a0..40156a87 100644
--- a/pages/o/[organization-slug]/[solution-slug]/goals/functionality.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/goals/functionality.client.vue
@@ -7,7 +7,7 @@ definePageMeta({ name: 'Goals Functionality' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Functionality').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -18,7 +18,7 @@ const { $eventBus } = useNuxtApp(),
if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value)
-const { data: functionalBehaviors, refresh, status, error: getFunctionalBehaviorsError } = await useFetch(`/api/functional-behaviors`, {
+const { data: functionalBehaviors, refresh, status, error: getFunctionalBehaviorsError } = await useFetch(`/api/functional-behavior`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -30,7 +30,7 @@ if (getFunctionalBehaviorsError.value)
$eventBus.$emit('page-error', getFunctionalBehaviorsError.value);
const onCreate = async (data: FunctionalBehavior) => {
- await $fetch(`/api/functional-behaviors`, {
+ await $fetch(`/api/functional-behavior`, {
method: 'POST',
body: {
...data,
@@ -43,7 +43,7 @@ const onCreate = async (data: FunctionalBehavior) => {
}
const onUpdate = async (data: FunctionalBehavior) => {
- await $fetch(`/api/functional-behaviors/${data.id}`, {
+ await $fetch(`/api/functional-behavior/${data.id}`, {
method: 'PUT',
body: {
...data,
@@ -56,7 +56,7 @@ const onUpdate = async (data: FunctionalBehavior) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/functional-behaviors/${id}`, {
+ await $fetch(`/api/functional-behavior/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
diff --git a/pages/o/[organization-slug]/[solution-slug]/goals/limitations.client.vue b/pages/o/[organization-slug]/[solution-slug]/goals/limitations.client.vue
index 84018da2..6f6af9c5 100644
--- a/pages/o/[organization-slug]/[solution-slug]/goals/limitations.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/goals/limitations.client.vue
@@ -6,7 +6,7 @@ definePageMeta({ name: 'Limitations' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Limitations').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -17,7 +17,7 @@ const { $eventBus } = useNuxtApp(),
if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value)
-const { data: limits, status, refresh, error: getLimitsError } = await useFetch(`/api/limits`, {
+const { data: limits, status, refresh, error: getLimitsError } = await useFetch(`/api/limit`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -29,7 +29,7 @@ if (getLimitsError.value)
$eventBus.$emit('page-error', getLimitsError.value)
const onCreate = async (data: Limit) => {
- await $fetch(`/api/limits`, {
+ await $fetch(`/api/limit`, {
method: 'POST',
body: {
solutionId,
@@ -42,7 +42,7 @@ const onCreate = async (data: Limit) => {
}
const onUpdate = async (data: Limit) => {
- await $fetch(`/api/limits/${data.id}`, {
+ await $fetch(`/api/limit/${data.id}`, {
method: 'PUT', body: {
solutionId,
id: data.id,
@@ -55,7 +55,7 @@ const onUpdate = async (data: Limit) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/limits/${id}`, {
+ await $fetch(`/api/limit/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
diff --git a/pages/o/[organization-slug]/[solution-slug]/goals/obstacles.client.vue b/pages/o/[organization-slug]/[solution-slug]/goals/obstacles.client.vue
index f0ec98ec..d9e500ae 100644
--- a/pages/o/[organization-slug]/[solution-slug]/goals/obstacles.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/goals/obstacles.client.vue
@@ -6,7 +6,7 @@ definePageMeta({ name: 'Obstacles' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Obstacles').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -17,7 +17,7 @@ const { $eventBus } = useNuxtApp(),
if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value);
-const { data: obstacles, refresh, status, error: getObstaclesError } = await useFetch(`/api/obstacles`, {
+const { data: obstacles, refresh, status, error: getObstaclesError } = await useFetch(`/api/obstacle`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -26,7 +26,7 @@ const { data: obstacles, refresh, status, error: getObstaclesError } = await use
})
const onCreate = async (data: Obstacle) => {
- await $fetch(`/api/obstacles`, {
+ await $fetch(`/api/obstacle`, {
method: 'POST',
body: {
solutionId,
@@ -39,7 +39,7 @@ const onCreate = async (data: Obstacle) => {
}
const onUpdate = async (data: Obstacle) => {
- await $fetch(`/api/obstacles/${data.id}`, {
+ await $fetch(`/api/obstacle/${data.id}`, {
method: 'PUT',
body: {
solutionId,
@@ -52,7 +52,7 @@ const onUpdate = async (data: Obstacle) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/obstacles/${id}`, {
+ await $fetch(`/api/obstacle/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
diff --git a/pages/o/[organization-slug]/[solution-slug]/goals/outcomes.client.vue b/pages/o/[organization-slug]/[solution-slug]/goals/outcomes.client.vue
index 01ff0a50..8027ab0b 100644
--- a/pages/o/[organization-slug]/[solution-slug]/goals/outcomes.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/goals/outcomes.client.vue
@@ -6,7 +6,7 @@ definePageMeta({ name: 'Outcomes' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Outcomes').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -17,7 +17,7 @@ const { $eventBus } = useNuxtApp(),
if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value);
-const { data: outcomes, refresh, status, error: getOutcomesError } = await useFetch(`/api/outcomes`, {
+const { data: outcomes, refresh, status, error: getOutcomesError } = await useFetch(`/api/outcome`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -29,7 +29,7 @@ if (getOutcomesError.value)
$eventBus.$emit('page-error', getOutcomesError.value);
const onCreate = async (data: Outcome) => {
- await $fetch(`/api/outcomes`, {
+ await $fetch(`/api/outcome`, {
method: 'POST',
body: {
solutionId,
@@ -42,7 +42,7 @@ const onCreate = async (data: Outcome) => {
}
const onUpdate = async (data: Outcome) => {
- await $fetch(`/api/outcomes/${data.id}`, {
+ await $fetch(`/api/outcome/${data.id}`, {
method: 'PUT',
body: {
solutionId,
@@ -55,7 +55,7 @@ const onUpdate = async (data: Outcome) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/outcomes/${id}`, {
+ await $fetch(`/api/outcome/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
diff --git a/pages/o/[organization-slug]/[solution-slug]/goals/rationale.client.vue b/pages/o/[organization-slug]/[solution-slug]/goals/rationale.client.vue
index 0f3908c3..a5c0b294 100644
--- a/pages/o/[organization-slug]/[solution-slug]/goals/rationale.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/goals/rationale.client.vue
@@ -6,7 +6,7 @@ definePageMeta({ name: 'Rationale' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Rationale').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -23,10 +23,10 @@ const [
{ data: situationJustifications, error: getSituationError },
{ data: objectiveJustifications, error: getObjectiveError }
] = await Promise.all([
- useFetch(`/api/justifications`, { query: { name: 'Vision', solutionId } }),
- useFetch(`/api/justifications`, { query: { name: 'Mission', solutionId } }),
- useFetch(`/api/justifications`, { query: { name: 'Situation', solutionId } }),
- useFetch(`/api/justifications`, { query: { name: 'Objective', solutionId } })
+ useFetch(`/api/justification`, { query: { name: 'Vision', solutionId } }),
+ useFetch(`/api/justification`, { query: { name: 'Mission', solutionId } }),
+ useFetch(`/api/justification`, { query: { name: 'Situation', solutionId } }),
+ useFetch(`/api/justification`, { query: { name: 'Objective', solutionId } })
]);
if (getVisionError.value)
@@ -53,7 +53,7 @@ const fieldTriple: [Ref, Justification, string][] = [
fieldTriple.forEach(([goalDescription, justification, _name]) => {
watch(goalDescription, debounce(() => {
justification.description = goalDescription.value;
- $fetch(`/api/justifications/${justification.id}`, {
+ $fetch(`/api/justification/${justification.id}`, {
method: 'PUT',
body: {
solutionId,
diff --git a/pages/o/[organization-slug]/[solution-slug]/goals/scenarios.client.vue b/pages/o/[organization-slug]/[solution-slug]/goals/scenarios.client.vue
index 499f6a47..ac65943d 100644
--- a/pages/o/[organization-slug]/[solution-slug]/goals/scenarios.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/goals/scenarios.client.vue
@@ -10,7 +10,7 @@ definePageMeta({ name: 'Goal Scenarios' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Scenarios').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -27,16 +27,16 @@ const [
{ data: functionalBehaviors, error: getFunctionalBehaviorsError },
{ data: outcomes, error: getOutcomesError },
] = await Promise.all([
- useFetch(`/api/user-stories`, {
+ useFetch(`/api/user-story`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
return item
})
}),
- useFetch(`/api/stakeholders`, { query: { solutionId } }),
- useFetch(`/api/functional-behaviors`, { query: { solutionId } }),
- useFetch(`/api/outcomes`, { query: { solutionId } })
+ useFetch(`/api/stakeholder`, { query: { solutionId } }),
+ useFetch(`/api/functional-behavior`, { query: { solutionId } }),
+ useFetch(`/api/outcome`, { query: { solutionId } })
])
if (getUserStoriesError.value)
@@ -49,7 +49,7 @@ if (getOutcomesError.value)
$eventBus.$emit('page-error', getOutcomesError.value);
const onUserStoryCreate = async (userStory: UserStory) => {
- await $fetch(`/api/user-stories`, {
+ await $fetch(`/api/user-story`, {
method: 'POST',
body: {
...userStory,
@@ -63,7 +63,7 @@ const onUserStoryCreate = async (userStory: UserStory) => {
}
const onUserStoryUpdate = async (userStory: UserStory) => {
- await $fetch(`/api/user-stories/${userStory.id}`, {
+ await $fetch(`/api/user-story/${userStory.id}`, {
method: 'PUT',
body: {
...userStory,
@@ -77,7 +77,7 @@ const onUserStoryUpdate = async (userStory: UserStory) => {
}
const onUserStoryDelete = async (id: string) => {
- await $fetch(`/api/user-stories/${id}`, {
+ await $fetch(`/api/user-story/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e));
diff --git a/pages/o/[organization-slug]/[solution-slug]/goals/stakeholders.client.vue b/pages/o/[organization-slug]/[solution-slug]/goals/stakeholders.client.vue
index 296f056a..51eace6a 100644
--- a/pages/o/[organization-slug]/[solution-slug]/goals/stakeholders.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/goals/stakeholders.client.vue
@@ -10,7 +10,7 @@ definePageMeta({ name: 'Stakeholders' })
const config = useAppConfig(),
{ $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Stakeholders').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -21,7 +21,7 @@ const config = useAppConfig(),
if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value);
-const { data: stakeholders, refresh: refreshStakeholders, status, error: getStakeholdersError } = await useFetch(`/api/stakeholders`, {
+const { data: stakeholders, refresh: refreshStakeholders, status, error: getStakeholdersError } = await useFetch(`/api/stakeholder`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -75,10 +75,15 @@ const renderChart = async () => {
watch(stakeholders, renderChart);
const onCreate = async (data: Stakeholder) => {
- await $fetch(`/api/stakeholders`, {
+ await $fetch(`/api/stakeholder`, {
method: 'POST',
body: {
- ...data,
+ name: data.name,
+ description: data.description,
+ category: data.category,
+ segmentation: data.segmentation,
+ availability: Number(data.availability),
+ influence: Number(data.influence),
solutionId
}
}).catch((e) => $eventBus.$emit('page-error', e))
@@ -87,10 +92,15 @@ const onCreate = async (data: Stakeholder) => {
}
const onUpdate = async (data: Stakeholder) => {
- await $fetch(`/api/stakeholders/${data.id}`, {
+ await $fetch(`/api/stakeholder/${data.id}`, {
method: 'PUT',
body: {
- ...data,
+ name: data.name,
+ description: data.description,
+ category: data.category,
+ segmentation: data.segmentation,
+ availability: Number(data.availability),
+ influence: Number(data.influence),
solutionId
}
}).catch((e) => $eventBus.$emit('page-error', e))
@@ -99,7 +109,7 @@ const onUpdate = async (data: Stakeholder) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/stakeholders/${id}`, {
+ await $fetch(`/api/stakeholder/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
diff --git a/pages/o/[organization-slug]/[solution-slug]/index.client.vue b/pages/o/[organization-slug]/[solution-slug]/index.client.vue
index 2f16e42d..08fd399e 100644
--- a/pages/o/[organization-slug]/[solution-slug]/index.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/index.client.vue
@@ -5,7 +5,7 @@ definePageMeta({ name: 'Solution' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Solution').params,
router = useRouter(),
- { data: solutions, error: solutionError } = await useFetch('/api/solutions', {
+ { data: solutions, error: solutionError } = await useFetch('/api/solution', {
query: {
organizationSlug: organizationslug,
slug: solutionslug
@@ -36,7 +36,7 @@ const handleSolutionDelete = async () => {
rejectLabel: 'Cancel',
acceptLabel: 'Delete',
accept: async () => {
- await $fetch(`/api/solutions/${solution.id}`, {
+ await $fetch(`/api/solution/${solution.id}`, {
method: 'delete'
}).catch((e) => $eventBus.$emit('page-error', e))
router.push({ name: 'Organization', params: { organizationslug } })
@@ -54,7 +54,7 @@ const parsingRequirements = ref(false),
const parseRawRequirement = async () => {
parsingRequirements.value = true
parsingError.value = ''
- const response = await $fetch('/api/parse-requirements', {
+ const response = await $fetch('/api/parse-requirement', {
method: 'post',
body: {
solutionId: solution.id,
diff --git a/pages/o/[organization-slug]/[solution-slug]/project/roles-personnel.client.vue b/pages/o/[organization-slug]/[solution-slug]/project/roles-personnel.client.vue
index e2a84a31..7a834e30 100644
--- a/pages/o/[organization-slug]/[solution-slug]/project/roles-personnel.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/project/roles-personnel.client.vue
@@ -6,7 +6,7 @@ definePageMeta({ name: 'Roles & Personnel' })
const { $eventBus } = useNuxtApp(),
{ solutionslug, organizationslug } = useRoute('Roles & Personnel').params,
- { data: solutions, error: getSolutionError } = await useFetch(`/api/solutions`, {
+ { data: solutions, error: getSolutionError } = await useFetch(`/api/solution`, {
query: {
slug: solutionslug,
organizationSlug: organizationslug
@@ -17,7 +17,7 @@ const { $eventBus } = useNuxtApp(),
if (getSolutionError.value)
$eventBus.$emit('page-error', getSolutionError.value)
-const { data: personnel, refresh, status, error: getPersonnelError } = await useFetch(`/api/persons`, {
+const { data: personnel, refresh, status, error: getPersonnelError } = await useFetch(`/api/person`, {
query: { solutionId },
transform: (data) => data.map((item) => {
item.lastModified = new Date(item.lastModified)
@@ -29,7 +29,7 @@ if (getPersonnelError.value)
$eventBus.$emit('page-error', getPersonnelError.value)
const onCreate = async (data: Person) => {
- await $fetch(`/api/persons`, {
+ await $fetch(`/api/person`, {
method: 'POST',
body: {
name: data.name ?? 'Anonymous',
@@ -43,7 +43,7 @@ const onCreate = async (data: Person) => {
}
const onUpdate = async (data: Person) => {
- await $fetch(`/api/persons/${data.id}`, {
+ await $fetch(`/api/person/${data.id}`, {
method: 'PUT',
body: {
name: data.name ?? 'Anonymous',
@@ -57,7 +57,7 @@ const onUpdate = async (data: Person) => {
}
const onDelete = async (id: string) => {
- await $fetch(`/api/persons/${id}`, {
+ await $fetch(`/api/person/${id}`, {
method: 'DELETE',
body: { solutionId }
}).catch((e) => $eventBus.$emit('page-error', e))
diff --git a/pages/o/[organization-slug]/[solution-slug]/system/components.client.vue b/pages/o/[organization-slug]/[solution-slug]/system/components.client.vue
index e56d5cd4..a2c7fb94 100644
--- a/pages/o/[organization-slug]/[solution-slug]/system/components.client.vue
+++ b/pages/o/[organization-slug]/[solution-slug]/system/components.client.vue
@@ -1,12 +1,13 @@
@@ -65,26 +84,45 @@ const onItemUpdate = async (type: ParsedReqColType, data: Requirement) => {
The Workbox is empty.
-
-
-
-
- {{
- parsedRequirement.lastModified.toLocaleString() }}
-
- by {{ parsedRequirement.modifiedBy.name }}
- {{ parsedRequirement.statement }}
-
+
+
+
+
+
+
+
+
+
+ {{ data.modifiedBy.name }}
-
-
-
+
+
+
+
+
+ {{ snakeCaseToTitle(reqType) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/pages/o/[organization-slug]/edit-entry.client.vue b/pages/o/[organization-slug]/edit-entry.client.vue
index a1cddaab..77b64c88 100644
--- a/pages/o/[organization-slug]/edit-entry.client.vue
+++ b/pages/o/[organization-slug]/edit-entry.client.vue
@@ -5,7 +5,7 @@ definePageMeta({ name: 'Edit Organization' })
const router = useRouter(),
{ $eventBus } = useNuxtApp(),
{ organizationslug } = useRoute('Edit Organization').params,
- { data: organizations, error: getOrgError } = await useFetch(`/api/organizations/`, { query: { slug: organizationslug } }),
+ { data: organizations, error: getOrgError } = await useFetch(`/api/organization/`, { query: { slug: organizationslug } }),
organization = ref(organizations.value![0]),
newSlug = ref(organization.value.slug);
@@ -13,7 +13,7 @@ if (getOrgError.value)
$eventBus.$emit('page-error', getOrgError.value);
const updateOrganization = async () => {
- await $fetch(`/api/organizations/${organization.value.id}`, {
+ await $fetch(`/api/organization/${organization.value.id}`, {
method: 'PUT',
body: {
name: organization.value.name,
diff --git a/pages/o/[organization-slug]/index.client.vue b/pages/o/[organization-slug]/index.client.vue
index 84606bad..fb77e4fa 100644
--- a/pages/o/[organization-slug]/index.client.vue
+++ b/pages/o/[organization-slug]/index.client.vue
@@ -5,11 +5,11 @@ definePageMeta({ name: 'Organization' })
const { $eventBus } = useNuxtApp(),
{ organizationslug } = useRoute('Organization').params,
router = useRouter(),
- { data: organizations, error: getOrgError } = await useFetch('/api/organizations', {
+ { data: organizations, error: getOrgError } = await useFetch('/api/organization', {
query: { slug: organizationslug }
}),
organization = organizations.value![0],
- { refresh: refreshSolutions, status, data: solutions, error: getSolutionError } = await useFetch('/api/solutions', {
+ { refresh: refreshSolutions, status, data: solutions, error: getSolutionError } = await useFetch('/api/solution', {
query: { organizationSlug: organizationslug }
}),
confirm = useConfirm()
@@ -35,7 +35,7 @@ const handleOrganizationDelete = async () => {
rejectLabel: 'Cancel',
acceptLabel: 'Delete',
accept: async () => {
- await $fetch(`/api/organizations/${organization.id}`, {
+ await $fetch(`/api/organization/${organization.id}`, {
method: 'delete'
}).catch((e) => $eventBus.$emit('page-error', e))
router.push({ name: 'Home' })
@@ -60,7 +60,7 @@ const handleSolutionDelete = async (solution: SolutionModel) => {
rejectLabel: 'Cancel',
acceptLabel: 'Delete',
accept: async () => {
- await $fetch(`/api/solutions/${solution.id}`, {
+ await $fetch(`/api/solution/${solution.id}`, {
method: 'delete'
}).catch((e) => $eventBus.$emit('page-error', e))
await refreshSolutions()
diff --git a/pages/o/[organization-slug]/new-solution.client.vue b/pages/o/[organization-slug]/new-solution.client.vue
index e9c9762f..32dccf2d 100644
--- a/pages/o/[organization-slug]/new-solution.client.vue
+++ b/pages/o/[organization-slug]/new-solution.client.vue
@@ -9,7 +9,7 @@ const { $eventBus } = useNuxtApp(),
slug = ref(''),
description = ref('')
-const { data: organizations, error: getOrgError } = await useFetch('/api/organizations', {
+const { data: organizations, error: getOrgError } = await useFetch('/api/organization', {
query: { slug: organizationslug }
}),
organization = organizations.value![0],
@@ -20,7 +20,7 @@ if (getOrgError.value)
const createSolution = async () => {
try {
- const solutionId = (await $fetch('/api/solutions', {
+ const solutionId = (await $fetch('/api/solution', {
method: 'post',
body: {
name: name.value,
@@ -30,7 +30,7 @@ const createSolution = async () => {
}).catch((e) => $eventBus.$emit('page-error', e)));
if (solutionId) {
- const newSolution = (await $fetch(`/api/solutions/${solutionId}`));
+ const newSolution = (await $fetch(`/api/solution/${solutionId}`));
router.push({ name: 'Solution', params: { organizationslug, solutionslug: newSolution.slug } });
} else {
$eventBus.$emit('page-error', 'Failed to create solution. No solution ID returned.');
diff --git a/pages/o/[organization-slug]/users.vue b/pages/o/[organization-slug]/users.vue
index df7ef33c..8a901d9f 100644
--- a/pages/o/[organization-slug]/users.vue
+++ b/pages/o/[organization-slug]/users.vue
@@ -8,7 +8,7 @@ definePageMeta({ name: 'Organization Users' })
const { $eventBus } = useNuxtApp()
const { organizationslug } = useRoute('Organization Users').params,
- { data: organizations, error: getOrgError } = await useFetch(`/api/organizations/`, {
+ { data: organizations, error: getOrgError } = await useFetch(`/api/organization/`, {
query: { slug: organizationslug }
}),
organization = ref(organizations.value?.[0]!)
diff --git a/server/api/appusers/[id].delete.ts b/server/api/appusers/[id].delete.ts
index d243e673..32a5f6d6 100644
--- a/server/api/appusers/[id].delete.ts
+++ b/server/api/appusers/[id].delete.ts
@@ -43,6 +43,5 @@ export default defineEventHandler(async (event) => {
})
// Removing the relationship to the organization and NOT the appuser itself
- em.remove(appUserRole)
- await em.flush()
+ await em.remove(appUserRole).flush()
})
\ No newline at end of file
diff --git a/server/api/assumptions/[id].delete.ts b/server/api/assumption/[id].delete.ts
similarity index 100%
rename from server/api/assumptions/[id].delete.ts
rename to server/api/assumption/[id].delete.ts
diff --git a/server/api/assumptions/[id].get.ts b/server/api/assumption/[id].get.ts
similarity index 93%
rename from server/api/assumptions/[id].get.ts
rename to server/api/assumption/[id].get.ts
index f58e8aac..83c51664 100644
--- a/server/api/assumptions/[id].get.ts
+++ b/server/api/assumption/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Assumption } from "~/server/domain/requirements"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/assumptions/[id].put.ts b/server/api/assumption/[id].put.ts
similarity index 96%
rename from server/api/assumptions/[id].put.ts
rename to server/api/assumption/[id].put.ts
index aec286e2..f87b11da 100644
--- a/server/api/assumptions/[id].put.ts
+++ b/server/api/assumption/[id].put.ts
@@ -31,6 +31,6 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(assumption)
})
diff --git a/server/api/assumptions/index.get.ts b/server/api/assumption/index.get.ts
similarity index 100%
rename from server/api/assumptions/index.get.ts
rename to server/api/assumption/index.get.ts
diff --git a/server/api/assumptions/index.post.ts b/server/api/assumption/index.post.ts
similarity index 100%
rename from server/api/assumptions/index.post.ts
rename to server/api/assumption/index.post.ts
diff --git a/server/api/audit-log/deleted.get.ts b/server/api/audit-log/deleted.get.ts
index 21948cf3..788c9fef 100644
--- a/server/api/audit-log/deleted.get.ts
+++ b/server/api/audit-log/deleted.get.ts
@@ -1,6 +1,7 @@
import { ChangeSetType } from "@mikro-orm/core"
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
+import { AuditLog } from "~/server/domain/application"
import { Organization } from "~/server/domain/requirements/index.js"
const querySchema = z.object({
@@ -51,7 +52,7 @@ export default defineEventHandler(async (event) => {
WHERE d.type = 'delete'
AND a.entity_name = ?;
`, [entityName]),
- auditLogs = res.map((row) => ({
+ auditLogs = res.map((row) => new AuditLog({
id: row.id,
createdAt: new Date(row.created_at),
type: row.type,
diff --git a/server/api/auth/[...].ts b/server/api/auth/[...].ts
index eeb0519f..c0e79dfb 100644
--- a/server/api/auth/[...].ts
+++ b/server/api/auth/[...].ts
@@ -50,7 +50,7 @@ export default NuxtAuthHandler({
appUser.lastLoginDate = new Date()
}
- await em.flush()
+ await em.persistAndFlush(appUser)
Object.assign(token, {
id: p.oid,
diff --git a/server/api/constraints/[id].delete.ts b/server/api/constraint/[id].delete.ts
similarity index 100%
rename from server/api/constraints/[id].delete.ts
rename to server/api/constraint/[id].delete.ts
diff --git a/server/api/constraints/[id].get.ts b/server/api/constraint/[id].get.ts
similarity index 93%
rename from server/api/constraints/[id].get.ts
rename to server/api/constraint/[id].get.ts
index b5f7b7fd..885433d7 100644
--- a/server/api/constraints/[id].get.ts
+++ b/server/api/constraint/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Constraint } from "~/server/domain/requirements/Constraint.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/constraints/[id].put.ts b/server/api/constraint/[id].put.ts
similarity index 96%
rename from server/api/constraints/[id].put.ts
rename to server/api/constraint/[id].put.ts
index b7f765f7..0f3b8561 100644
--- a/server/api/constraints/[id].put.ts
+++ b/server/api/constraint/[id].put.ts
@@ -33,5 +33,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(constraint)
})
\ No newline at end of file
diff --git a/server/api/constraints/index.get.ts b/server/api/constraint/index.get.ts
similarity index 100%
rename from server/api/constraints/index.get.ts
rename to server/api/constraint/index.get.ts
diff --git a/server/api/constraints/index.post.ts b/server/api/constraint/index.post.ts
similarity index 100%
rename from server/api/constraints/index.post.ts
rename to server/api/constraint/index.post.ts
diff --git a/server/api/effects/[id].delete.ts b/server/api/effect/[id].delete.ts
similarity index 100%
rename from server/api/effects/[id].delete.ts
rename to server/api/effect/[id].delete.ts
diff --git a/server/api/effects/[id].get.ts b/server/api/effect/[id].get.ts
similarity index 92%
rename from server/api/effects/[id].get.ts
rename to server/api/effect/[id].get.ts
index 06f40845..11b591ab 100644
--- a/server/api/effects/[id].get.ts
+++ b/server/api/effect/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Effect } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/effects/[id].put.ts b/server/api/effect/[id].put.ts
similarity index 96%
rename from server/api/effects/[id].put.ts
rename to server/api/effect/[id].put.ts
index c8dff168..c08f4337 100644
--- a/server/api/effects/[id].put.ts
+++ b/server/api/effect/[id].put.ts
@@ -31,5 +31,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date(),
})
- await em.flush()
+ await em.persistAndFlush(effect)
})
\ No newline at end of file
diff --git a/server/api/effects/index.get.ts b/server/api/effect/index.get.ts
similarity index 100%
rename from server/api/effects/index.get.ts
rename to server/api/effect/index.get.ts
diff --git a/server/api/effects/index.post.ts b/server/api/effect/index.post.ts
similarity index 100%
rename from server/api/effects/index.post.ts
rename to server/api/effect/index.post.ts
diff --git a/server/api/environment-components/[id].delete.ts b/server/api/environment-component/[id].delete.ts
similarity index 100%
rename from server/api/environment-components/[id].delete.ts
rename to server/api/environment-component/[id].delete.ts
diff --git a/server/api/environment-components/[id].get.ts b/server/api/environment-component/[id].get.ts
similarity index 84%
rename from server/api/environment-components/[id].get.ts
rename to server/api/environment-component/[id].get.ts
index 00aa0c72..53a5fb3f 100644
--- a/server/api/environment-components/[id].get.ts
+++ b/server/api/environment-component/[id].get.ts
@@ -1,8 +1,6 @@
-import { m } from "@vite-pwa/assets-generator/dist/shared/assets-generator.5e51fd40.mjs"
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { EnvironmentComponent } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/environment-components/[id].put.ts b/server/api/environment-component/[id].put.ts
similarity index 64%
rename from server/api/environment-components/[id].put.ts
rename to server/api/environment-component/[id].put.ts
index b46b7017..8d0e3242 100644
--- a/server/api/environment-components/[id].put.ts
+++ b/server/api/environment-component/[id].put.ts
@@ -1,5 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
+import { Belongs } from "~/server/domain/relations"
import { EnvironmentComponent } from "~/server/domain/requirements/index.js"
const paramSchema = z.object({
@@ -23,16 +24,31 @@ export default defineEventHandler(async (event) => {
{ sessionUser, solution } = await assertSolutionContributor(event, solutionId),
em = fork(),
environmentComponent = await assertReqBelongsToSolution(em, EnvironmentComponent, id, solution),
- parentComponent = parentComponentId ? await assertReqBelongsToSolution(em, EnvironmentComponent, parentComponentId, solution) : environmentComponent.parentComponent
+ parentComponent = parentComponentId ? await assertReqBelongsToSolution(em, EnvironmentComponent, parentComponentId, solution) : undefined
environmentComponent.assign({
name: name ?? environmentComponent.name,
description: description ?? environmentComponent.description,
isSilence: isSilence ?? environmentComponent.isSilence,
modifiedBy: sessionUser,
- parentComponent,
lastModified: new Date()
})
- await em.flush()
+ const existingParentComponent = await em.findOne(Belongs, {
+ left: environmentComponent,
+ right: parentComponent
+ })
+
+ if (!existingParentComponent && parentComponent) {
+ em.create(Belongs, { left: environmentComponent, right: parentComponent })
+ } else if (existingParentComponent && !parentComponent) {
+ em.remove(existingParentComponent)
+ } else if (existingParentComponent && parentComponent) {
+ em.remove(existingParentComponent)
+ em.create(Belongs, { left: environmentComponent, right: parentComponent })
+ } else {
+ // Do nothing
+ }
+
+ await em.persistAndFlush(environmentComponent)
})
\ No newline at end of file
diff --git a/server/api/environment-components/index.get.ts b/server/api/environment-component/index.get.ts
similarity index 100%
rename from server/api/environment-components/index.get.ts
rename to server/api/environment-component/index.get.ts
diff --git a/server/api/environment-components/index.post.ts b/server/api/environment-component/index.post.ts
similarity index 89%
rename from server/api/environment-components/index.post.ts
rename to server/api/environment-component/index.post.ts
index d618601b..2c8a8dc0 100644
--- a/server/api/environment-components/index.post.ts
+++ b/server/api/environment-component/index.post.ts
@@ -24,12 +24,14 @@ export default defineEventHandler(async (event) => {
description,
lastModified: new Date(),
modifiedBy: sessionUser,
- isSilence,
- parentComponent: parentComponentId ? em.getReference(EnvironmentComponent, parentComponentId) : undefined
+ isSilence
})
em.create(Belongs, { left: newEnvironmentComponent, right: solution })
+ if (parentComponentId)
+ em.create(Belongs, { left: newEnvironmentComponent, right: parentComponentId })
+
await em.flush()
return newEnvironmentComponent.id
diff --git a/server/api/functional-behaviors/[id].delete.ts b/server/api/functional-behavior/[id].delete.ts
similarity index 100%
rename from server/api/functional-behaviors/[id].delete.ts
rename to server/api/functional-behavior/[id].delete.ts
diff --git a/server/api/functional-behaviors/[id].get.ts b/server/api/functional-behavior/[id].get.ts
similarity index 93%
rename from server/api/functional-behaviors/[id].get.ts
rename to server/api/functional-behavior/[id].get.ts
index aee71850..3a110add 100644
--- a/server/api/functional-behaviors/[id].get.ts
+++ b/server/api/functional-behavior/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { FunctionalBehavior } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/functional-behaviors/[id].put.ts b/server/api/functional-behavior/[id].put.ts
similarity index 96%
rename from server/api/functional-behaviors/[id].put.ts
rename to server/api/functional-behavior/[id].put.ts
index e2b28fb1..7884b19a 100644
--- a/server/api/functional-behaviors/[id].put.ts
+++ b/server/api/functional-behavior/[id].put.ts
@@ -33,5 +33,5 @@ export default defineEventHandler(async (event) => {
...(isSilence !== undefined && { isSilence })
})
- await em.flush()
+ await em.persistAndFlush(functionalBehavior)
})
\ No newline at end of file
diff --git a/server/api/functional-behaviors/index.get.ts b/server/api/functional-behavior/index.get.ts
similarity index 100%
rename from server/api/functional-behaviors/index.get.ts
rename to server/api/functional-behavior/index.get.ts
diff --git a/server/api/functional-behaviors/index.post.ts b/server/api/functional-behavior/index.post.ts
similarity index 100%
rename from server/api/functional-behaviors/index.post.ts
rename to server/api/functional-behavior/index.post.ts
diff --git a/server/api/glossary-terms/[id].delete.ts b/server/api/glossary-term/[id].delete.ts
similarity index 100%
rename from server/api/glossary-terms/[id].delete.ts
rename to server/api/glossary-term/[id].delete.ts
diff --git a/server/api/glossary-terms/[id].get.ts b/server/api/glossary-term/[id].get.ts
similarity index 93%
rename from server/api/glossary-terms/[id].get.ts
rename to server/api/glossary-term/[id].get.ts
index d093ab82..1944984b 100644
--- a/server/api/glossary-terms/[id].get.ts
+++ b/server/api/glossary-term/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { GlossaryTerm } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/glossary-terms/[id].put.ts b/server/api/glossary-term/[id].put.ts
similarity index 96%
rename from server/api/glossary-terms/[id].put.ts
rename to server/api/glossary-term/[id].put.ts
index adfa7a70..96e5df86 100644
--- a/server/api/glossary-terms/[id].put.ts
+++ b/server/api/glossary-term/[id].put.ts
@@ -33,5 +33,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(glossaryTerm)
})
\ No newline at end of file
diff --git a/server/api/glossary-terms/index.get.ts b/server/api/glossary-term/index.get.ts
similarity index 100%
rename from server/api/glossary-terms/index.get.ts
rename to server/api/glossary-term/index.get.ts
diff --git a/server/api/glossary-terms/index.post.ts b/server/api/glossary-term/index.post.ts
similarity index 76%
rename from server/api/glossary-terms/index.post.ts
rename to server/api/glossary-term/index.post.ts
index 36d9c8de..10530f2c 100644
--- a/server/api/glossary-terms/index.post.ts
+++ b/server/api/glossary-term/index.post.ts
@@ -7,6 +7,7 @@ const bodySchema = z.object({
solutionId: z.string().uuid(),
name: z.string().default("{Untitled Glossary Term}"),
description: z.string().default(""),
+ parentComponentId: z.string().uuid().optional(),
isSilence: z.boolean().default(false)
})
@@ -14,14 +15,13 @@ const bodySchema = z.object({
* Creates a new glossary term and returns its id
*/
export default defineEventHandler(async (event) => {
- const { name, description, solutionId, isSilence } = await validateEventBody(event, bodySchema),
+ const { name, description, solutionId, isSilence, parentComponentId } = await validateEventBody(event, bodySchema),
{ solution, sessionUser } = await assertSolutionContributor(event, solutionId),
em = fork()
const glossaryTerm = em.create(GlossaryTerm, {
name,
description,
- parentComponent: undefined,
lastModified: new Date(),
modifiedBy: sessionUser,
isSilence
@@ -29,6 +29,9 @@ export default defineEventHandler(async (event) => {
em.create(Belongs, { left: glossaryTerm, right: solution })
+ if (parentComponentId)
+ em.create(Belongs, { left: glossaryTerm, right: parentComponentId })
+
await em.flush()
return glossaryTerm.id
diff --git a/server/api/invariants/[id].delete.ts b/server/api/invariant/[id].delete.ts
similarity index 100%
rename from server/api/invariants/[id].delete.ts
rename to server/api/invariant/[id].delete.ts
diff --git a/server/api/invariants/[id].get.ts b/server/api/invariant/[id].get.ts
similarity index 93%
rename from server/api/invariants/[id].get.ts
rename to server/api/invariant/[id].get.ts
index fbe1d78e..5dc0e54a 100644
--- a/server/api/invariants/[id].get.ts
+++ b/server/api/invariant/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Invariant } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/invariants/[id].put.ts b/server/api/invariant/[id].put.ts
similarity index 96%
rename from server/api/invariants/[id].put.ts
rename to server/api/invariant/[id].put.ts
index 0b964a86..daa80631 100644
--- a/server/api/invariants/[id].put.ts
+++ b/server/api/invariant/[id].put.ts
@@ -31,5 +31,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(invariant)
})
\ No newline at end of file
diff --git a/server/api/invariants/index.get.ts b/server/api/invariant/index.get.ts
similarity index 100%
rename from server/api/invariants/index.get.ts
rename to server/api/invariant/index.get.ts
diff --git a/server/api/invariants/index.post.ts b/server/api/invariant/index.post.ts
similarity index 100%
rename from server/api/invariants/index.post.ts
rename to server/api/invariant/index.post.ts
diff --git a/server/api/justifications/[id].delete.ts b/server/api/justification/[id].delete.ts
similarity index 100%
rename from server/api/justifications/[id].delete.ts
rename to server/api/justification/[id].delete.ts
diff --git a/server/api/justifications/[id].get.ts b/server/api/justification/[id].get.ts
similarity index 93%
rename from server/api/justifications/[id].get.ts
rename to server/api/justification/[id].get.ts
index 6d5e9e90..85baca64 100644
--- a/server/api/justifications/[id].get.ts
+++ b/server/api/justification/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Justification } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/justifications/[id].put.ts b/server/api/justification/[id].put.ts
similarity index 96%
rename from server/api/justifications/[id].put.ts
rename to server/api/justification/[id].put.ts
index e251692d..cdeb3caa 100644
--- a/server/api/justifications/[id].put.ts
+++ b/server/api/justification/[id].put.ts
@@ -32,5 +32,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(justification)
})
\ No newline at end of file
diff --git a/server/api/justifications/index.get.ts b/server/api/justification/index.get.ts
similarity index 100%
rename from server/api/justifications/index.get.ts
rename to server/api/justification/index.get.ts
diff --git a/server/api/justifications/index.post.ts b/server/api/justification/index.post.ts
similarity index 100%
rename from server/api/justifications/index.post.ts
rename to server/api/justification/index.post.ts
diff --git a/server/api/limits/[id].delete.ts b/server/api/limit/[id].delete.ts
similarity index 100%
rename from server/api/limits/[id].delete.ts
rename to server/api/limit/[id].delete.ts
diff --git a/server/api/limits/[id].get.ts b/server/api/limit/[id].get.ts
similarity index 92%
rename from server/api/limits/[id].get.ts
rename to server/api/limit/[id].get.ts
index cbddbc63..1afc454c 100644
--- a/server/api/limits/[id].get.ts
+++ b/server/api/limit/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Limit } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/limits/[id].put.ts b/server/api/limit/[id].put.ts
similarity index 96%
rename from server/api/limits/[id].put.ts
rename to server/api/limit/[id].put.ts
index 640ad00d..0d7dbff3 100644
--- a/server/api/limits/[id].put.ts
+++ b/server/api/limit/[id].put.ts
@@ -31,5 +31,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(limit)
})
\ No newline at end of file
diff --git a/server/api/limits/index.get.ts b/server/api/limit/index.get.ts
similarity index 100%
rename from server/api/limits/index.get.ts
rename to server/api/limit/index.get.ts
diff --git a/server/api/limits/index.post.ts b/server/api/limit/index.post.ts
similarity index 100%
rename from server/api/limits/index.post.ts
rename to server/api/limit/index.post.ts
diff --git a/server/api/non-functional-behaviors/[id].delete.ts b/server/api/non-functional-behavior/[id].delete.ts
similarity index 100%
rename from server/api/non-functional-behaviors/[id].delete.ts
rename to server/api/non-functional-behavior/[id].delete.ts
diff --git a/server/api/non-functional-behaviors/[id].get.ts b/server/api/non-functional-behavior/[id].get.ts
similarity index 93%
rename from server/api/non-functional-behaviors/[id].get.ts
rename to server/api/non-functional-behavior/[id].get.ts
index 79cd866f..db17b958 100644
--- a/server/api/non-functional-behaviors/[id].get.ts
+++ b/server/api/non-functional-behavior/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { NonFunctionalBehavior } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/non-functional-behaviors/[id].put.ts b/server/api/non-functional-behavior/[id].put.ts
similarity index 100%
rename from server/api/non-functional-behaviors/[id].put.ts
rename to server/api/non-functional-behavior/[id].put.ts
diff --git a/server/api/non-functional-behaviors/index.get.ts b/server/api/non-functional-behavior/index.get.ts
similarity index 100%
rename from server/api/non-functional-behaviors/index.get.ts
rename to server/api/non-functional-behavior/index.get.ts
diff --git a/server/api/non-functional-behaviors/index.post.ts b/server/api/non-functional-behavior/index.post.ts
similarity index 100%
rename from server/api/non-functional-behaviors/index.post.ts
rename to server/api/non-functional-behavior/index.post.ts
diff --git a/server/api/obstacles/[id].delete.ts b/server/api/obstacle/[id].delete.ts
similarity index 100%
rename from server/api/obstacles/[id].delete.ts
rename to server/api/obstacle/[id].delete.ts
diff --git a/server/api/obstacles/[id].get.ts b/server/api/obstacle/[id].get.ts
similarity index 92%
rename from server/api/obstacles/[id].get.ts
rename to server/api/obstacle/[id].get.ts
index d13ae8d3..03b60f53 100644
--- a/server/api/obstacles/[id].get.ts
+++ b/server/api/obstacle/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Obstacle } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/obstacles/[id].put.ts b/server/api/obstacle/[id].put.ts
similarity index 96%
rename from server/api/obstacles/[id].put.ts
rename to server/api/obstacle/[id].put.ts
index 0e7ae544..44170ac4 100644
--- a/server/api/obstacles/[id].put.ts
+++ b/server/api/obstacle/[id].put.ts
@@ -31,5 +31,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(obstacle)
})
\ No newline at end of file
diff --git a/server/api/obstacles/index.get.ts b/server/api/obstacle/index.get.ts
similarity index 100%
rename from server/api/obstacles/index.get.ts
rename to server/api/obstacle/index.get.ts
diff --git a/server/api/obstacles/index.post.ts b/server/api/obstacle/index.post.ts
similarity index 100%
rename from server/api/obstacles/index.post.ts
rename to server/api/obstacle/index.post.ts
diff --git a/server/api/organizations/[id].delete.ts b/server/api/organization/[id].delete.ts
similarity index 100%
rename from server/api/organizations/[id].delete.ts
rename to server/api/organization/[id].delete.ts
diff --git a/server/api/organizations/[id].get.ts b/server/api/organization/[id].get.ts
similarity index 100%
rename from server/api/organizations/[id].get.ts
rename to server/api/organization/[id].get.ts
diff --git a/server/api/organizations/[id].put.ts b/server/api/organization/[id].put.ts
similarity index 94%
rename from server/api/organizations/[id].put.ts
rename to server/api/organization/[id].put.ts
index d3d01cb6..d03bf8f1 100644
--- a/server/api/organizations/[id].put.ts
+++ b/server/api/organization/[id].put.ts
@@ -26,5 +26,5 @@ export default defineEventHandler(async (event) => {
slug: name ? slugify(name) : organization.slug
})
- await em.flush()
+ await em.persistAndFlush(organization)
})
\ No newline at end of file
diff --git a/server/api/organizations/index.get.ts b/server/api/organization/index.get.ts
similarity index 100%
rename from server/api/organizations/index.get.ts
rename to server/api/organization/index.get.ts
diff --git a/server/api/organizations/index.post.ts b/server/api/organization/index.post.ts
similarity index 100%
rename from server/api/organizations/index.post.ts
rename to server/api/organization/index.post.ts
diff --git a/server/api/outcomes/[id].delete.ts b/server/api/outcome/[id].delete.ts
similarity index 100%
rename from server/api/outcomes/[id].delete.ts
rename to server/api/outcome/[id].delete.ts
diff --git a/server/api/outcomes/[id].get.ts b/server/api/outcome/[id].get.ts
similarity index 92%
rename from server/api/outcomes/[id].get.ts
rename to server/api/outcome/[id].get.ts
index 169f1d9e..aad419c6 100644
--- a/server/api/outcomes/[id].get.ts
+++ b/server/api/outcome/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Outcome } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/outcomes/[id].put.ts b/server/api/outcome/[id].put.ts
similarity index 96%
rename from server/api/outcomes/[id].put.ts
rename to server/api/outcome/[id].put.ts
index fdf50a29..45ad66a5 100644
--- a/server/api/outcomes/[id].put.ts
+++ b/server/api/outcome/[id].put.ts
@@ -31,5 +31,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(outcome)
})
\ No newline at end of file
diff --git a/server/api/outcomes/index.get.ts b/server/api/outcome/index.get.ts
similarity index 100%
rename from server/api/outcomes/index.get.ts
rename to server/api/outcome/index.get.ts
diff --git a/server/api/outcomes/index.post.ts b/server/api/outcome/index.post.ts
similarity index 100%
rename from server/api/outcomes/index.post.ts
rename to server/api/outcome/index.post.ts
diff --git a/server/api/parse-requirement/follows.get.ts b/server/api/parse-requirement/follows.get.ts
new file mode 100644
index 00000000..7f8cac53
--- /dev/null
+++ b/server/api/parse-requirement/follows.get.ts
@@ -0,0 +1,30 @@
+import { z } from "zod"
+import { fork } from "~/server/data/orm.js"
+import { ParsedRequirement, Requirement } from "~/server/domain/requirements/index.js"
+import { Follows } from "~/server/domain/relations/index.js"
+
+const querySchema = z.object({
+ solutionId: z.string().uuid(),
+ id: z.string().uuid()
+})
+
+/**
+ * Get all unapproved requirements that follow from the specified parsed requirement
+ */
+export default defineEventHandler(async (event) => {
+ const { solutionId, id } = await validateEventQuery(event, querySchema),
+ { solution } = await assertSolutionReader(event, solutionId),
+ em = fork(),
+ parsedRequirement = await assertReqBelongsToSolution(em, ParsedRequirement, id, solution),
+ follows = await em.find(Follows, {
+ right: parsedRequirement,
+ left: { isSilence: true }
+ }, { populate: ['left'] })
+
+ const groupedResult = groupBy(
+ follows.map(f => f.left) as Requirement[],
+ ({ req_type }) => req_type
+ )
+
+ return groupedResult
+})
\ No newline at end of file
diff --git a/server/api/parse-requirements/index.get.ts b/server/api/parse-requirement/index.get.ts
similarity index 92%
rename from server/api/parse-requirements/index.get.ts
rename to server/api/parse-requirement/index.get.ts
index 6ef697a4..ff8a8a9b 100644
--- a/server/api/parse-requirements/index.get.ts
+++ b/server/api/parse-requirement/index.get.ts
@@ -1,7 +1,6 @@
import { z } from "zod";
import { fork } from "~/server/data/orm.js"
import { ParsedRequirement, ReqType } from "~/server/domain/requirements/index.js";
-import { Belongs } from "~/server/domain/relations";
const querySchema = z.object({
solutionId: z.string().uuid()
diff --git a/server/api/parse-requirements/index.post.ts b/server/api/parse-requirement/index.post.ts
similarity index 92%
rename from server/api/parse-requirements/index.post.ts
rename to server/api/parse-requirement/index.post.ts
index a66e8619..38e2a6e3 100644
--- a/server/api/parse-requirements/index.post.ts
+++ b/server/api/parse-requirement/index.post.ts
@@ -73,20 +73,7 @@ export default defineEventHandler(async (event) => {
[K in ArrayToUnion['type']]?: ExtractGroupItem[]
}
- // The server is currently Node 20 which does not support Object.groupBy.
- // See: https://github.com/final-hill/cathedral/issues/371
- if (!Object.groupBy) {
- Object.groupBy = function (items: Iterable, keySelector: (item: T, index: number) => K): Partial> {
- return [...items].reduce((acc, item, index) => {
- const key = keySelector(item, index),
- group = (acc as any)[key as any] ?? ((acc as any)[key as any] = [])
- group.push(item)
- return acc
- }, {} as Partial>)
- }
- }
-
- const groupedResult = Object.groupBy(result, ({ type }) => type) as GroupedResult
+ const groupedResult = groupBy(result, ({ type }) => type) as GroupedResult
const parsedRequirement = em.create(ParsedRequirement, {
name: '{LLM Parsed Requirement}',
@@ -138,8 +125,7 @@ export default defineEventHandler(async (event) => {
lastModified: new Date(),
modifiedBy: sessionUser,
name: item.name,
- description: item.description,
- parentComponent: undefined
+ description: item.description
})
em.create(Belongs, { left: environmentComponent, right: solution });
em.create(Follows, { left: environmentComponent, right: parsedRequirement });
@@ -162,8 +148,7 @@ export default defineEventHandler(async (event) => {
lastModified: new Date(),
modifiedBy: sessionUser,
name: item.name,
- description: item.description,
- parentComponent: undefined
+ description: item.description
})
em.create(Belongs, { left: glossaryTerm, right: solution });
em.create(Follows, { left: glossaryTerm, right: parsedRequirement });
@@ -257,7 +242,6 @@ export default defineEventHandler(async (event) => {
influence: item.influence,
description: '',
category: item.category as StakeholderCategory,
- parentComponent: undefined,
segmentation: item.segmentation as StakeholderSegmentation
})
em.create(Belongs, { left: stakeholder, right: solution });
@@ -269,8 +253,7 @@ export default defineEventHandler(async (event) => {
lastModified: new Date(),
modifiedBy: sessionUser,
name: item.name,
- description: item.description,
- parentComponent: undefined
+ description: item.description
})
em.create(Belongs, { left: systemComponent, right: solution });
em.create(Follows, { left: systemComponent, right: parsedRequirement });
@@ -312,7 +295,6 @@ export default defineEventHandler(async (event) => {
influence: 50,
description: '',
category: StakeholderCategory.KEY_STAKEHOLDER,
- parentComponent: undefined,
segmentation: StakeholderSegmentation.VENDOR,
})
})
@@ -355,7 +337,6 @@ export default defineEventHandler(async (event) => {
influence: 50,
description: '',
category: StakeholderCategory.KEY_STAKEHOLDER,
- parentComponent: undefined,
segmentation: StakeholderSegmentation.VENDOR
})
})
diff --git a/server/api/persons/[id].delete.ts b/server/api/person/[id].delete.ts
similarity index 100%
rename from server/api/persons/[id].delete.ts
rename to server/api/person/[id].delete.ts
diff --git a/server/api/persons/[id].get.ts b/server/api/person/[id].get.ts
similarity index 92%
rename from server/api/persons/[id].get.ts
rename to server/api/person/[id].get.ts
index 25232f69..96a45cbd 100644
--- a/server/api/persons/[id].get.ts
+++ b/server/api/person/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Person } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/persons/[id].put.ts b/server/api/person/[id].put.ts
similarity index 96%
rename from server/api/persons/[id].put.ts
rename to server/api/person/[id].put.ts
index 112c2643..0a1e8698 100644
--- a/server/api/persons/[id].put.ts
+++ b/server/api/person/[id].put.ts
@@ -33,5 +33,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(person)
})
\ No newline at end of file
diff --git a/server/api/persons/index.get.ts b/server/api/person/index.get.ts
similarity index 100%
rename from server/api/persons/index.get.ts
rename to server/api/person/index.get.ts
diff --git a/server/api/persons/index.post.ts b/server/api/person/index.post.ts
similarity index 100%
rename from server/api/persons/index.post.ts
rename to server/api/person/index.post.ts
diff --git a/server/api/solutions/[id].delete.ts b/server/api/solution/[id].delete.ts
similarity index 100%
rename from server/api/solutions/[id].delete.ts
rename to server/api/solution/[id].delete.ts
diff --git a/server/api/solutions/[id].get.ts b/server/api/solution/[id].get.ts
similarity index 100%
rename from server/api/solutions/[id].get.ts
rename to server/api/solution/[id].get.ts
diff --git a/server/api/solutions/[id].put.ts b/server/api/solution/[id].put.ts
similarity index 94%
rename from server/api/solutions/[id].put.ts
rename to server/api/solution/[id].put.ts
index 0c9677f3..4c73048c 100644
--- a/server/api/solutions/[id].put.ts
+++ b/server/api/solution/[id].put.ts
@@ -24,5 +24,5 @@ export default defineEventHandler(async (event) => {
description: description ?? solution.description
})
- await em.flush()
+ await em.persistAndFlush(solution)
})
\ No newline at end of file
diff --git a/server/api/solutions/index.get.ts b/server/api/solution/index.get.ts
similarity index 100%
rename from server/api/solutions/index.get.ts
rename to server/api/solution/index.get.ts
diff --git a/server/api/solutions/index.post.ts b/server/api/solution/index.post.ts
similarity index 94%
rename from server/api/solutions/index.post.ts
rename to server/api/solution/index.post.ts
index 84bae2cc..b48c2175 100644
--- a/server/api/solutions/index.post.ts
+++ b/server/api/solution/index.post.ts
@@ -1,4 +1,3 @@
-import { e } from "@vite-pwa/assets-generator/dist/shared/assets-generator.5e51fd40.mjs"
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Solution } from "~/server/domain/requirements/index.js"
diff --git a/server/api/stakeholders/[id].delete.ts b/server/api/stakeholder/[id].delete.ts
similarity index 100%
rename from server/api/stakeholders/[id].delete.ts
rename to server/api/stakeholder/[id].delete.ts
diff --git a/server/api/stakeholders/[id].get.ts b/server/api/stakeholder/[id].get.ts
similarity index 93%
rename from server/api/stakeholders/[id].get.ts
rename to server/api/stakeholder/[id].get.ts
index 96b65420..0690be8f 100644
--- a/server/api/stakeholders/[id].get.ts
+++ b/server/api/stakeholder/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { Stakeholder } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/stakeholders/[id].put.ts b/server/api/stakeholder/[id].put.ts
similarity index 67%
rename from server/api/stakeholders/[id].put.ts
rename to server/api/stakeholder/[id].put.ts
index 853cc734..67363128 100644
--- a/server/api/stakeholders/[id].put.ts
+++ b/server/api/stakeholder/[id].put.ts
@@ -1,5 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
+import { Belongs } from "~/server/domain/relations"
import { Stakeholder, StakeholderSegmentation, StakeholderCategory } from "~/server/domain/requirements/index.js"
const paramSchema = z.object({
@@ -27,11 +28,13 @@ export default defineEventHandler(async (event) => {
await validateEventBody(event, bodySchema),
{ sessionUser, solution } = await assertSolutionContributor(event, solutionId),
em = fork(),
- stakeholder = await assertReqBelongsToSolution(em, Stakeholder, id, solution)
+ stakeholder = await assertReqBelongsToSolution(em, Stakeholder, id, solution),
+ parentComponent = parentComponentId ? await assertReqBelongsToSolution(em, Stakeholder, parentComponentId, solution) : undefined
-
- if (parentComponentId)
- stakeholder.parentComponent = await assertReqBelongsToSolution(em, Stakeholder, parentComponentId, solution)
+ const existingParentComponent = await em.findOne(Belongs, {
+ left: stakeholder,
+ right: parentComponent
+ })
stakeholder.assign({
name: name ?? stakeholder.name,
@@ -45,5 +48,16 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ if (!existingParentComponent && parentComponent) {
+ em.create(Belongs, { left: stakeholder, right: parentComponent })
+ } else if (existingParentComponent && !parentComponent) {
+ em.remove(existingParentComponent)
+ } else if (existingParentComponent && parentComponent) {
+ em.remove(existingParentComponent)
+ em.create(Belongs, { left: stakeholder, right: parentComponent })
+ } else {
+ // Do nothing
+ }
+
+ await em.persistAndFlush(stakeholder)
})
\ No newline at end of file
diff --git a/server/api/stakeholders/index.get.ts b/server/api/stakeholder/index.get.ts
similarity index 100%
rename from server/api/stakeholders/index.get.ts
rename to server/api/stakeholder/index.get.ts
diff --git a/server/api/stakeholders/index.post.ts b/server/api/stakeholder/index.post.ts
similarity index 88%
rename from server/api/stakeholders/index.post.ts
rename to server/api/stakeholder/index.post.ts
index 668d6291..fec1dfd1 100644
--- a/server/api/stakeholders/index.post.ts
+++ b/server/api/stakeholder/index.post.ts
@@ -19,7 +19,7 @@ const bodySchema = z.object({
* Creates a new stakeholder and returns its id
*/
export default defineEventHandler(async (event) => {
- const { availability, category, influence, name, segmentation, description, parentComponentId, solutionId, isSilence }
+ const { availability, category, influence, name, segmentation, description, solutionId, isSilence, parentComponentId }
= await validateEventBody(event, bodySchema),
{ solution, sessionUser } = await assertSolutionContributor(event, solutionId),
em = fork()
@@ -33,12 +33,14 @@ export default defineEventHandler(async (event) => {
category,
lastModified: new Date(),
modifiedBy: sessionUser,
- isSilence,
- parentComponent: parentComponentId ? em.getReference(Stakeholder, parentComponentId) : undefined
+ isSilence
})
em.create(Belongs, { left: newStakeholder, right: solution })
+ if (parentComponentId)
+ em.create(Belongs, { left: newStakeholder, right: parentComponentId })
+
await em.flush()
return newStakeholder.id
diff --git a/server/api/system-components/[id].delete.ts b/server/api/system-component/[id].delete.ts
similarity index 100%
rename from server/api/system-components/[id].delete.ts
rename to server/api/system-component/[id].delete.ts
diff --git a/server/api/system-components/[id].get.ts b/server/api/system-component/[id].get.ts
similarity index 93%
rename from server/api/system-components/[id].get.ts
rename to server/api/system-component/[id].get.ts
index 16736474..c8d6f829 100644
--- a/server/api/system-components/[id].get.ts
+++ b/server/api/system-component/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { SystemComponent } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/system-components/[id].put.ts b/server/api/system-component/[id].put.ts
similarity index 50%
rename from server/api/system-components/[id].put.ts
rename to server/api/system-component/[id].put.ts
index 0f7e6a7e..988d5a87 100644
--- a/server/api/system-components/[id].put.ts
+++ b/server/api/system-component/[id].put.ts
@@ -1,5 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
+import { Belongs } from "~/server/domain/relations"
import { SystemComponent } from "~/server/domain/requirements/index.js"
const paramSchema = z.object({
@@ -10,7 +11,7 @@ const bodySchema = z.object({
solutionId: z.string().uuid(),
name: z.string().optional(),
description: z.string().optional(),
- parentComponentId: z.string().uuid().optional(),
+ parentComponent: z.string().uuid().optional(),
isSilence: z.boolean().optional()
})
@@ -19,13 +20,16 @@ const bodySchema = z.object({
*/
export default defineEventHandler(async (event) => {
const { id } = await validateEventParams(event, paramSchema),
- { name, description, parentComponentId, solutionId, isSilence } = await validateEventBody(event, bodySchema),
+ { name, description, parentComponent, solutionId, isSilence } = await validateEventBody(event, bodySchema),
{ sessionUser, solution } = await assertSolutionContributor(event, solutionId),
em = fork(),
- systemComponent = await assertReqBelongsToSolution(em, SystemComponent, id, solution)
+ systemComponent = await assertReqBelongsToSolution(em, SystemComponent, id, solution),
+ pComponent = parentComponent ? await assertReqBelongsToSolution(em, SystemComponent, parentComponent, solution) : undefined
- if (parentComponentId)
- systemComponent.parentComponent = await assertReqBelongsToSolution(em, SystemComponent, parentComponentId, solution)
+ const existingParentComponent = await em.findOne(Belongs, {
+ left: systemComponent,
+ right: pComponent
+ })
systemComponent.assign({
name: name ?? systemComponent.name,
@@ -35,5 +39,16 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ if (!existingParentComponent && pComponent) {
+ em.create(Belongs, { left: systemComponent, right: pComponent })
+ } else if (existingParentComponent && !pComponent) {
+ em.remove(existingParentComponent)
+ } else if (existingParentComponent && pComponent) {
+ em.remove(existingParentComponent)
+ em.create(Belongs, { left: systemComponent, right: pComponent })
+ } else {
+ // Do nothing
+ }
+
+ await em.persistAndFlush(systemComponent)
})
\ No newline at end of file
diff --git a/server/api/system-component/index.get.ts b/server/api/system-component/index.get.ts
new file mode 100644
index 00000000..802c0dfb
--- /dev/null
+++ b/server/api/system-component/index.get.ts
@@ -0,0 +1,42 @@
+import { z } from "zod"
+import { fork } from "~/server/data/orm.js"
+import { Belongs } from "~/server/domain/relations"
+import { ReqType, SystemComponent } from "~/server/domain/requirements/index.js"
+import { type ReqRelModel } from "~/server/domain/types"
+
+const querySchema = z.object({
+ solutionId: z.string().uuid(),
+ name: z.string().optional(),
+ description: z.string().optional(),
+ parentComponent: z.string().uuid().optional(),
+ isSilence: z.boolean().optional().default(false)
+})
+
+/**
+ * Returns all system-components that match the query parameters
+ */
+export default defineEventHandler(async (event) => {
+ const query = await validateEventQuery(event, querySchema),
+ em = fork()
+
+ await assertSolutionReader(event, query.solutionId)
+
+ const sysComponents = await findAllSolutionRequirements(ReqType.SYSTEM_COMPONENT, em, query),
+ parentComponents = await em.find(Belongs, {
+ left: sysComponents,
+ right: {
+ req_type: ReqType.SYSTEM_COMPONENT,
+ ...(query.parentComponent ? { id: query.parentComponent } : {})
+ }
+ }, { populate: ['right'] }),
+ joinedComponents = sysComponents.map(sysComp => {
+ const parent = parentComponents.find(pc => pc.left.id === sysComp.id)
+ return {
+ ...sysComp,
+ solutionId: query.solutionId,
+ parentComponent: parent?.right
+ }
+ }) as unknown as ReqRelModel[]
+
+ return joinedComponents
+})
\ No newline at end of file
diff --git a/server/api/system-components/index.post.ts b/server/api/system-component/index.post.ts
similarity index 75%
rename from server/api/system-components/index.post.ts
rename to server/api/system-component/index.post.ts
index a0ea17ee..61a26ad4 100644
--- a/server/api/system-components/index.post.ts
+++ b/server/api/system-component/index.post.ts
@@ -7,7 +7,7 @@ const bodySchema = z.object({
solutionId: z.string().uuid(),
name: z.string().default("{Untitled System Component}"),
description: z.string().default(""),
- parentComponentId: z.string().uuid().optional(),
+ parentComponent: z.string().uuid().optional(),
isSilence: z.boolean().default(false)
})
@@ -15,7 +15,7 @@ const bodySchema = z.object({
* Creates a new system-component and returns its id
*/
export default defineEventHandler(async (event) => {
- const { name, description, parentComponentId, solutionId, isSilence } = await validateEventBody(event, bodySchema),
+ const { name, description, parentComponent, solutionId, isSilence } = await validateEventBody(event, bodySchema),
{ solution, sessionUser } = await assertSolutionContributor(event, solutionId),
em = fork()
@@ -24,12 +24,14 @@ export default defineEventHandler(async (event) => {
description,
lastModified: new Date(),
modifiedBy: sessionUser,
- isSilence,
- parentComponent: parentComponentId ? em.getReference(SystemComponent, parentComponentId) : undefined
+ isSilence
})
em.create(Belongs, { left: newSystemComponent, right: solution })
+ if (parentComponent)
+ em.create(Belongs, { left: newSystemComponent, right: parentComponent })
+
await em.flush()
return newSystemComponent.id
diff --git a/server/api/system-components/index.get.ts b/server/api/system-components/index.get.ts
deleted file mode 100644
index 337d99d9..00000000
--- a/server/api/system-components/index.get.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { z } from "zod"
-import { fork } from "~/server/data/orm.js"
-import { ReqType, SystemComponent } from "~/server/domain/requirements/index.js"
-
-const querySchema = z.object({
- solutionId: z.string().uuid(),
- name: z.string().optional(),
- description: z.string().optional(),
- parentComponentId: z.string().uuid().optional(),
- isSilence: z.boolean().optional().default(false)
-})
-
-/**
- * Returns all system-components that match the query parameters
- */
-export default defineEventHandler(async (event) => {
- const query = await validateEventQuery(event, querySchema),
- em = fork()
-
- await assertSolutionReader(event, query.solutionId)
-
- return await findAllSolutionRequirements(ReqType.SYSTEM_COMPONENT, em, query)
-})
\ No newline at end of file
diff --git a/server/api/use-cases/[id].delete.ts b/server/api/use-case/[id].delete.ts
similarity index 100%
rename from server/api/use-cases/[id].delete.ts
rename to server/api/use-case/[id].delete.ts
diff --git a/server/api/use-cases/[id].get.ts b/server/api/use-case/[id].get.ts
similarity index 92%
rename from server/api/use-cases/[id].get.ts
rename to server/api/use-case/[id].get.ts
index a5b696cb..ac149a55 100644
--- a/server/api/use-cases/[id].get.ts
+++ b/server/api/use-case/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { UseCase } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/use-cases/[id].put.ts b/server/api/use-case/[id].put.ts
similarity index 82%
rename from server/api/use-cases/[id].put.ts
rename to server/api/use-case/[id].put.ts
index 807e8af3..7c654618 100644
--- a/server/api/use-cases/[id].put.ts
+++ b/server/api/use-case/[id].put.ts
@@ -10,15 +10,15 @@ const bodySchema = z.object({
solutionId: z.string().uuid(),
name: z.string().optional(),
description: z.string().optional(),
- primaryActorId: z.string().uuid().optional(),
+ primaryActor: z.string().uuid().optional(),
priority: z.nativeEnum(MoscowPriority).optional(),
scope: z.string().optional(),
level: z.string().optional(),
goalInContext: z.string().optional(),
- preconditionId: z.string().uuid().optional(),
+ precondition: z.string().uuid().optional(),
triggerId: z.string().uuid().optional(),
mainSuccessScenario: z.string().optional(),
- successGuaranteeId: z.string().uuid().optional(),
+ successGuarantee: z.string().uuid().optional(),
extensions: z.string().optional(),
isSilence: z.boolean().optional()
})
@@ -33,12 +33,12 @@ export default defineEventHandler(async (event) => {
em = fork(),
useCase = await assertReqBelongsToSolution(em, UseCase, id, solution)
- if (body.primaryActorId)
- useCase.primaryActor = await assertReqBelongsToSolution(em, Stakeholder, body.primaryActorId, solution)
- if (body.preconditionId)
- useCase.precondition = await assertReqBelongsToSolution(em, Assumption, body.preconditionId, solution)
- if (body.successGuaranteeId)
- useCase.successGuarantee = await assertReqBelongsToSolution(em, Effect, body.successGuaranteeId, solution)
+ if (body.primaryActor)
+ useCase.primaryActor = await assertReqBelongsToSolution(em, Stakeholder, body.primaryActor, solution)
+ if (body.precondition)
+ useCase.precondition = await assertReqBelongsToSolution(em, Assumption, body.precondition, solution)
+ if (body.successGuarantee)
+ useCase.successGuarantee = await assertReqBelongsToSolution(em, Effect, body.successGuarantee, solution)
useCase.assign({
name: body.name ?? useCase.name,
@@ -55,5 +55,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(useCase)
})
\ No newline at end of file
diff --git a/server/api/use-cases/index.get.ts b/server/api/use-case/index.get.ts
similarity index 82%
rename from server/api/use-cases/index.get.ts
rename to server/api/use-case/index.get.ts
index 3aafadcc..adde2173 100644
--- a/server/api/use-cases/index.get.ts
+++ b/server/api/use-case/index.get.ts
@@ -7,15 +7,15 @@ const querySchema = z.object({
solutionId: z.string().uuid(),
name: z.string().optional(),
description: z.string().optional(),
- primaryActorId: z.string().uuid().optional(),
+ primaryActor: z.string().uuid().optional(),
priority: z.nativeEnum(MoscowPriority).optional(),
scope: z.string().optional(),
level: z.string().optional(),
goalInContext: z.string().optional(),
- preconditionId: z.string().uuid().optional(),
+ precondition: z.string().uuid().optional(),
triggerId: z.literal(emptyUuid).optional(),
mainSuccessScenario: z.string().optional(),
- successGuaranteeId: z.string().uuid().optional(),
+ successGuarantee: z.string().uuid().optional(),
extensions: z.string().optional(),
isSilence: z.boolean().optional().default(false)
})
@@ -29,5 +29,5 @@ export default defineEventHandler(async (event) => {
await assertSolutionReader(event, query.solutionId)
- return await findAllSolutionRequirements(ReqType.USE_CASE, em, query)
+ return await findAllSolutionRequirements(ReqType.USE_CASE, em, query, ['primaryActor', 'precondition', 'successGuarantee'])
})
\ No newline at end of file
diff --git a/server/api/use-cases/index.post.ts b/server/api/use-case/index.post.ts
similarity index 77%
rename from server/api/use-cases/index.post.ts
rename to server/api/use-case/index.post.ts
index 6f8b3ee2..a1056d63 100644
--- a/server/api/use-cases/index.post.ts
+++ b/server/api/use-case/index.post.ts
@@ -8,15 +8,15 @@ const bodySchema = z.object({
solutionId: z.string().uuid(),
name: z.string(),
description: z.string(),
- primaryActorId: z.string().uuid(),
+ primaryActor: z.string().uuid(),
priority: z.nativeEnum(MoscowPriority),
scope: z.string(),
level: z.string(),
goalInContext: z.string(),
- preconditionId: z.string().uuid(),
+ precondition: z.string().uuid(),
triggerId: z.literal(emptyUuid),
mainSuccessScenario: z.string(),
- successGuaranteeId: z.string().uuid(),
+ successGuarantee: z.string().uuid(),
extensions: z.string(),
isSilence: z.boolean().default(false)
})
@@ -32,15 +32,15 @@ export default defineEventHandler(async (event) => {
const newUseCase = new UseCase({
name: body.name,
description: body.description,
- primaryActor: body.primaryActorId ? em.getReference(Stakeholder, body.primaryActorId) : undefined,
+ primaryActor: body.primaryActor ? em.getReference(Stakeholder, body.primaryActor) : undefined,
priority: body.priority,
scope: body.scope,
level: body.level,
goalInContext: body.goalInContext,
- precondition: body.preconditionId ? em.getReference(Assumption, body.preconditionId) : undefined,
+ precondition: body.precondition ? em.getReference(Assumption, body.precondition) : undefined,
triggerId: body.triggerId,
mainSuccessScenario: body.mainSuccessScenario,
- successGuarantee: body.successGuaranteeId ? em.getReference(Effect, body.successGuaranteeId) : undefined,
+ successGuarantee: body.successGuarantee ? em.getReference(Effect, body.successGuarantee) : undefined,
extensions: body.extensions,
lastModified: new Date(),
modifiedBy: sessionUser,
diff --git a/server/api/user-stories/[id].delete.ts b/server/api/user-story/[id].delete.ts
similarity index 100%
rename from server/api/user-stories/[id].delete.ts
rename to server/api/user-story/[id].delete.ts
diff --git a/server/api/user-stories/[id].get.ts b/server/api/user-story/[id].get.ts
similarity index 92%
rename from server/api/user-stories/[id].get.ts
rename to server/api/user-story/[id].get.ts
index e2651cd7..300cb533 100644
--- a/server/api/user-stories/[id].get.ts
+++ b/server/api/user-story/[id].get.ts
@@ -1,7 +1,6 @@
import { z } from "zod"
import { fork } from "~/server/data/orm.js"
import { UserStory } from "~/server/domain/requirements/index.js"
-import { Belongs } from "~/server/domain/relations"
const paramSchema = z.object({
id: z.string().uuid()
diff --git a/server/api/user-stories/[id].put.ts b/server/api/user-story/[id].put.ts
similarity index 77%
rename from server/api/user-stories/[id].put.ts
rename to server/api/user-story/[id].put.ts
index 7d6f6be2..092fa95a 100644
--- a/server/api/user-stories/[id].put.ts
+++ b/server/api/user-story/[id].put.ts
@@ -10,10 +10,10 @@ const bodySchema = z.object({
solutionId: z.string().uuid(),
name: z.string().optional(),
description: z.string().optional(),
- primaryActorId: z.string().uuid().optional(),
+ primaryActor: z.string().uuid().optional(),
priority: z.nativeEnum(MoscowPriority).optional(),
- outcomeId: z.string().uuid().optional(),
- functionalBehaviorId: z.string().uuid().optional(),
+ outcome: z.string().uuid().optional(),
+ functionalBehavior: z.string().uuid().optional(),
isSilence: z.boolean().optional()
})
@@ -27,12 +27,12 @@ export default defineEventHandler(async (event) => {
em = fork(),
userStory = await assertReqBelongsToSolution(em, UserStory, id, solution)
- if (body.primaryActorId)
- userStory.primaryActor = await assertReqBelongsToSolution(em, Stakeholder, body.primaryActorId, solution)
- if (body.outcomeId)
- userStory.outcome = await assertReqBelongsToSolution(em, Outcome, body.outcomeId, solution)
- if (body.functionalBehaviorId)
- userStory.functionalBehavior = await assertReqBelongsToSolution(em, FunctionalBehavior, body.functionalBehaviorId, solution)
+ if (body.primaryActor)
+ userStory.primaryActor = await assertReqBelongsToSolution(em, Stakeholder, body.primaryActor, solution)
+ if (body.outcome)
+ userStory.outcome = await assertReqBelongsToSolution(em, Outcome, body.outcome, solution)
+ if (body.functionalBehavior)
+ userStory.functionalBehavior = await assertReqBelongsToSolution(em, FunctionalBehavior, body.functionalBehavior, solution)
userStory.assign({
name: body.name ?? userStory.name,
@@ -43,5 +43,5 @@ export default defineEventHandler(async (event) => {
lastModified: new Date()
})
- await em.flush()
+ await em.persistAndFlush(userStory)
})
\ No newline at end of file
diff --git a/server/api/user-stories/index.get.ts b/server/api/user-story/index.get.ts
similarity index 92%
rename from server/api/user-stories/index.get.ts
rename to server/api/user-story/index.get.ts
index ed36fa5f..e62481cd 100644
--- a/server/api/user-stories/index.get.ts
+++ b/server/api/user-story/index.get.ts
@@ -22,5 +22,5 @@ export default defineEventHandler(async (event) => {
await assertSolutionReader(event, query.solutionId)
- return await findAllSolutionRequirements(ReqType.USER_STORY, em, query)
+ return await findAllSolutionRequirements(ReqType.USER_STORY, em, query, ['primaryActor', 'outcome', 'functionalBehavior'])
})
\ No newline at end of file
diff --git a/server/api/user-stories/index.post.ts b/server/api/user-story/index.post.ts
similarity index 71%
rename from server/api/user-stories/index.post.ts
rename to server/api/user-story/index.post.ts
index 361b8970..73ad4dd8 100644
--- a/server/api/user-stories/index.post.ts
+++ b/server/api/user-story/index.post.ts
@@ -7,10 +7,10 @@ const bodySchema = z.object({
solutionId: z.string().uuid(),
name: z.string().default("{Untitled User Story}"),
description: z.string().default(""),
- primaryActorId: z.string().uuid().optional(),
+ primaryActor: z.string().uuid().optional(),
priority: z.nativeEnum(MoscowPriority).default(MoscowPriority.MUST),
- outcomeId: z.string().uuid().optional(),
- functionalBehaviorId: z.string().uuid().optional(),
+ outcome: z.string().uuid().optional(),
+ functionalBehavior: z.string().uuid().optional(),
isSilence: z.boolean().default(false)
})
@@ -23,11 +23,11 @@ export default defineEventHandler(async (event) => {
em = fork()
const newUserStory = new UserStory({
- functionalBehavior: body.functionalBehaviorId ? em.getReference(FunctionalBehavior, body.functionalBehaviorId) : undefined,
- outcome: body.outcomeId ? em.getReference(Outcome, body.outcomeId) : undefined,
+ functionalBehavior: body.functionalBehavior ? em.getReference(FunctionalBehavior, body.functionalBehavior) : undefined,
+ outcome: body.outcome ? em.getReference(Outcome, body.outcome) : undefined,
name: body.name,
description: body.description,
- primaryActor: body.primaryActorId ? em.getReference(Stakeholder, body.primaryActorId) : undefined,
+ primaryActor: body.primaryActor ? em.getReference(Stakeholder, body.primaryActor) : undefined,
priority: body.priority,
lastModified: new Date(),
modifiedBy: sessionUser,
diff --git a/server/domain/application/AuditLog.ts b/server/domain/application/AuditLog.ts
index 8d77d310..cb090a6d 100644
--- a/server/domain/application/AuditLog.ts
+++ b/server/domain/application/AuditLog.ts
@@ -7,19 +7,21 @@ import { type Properties } from '../types/index.js';
*/
@Entity()
export class AuditLog extends BaseEntity {
- constructor(props: Properties>) {
+ constructor(props: Properties> & { id?: string, createdAt?: Date }) {
super()
this.type = props.type;
this.entity = props.entity;
this.entityId = props.entityId;
this.entityName = props.entityName;
+ this.createdAt = props.createdAt || new Date();
+ this.id = props.id || uuidv7();
}
/**
* The unique identifier of the AuditLog
*/
@Property({ type: 'uuid', primary: true })
- id: string = uuidv7();
+ id: string
/**
* The unique identifier of the entity that was changed
@@ -49,5 +51,5 @@ export class AuditLog extends BaseEntity {
* The date and time when the AuditLog was created
*/
@Property({ type: 'datetime' })
- createdAt: Date = new Date();
+ createdAt: Date
}
\ No newline at end of file
diff --git a/server/domain/relations/Characterizes.ts b/server/domain/relations/Characterizes.ts
index bfaa8748..bf0aad0f 100644
--- a/server/domain/relations/Characterizes.ts
+++ b/server/domain/relations/Characterizes.ts
@@ -1,4 +1,4 @@
-import { Entity, ManyToOne } from "@mikro-orm/core";
+import { Entity } from "@mikro-orm/core";
import { RequirementRelation } from "./RequirementRelation.js";
import { MetaRequirement } from "../requirements/MetaRequirement.js";
import { type Properties } from "../types/index.js";
diff --git a/server/domain/relations/RequirementRelation.ts b/server/domain/relations/RequirementRelation.ts
index e6b2b66c..18de2c3a 100644
--- a/server/domain/relations/RequirementRelation.ts
+++ b/server/domain/relations/RequirementRelation.ts
@@ -1,5 +1,5 @@
import { v7 as uuidv7 } from 'uuid';
-import { BaseEntity, Entity, ManyToOne, Property } from "@mikro-orm/core";
+import { BaseEntity, Cascade, Entity, ManyToOne, Property } from "@mikro-orm/core";
import { Requirement } from '../requirements/Requirement.js'
import { type Properties } from '../types/index.js';
@@ -21,9 +21,9 @@ export abstract class RequirementRelation extends BaseEntity {
@Property({ type: 'uuid', primary: true })
id: string;
- @ManyToOne({ entity: () => Requirement })
+ @ManyToOne({ entity: () => Requirement, cascade: [Cascade.REMOVE] })
left: Requirement
- @ManyToOne({ entity: () => Requirement })
+ @ManyToOne({ entity: () => Requirement, cascade: [Cascade.REMOVE] })
right: Requirement
}
\ No newline at end of file
diff --git a/server/domain/relations/index.ts b/server/domain/relations/index.ts
index c082cea2..d8c1207a 100644
--- a/server/domain/relations/index.ts
+++ b/server/domain/relations/index.ts
@@ -1,4 +1,3 @@
-
export * from './RequirementRelation.js'
export * from './Belongs.js'
export * from './Characterizes.js'
diff --git a/server/domain/requirements/EnvironmentComponent.ts b/server/domain/requirements/EnvironmentComponent.ts
index 25c905cc..f6ea5547 100644
--- a/server/domain/requirements/EnvironmentComponent.ts
+++ b/server/domain/requirements/EnvironmentComponent.ts
@@ -8,15 +8,8 @@ import { ReqType } from "./ReqType.js";
*/
@Entity({ discriminatorValue: ReqType.ENVIRONMENT_COMPONENT })
export class EnvironmentComponent extends Component {
- constructor({ parentComponent, ...rest }: Properties>) {
- super(rest);
- this.parentComponent = parentComponent;
+ constructor(props: Properties>) {
+ super(props);
this.req_type = ReqType.ENVIRONMENT_COMPONENT;
}
-
- /**
- * The parent component of the current environment component if any
- */
- @ManyToOne({ entity: () => EnvironmentComponent })
- parentComponent?: EnvironmentComponent;
}
\ No newline at end of file
diff --git a/server/domain/requirements/GlossaryTerm.ts b/server/domain/requirements/GlossaryTerm.ts
index 1be2b726..f0ec86a6 100644
--- a/server/domain/requirements/GlossaryTerm.ts
+++ b/server/domain/requirements/GlossaryTerm.ts
@@ -8,15 +8,8 @@ import { ReqType } from "./ReqType.js";
*/
@Entity({ discriminatorValue: ReqType.GLOSSARY_TERM })
export class GlossaryTerm extends Component {
- constructor({ parentComponent, ...rest }: Properties>) {
- super(rest);
- this.parentComponent = parentComponent;
+ constructor(props: Properties>) {
+ super(props);
this.req_type = ReqType.GLOSSARY_TERM;
}
-
- /**
- * The parent term of the glossary term, if any.
- */
- @ManyToOne({ entity: () => GlossaryTerm })
- parentComponent?: GlossaryTerm;
}
\ No newline at end of file
diff --git a/server/domain/requirements/ParsedRequirement.ts b/server/domain/requirements/ParsedRequirement.ts
index e48e1635..4bc28d1d 100644
--- a/server/domain/requirements/ParsedRequirement.ts
+++ b/server/domain/requirements/ParsedRequirement.ts
@@ -1,14 +1,8 @@
import { Entity } from '@mikro-orm/core';
-import type { Properties } from '../types/index.js';
+import { type Properties } from '../types/index.js';
import { MetaRequirement } from './MetaRequirement.js';
import { ReqType } from './ReqType.js';
-export type ParsedReqColType = 'assumptions' | 'constraints' |
- 'effects' | 'environmentComponents' | 'functionalBehaviors' |
- 'glossaryTerms' | 'invariants' | 'justifications' | 'limits' |
- 'nonFunctionalBehaviors' | 'obstacles' | 'outcomes' | 'persons' |
- 'stakeholders' | 'systemComponents' | 'useCases' | 'userStories'
-
/**
* A requirement that has been parsed from natural language text
*/
diff --git a/server/domain/requirements/ReqType.ts b/server/domain/requirements/ReqType.ts
index aeb596ef..9b5276ec 100644
--- a/server/domain/requirements/ReqType.ts
+++ b/server/domain/requirements/ReqType.ts
@@ -1,3 +1,7 @@
+// Note: it is assumed that api endpoints are snakeCaseToSlug(requirement.req_type)
+// see the workbox view for a couple example usages
+// TODO: update the architecture to encode this assumption somehow.
+// Nuxt may limit the ability to do this, but it is worth investigating.
export enum ReqType {
ACTOR = 'actor',
ASSUMPTION = 'assumption',
diff --git a/server/domain/requirements/Stakeholder.ts b/server/domain/requirements/Stakeholder.ts
index 3bd8f92b..ee7f8974 100644
--- a/server/domain/requirements/Stakeholder.ts
+++ b/server/domain/requirements/Stakeholder.ts
@@ -17,15 +17,8 @@ export class Stakeholder extends Component {
this.availability = props.availability;
this.segmentation = props.segmentation;
this.category = props.category;
- this.parentComponent = props.parentComponent;
}
- /**
- * The parent component of the stakeholder, if any.
- */
- @ManyToOne({ entity: () => Stakeholder })
- parentComponent?: Stakeholder;
-
/**
* The segmentation of the stakeholder.
*/
diff --git a/server/domain/requirements/SystemComponent.ts b/server/domain/requirements/SystemComponent.ts
index 371f9980..c0b68a82 100644
--- a/server/domain/requirements/SystemComponent.ts
+++ b/server/domain/requirements/SystemComponent.ts
@@ -11,12 +11,5 @@ export class SystemComponent extends Component {
constructor(props: Properties>) {
super(props);
this.req_type = ReqType.SYSTEM_COMPONENT;
- this.parentComponent = props.parentComponent;
}
-
- /**
- * Parent component of the current system component
- */
- @ManyToOne({ entity: () => SystemComponent })
- parentComponent?: SystemComponent;
}
\ No newline at end of file
diff --git a/server/domain/types/index.ts b/server/domain/types/index.ts
index 656ec634..4a4a9425 100644
--- a/server/domain/types/index.ts
+++ b/server/domain/types/index.ts
@@ -1,6 +1,16 @@
+import { Requirement } from "../requirements/Requirement.js";
+
/**
* A type that represents all the members of a type T that are not functions
*/
export type Properties = Pick any ? never : K
-}[keyof T]>;
\ No newline at end of file
+}[keyof T]>;
+
+/**
+ * Represents a requirement model with relations
+ */
+export type ReqRelModel = R & {
+ parentComponent?: string,
+ solutionId: string
+}
\ No newline at end of file
diff --git a/server/utils/findAllSolutionRequirements.ts b/server/utils/findAllSolutionRequirements.ts
index 7ef72a9c..b681784a 100644
--- a/server/utils/findAllSolutionRequirements.ts
+++ b/server/utils/findAllSolutionRequirements.ts
@@ -2,24 +2,41 @@ import { PostgreSqlDriver, SqlEntityManager } from "@mikro-orm/postgresql"
import { Requirement } from "../domain/requirements/Requirement.js"
import { Belongs } from "../domain/relations/index.js"
import { ReqType } from "../domain/requirements/ReqType.js"
+import { type ReqRelModel } from "../domain/types/index.js"
+/**
+ *
+ * @param req_type - The type of requirement to find
+ * @param em - The entity manager
+ * @param query - The query parameters
+ * @param [populate] - The reference fields to populate
+ * @returns
+ */
export default async function findAllSolutionRequirements(
req_type: ReqType,
em: SqlEntityManager,
- query: Record & { solutionId: string }
-): Promise {
- const results = await em.find(Belongs, {
- left: {
- req_type,
- ...Object.entries(query)
- .filter(([key, value]) => value !== undefined && key !== "solutionId")
- .reduce((acc, [key, value]) => ({
- ...acc,
- [key.endsWith("Id") ? key.replace(/Id$/, "") : key]: value
- }), {})
- },
+ query: Record & { solutionId: string, parentComponent?: string },
+ populate: string[] = []
+): Promise[]> {
+ const q = Object.entries(query)
+ .filter(([key, value]) =>
+ value !== undefined && !['solutionId'].includes(key)
+ ).reduce((acc, [key, value]) => ({
+ ...acc,
+ [key.endsWith("Id") ? key.replace(/Id$/, "") : key]: value
+ }), {})
+
+ const solutionItems = await em.find(Belongs, {
+ left: { req_type, ...q },
right: query.solutionId
- }, { populate: ['left'] })
+ }, {
+ populate: [
+ 'left',
+ ...populate.map(prop => `left.${prop}`) as any[]
+ ]
+ })
- return results.map(result => result.left as unknown as R)
+ return solutionItems.map(result =>
+ Object.assign(result.left, { solutionId: query.solutionId }) as unknown as ReqRelModel
+ )
}
\ No newline at end of file
diff --git a/server/utils/groupBy.ts b/server/utils/groupBy.ts
new file mode 100644
index 00000000..d44def06
--- /dev/null
+++ b/server/utils/groupBy.ts
@@ -0,0 +1,10 @@
+// The server is currently Node 20 which does not support Object.groupBy.
+// See: https://github.com/final-hill/cathedral/issues/371
+export const groupBy = function (items: Iterable, keySelector: (item: T, index: number) => K): Partial> {
+ return [...items].reduce((acc, item, index) => {
+ const key = keySelector(item, index),
+ group = (acc as any)[key as any] ?? ((acc as any)[key as any] = [])
+ group.push(item)
+ return acc
+ }, {} as Partial>)
+}
\ No newline at end of file
diff --git a/utils/snakeCaseToSlug.ts b/utils/snakeCaseToSlug.ts
new file mode 100644
index 00000000..91d1c4ea
--- /dev/null
+++ b/utils/snakeCaseToSlug.ts
@@ -0,0 +1,7 @@
+/**
+ * Convert snake_case to slug
+ * @example
+ * snakeCaseToSlug('snake_case_string'); // 'snake-case-string'
+ */
+export default (str: string) =>
+ str.replace(/_/g, '-');
\ No newline at end of file
diff --git a/utils/snakeCaseToTitle.ts b/utils/snakeCaseToTitle.ts
new file mode 100644
index 00000000..b3d9ebd5
--- /dev/null
+++ b/utils/snakeCaseToTitle.ts
@@ -0,0 +1,8 @@
+/**
+ * Convert snake_case to Title Case
+ * @example
+ * snakeCaseToTitle('snake_case_string'); // 'Snake Case String'
+ */
+export default (str: string) =>
+ str.replace(/_/g, ' ')
+ .replace(/\b\w/g, char => char.toUpperCase());
\ No newline at end of file