Skip to content

Commit

Permalink
449 implement application layer (#455)
Browse files Browse the repository at this point in the history
- Refactored to create Application layer
- Refactored View Models to separate folder
- Defined static Requirement.req_type
- Added Epic.protype.functionalBehavior
  • Loading branch information
mlhaufe authored Nov 19, 2024
1 parent 8695997 commit 05aad6b
Show file tree
Hide file tree
Showing 233 changed files with 3,004 additions and 4,572 deletions.
File renamed without changes.
1,068 changes: 1,068 additions & 0 deletions application/OrganizationInteractor.ts

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions application/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './OrganizationInteractor.js'
2 changes: 1 addition & 1 deletion components/TopNavigation.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts" setup>
import deSlugify from '#shared/deSlugify.js';
import deSlugify from '~/shared/deSlugify.js';
const { data, signIn, signOut } = useAuth(),
router = useRouter()
Expand Down
23 changes: 11 additions & 12 deletions components/XDataTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@
import type Dialog from 'primevue/dialog'
import type DataTable from 'primevue/datatable'
import { FilterMatchMode } from 'primevue/api';
import camelCaseToTitle from '#shared/camelCaseToTitle.js';
import camelCaseToTitle from '~/shared/camelCaseToTitle.js';
import type { AuditLogViewModel } from '~/shared/models';
export type ViewFieldType = 'text' | 'textarea' | 'number' | 'date' | 'boolean' | 'hidden' | 'object'
export type RequirementFieldType = { type: 'requirement', options: { id: string, name: string }[] }
export type FormFieldType = 'text' | 'textarea' | { type: 'number', min: number, max: number } | 'date' | 'boolean' | 'hidden' | string[]
| { type: 'requirement', options: { id: string, name: string }[] }
export type ViewFieldType = 'text' | 'textarea' | 'number' | 'date' | 'boolean' | 'hidden' | 'object' | RequirementFieldType
interface AuditLogViewModel {
id: string;
entityId: string;
entityName: string;
entity: string;
organizationSlug: string;
createdAt: Date;
}
export type FormFieldType = 'text' | 'textarea' | { type: 'number', min: number, max: number } | 'date' | 'boolean' | 'hidden' | string[]
| RequirementFieldType
const props = defineProps<{
datasource: RowType[] | null,
Expand Down Expand Up @@ -207,6 +201,11 @@ const onEditDialogCancel = () => {
<span v-else-if="props.viewModel[field as keyof RowType] === 'object'">
{{ data[field]?.name ?? JSON.stringify(data[field]) }}
</span>
<span
v-else-if="(props.viewModel[key as keyof RowType] as RequirementFieldType).type === 'requirement'">
{{ (props.viewModel[key as keyof RowType] as RequirementFieldType).options.find(o => o.id ===
data[key])?.name }}
</span>
<span v-else-if="props.viewModel[field as keyof RowType] === 'textarea'">{{ data[field] }}</span>
<span v-else>{{ data[field] }}</span>
</template>
Expand Down
4 changes: 2 additions & 2 deletions domain/application/AppUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ export class AppUser extends BaseEntity {

/**
* The role of the AppUser.
* Note: this field is not mapped in the ORM. It is populated in the API layer.
* It's a design smell that needs to be addressed.
*/
// FIXME: this field is not mapped in the ORM. It is populated in the API layer.
// It's a design smell that needs to be addressed.
@Enum({ items: () => AppRole, persist: false })
role?: AppRole;
}
6 changes: 1 addition & 5 deletions domain/requirements/Actor.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { Entity } from "@mikro-orm/core";
import { Requirement } from "./Requirement.js";
import { ReqType } from "./ReqType.js";
import { type Properties } from "../types/index.js";

/**
* A part of a Project, Environment, System, or Goals that may affect or be affected by the associated entities
*/
@Entity({ abstract: true, discriminatorValue: ReqType.ACTOR })
export abstract class Actor extends Requirement {
constructor(props: Properties<Omit<Actor, 'id' | 'req_type'>>) {
super(props)
this.req_type = ReqType.ACTOR
}
static override req_type: ReqType = ReqType.ACTOR;
}
14 changes: 5 additions & 9 deletions domain/requirements/Assumption.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import { Entity } from "@mikro-orm/core";
import { Requirement } from "./Requirement.js";
import { type Properties } from "../types/index.js";
import { ReqType } from "./ReqType.js";

export const assumptionReqIdPrefix = 'E.4.' as const;
export type AssumptionReqId = `${typeof assumptionReqIdPrefix}${number}`;
export type AssumptionReqId = `${typeof Assumption.reqIdPrefix}${number}`;

/**
* Posited property of the environment
*/
@Entity({ discriminatorValue: ReqType.ASSUMPTION })
export class Assumption extends Requirement {
constructor(props: Properties<Omit<Assumption, 'id' | 'req_type'>>) {
super(props);
this.req_type = ReqType.ASSUMPTION;
}
static override reqIdPrefix = 'E.4.' as const;
static override req_type = ReqType.ASSUMPTION;

override get reqId(): AssumptionReqId | undefined { return super.reqId as AssumptionReqId | undefined }
override set reqId(value: AssumptionReqId | undefined) { super.reqId = value }
override get reqId() { return super.reqId as `${typeof Assumption.reqIdPrefix}${number}` | undefined }
override set reqId(value) { super.reqId = value }
}
3 changes: 2 additions & 1 deletion domain/requirements/Behavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ import { ReqType } from "./ReqType.js";
*/
@Entity({ abstract: true, discriminatorValue: ReqType.BEHAVIOR })
export class Behavior extends Requirement {
static override req_type: ReqType = ReqType.BEHAVIOR;

constructor({ priority, ...rest }: Properties<Omit<Behavior, 'id' | 'req_type'>>) {
super(rest);
this.priority = priority;
this.req_type = ReqType.BEHAVIOR;
}

/**
Expand Down
6 changes: 1 addition & 5 deletions domain/requirements/Component.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { Entity } from "@mikro-orm/core";
import { Actor } from "./Actor.js";
import { ReqType } from "./ReqType.js";
import { type Properties } from "../types/index.js";

/**
* Idenfitication of a part (of the Project, Environment, Goals, or System)
*/
@Entity({ abstract: true, discriminatorValue: ReqType.COMPONENT })
export abstract class Component extends Actor {
constructor(props: Properties<Omit<Component, 'id' | 'req_type'>>) {
super(props)
this.req_type = ReqType.COMPONENT
}
static override req_type: ReqType = ReqType.COMPONENT;
}
11 changes: 5 additions & 6 deletions domain/requirements/Constraint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,21 @@ import { ConstraintCategory } from './ConstraintCategory.js';
import { type Properties } from '../types/index.js';
import { ReqType } from './ReqType.js';

export const constraintReqIdPrefix = 'E.3.' as const;
export type ConstraintReqId = `${typeof constraintReqIdPrefix}${number}`;

/**
* A Constraint is a property imposed by the environment
*/
@Entity({ discriminatorValue: ReqType.CONSTRAINT })
export class Constraint extends Requirement {
static override reqIdPrefix = 'E.3.' as const;
static override req_type = ReqType.CONSTRAINT;

constructor({ category, ...rest }: Properties<Omit<Constraint, 'id' | 'req_type'>>) {
super(rest);
this.category = category;
this.req_type = ReqType.CONSTRAINT;
}

override get reqId(): ConstraintReqId | undefined { return super.reqId as ConstraintReqId | undefined }
override set reqId(value: ConstraintReqId | undefined) { super.reqId = value }
override get reqId() { return super.reqId as `${typeof Constraint.reqIdPrefix}${number}` | undefined }
override set reqId(value) { super.reqId = value }

/**
* Category of the constraint
Expand Down
14 changes: 4 additions & 10 deletions domain/requirements/Effect.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import { Entity } from "@mikro-orm/core";
import { Requirement } from "./Requirement.js";
import { type Properties } from "../types/index.js";
import { ReqType } from "./ReqType.js";

export const effectReqIdPrefix = 'E.5.' as const;
export type EffectReqId = `${typeof effectReqIdPrefix}${number}`;

/**
* Environment property affected by the system
*/
@Entity({ discriminatorValue: ReqType.EFFECT })
export class Effect extends Requirement {
constructor(props: Properties<Omit<Effect, 'id' | 'req_type'>>) {
super(props);
this.req_type = ReqType.EFFECT;
}
static override reqIdPrefix = 'E.5.' as const;
static override req_type = ReqType.EFFECT;

override get reqId(): EffectReqId | undefined { return super.reqId as EffectReqId | undefined }
override set reqId(value: EffectReqId | undefined) { super.reqId = value }
override get reqId() { return super.reqId as `${typeof Effect.reqIdPrefix}${number}` | undefined }
override set reqId(value) { super.reqId = value }
}
14 changes: 4 additions & 10 deletions domain/requirements/EnvironmentComponent.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import { Entity } from "@mikro-orm/core";
import { Component } from "./Component.js";
import { type Properties } from "../types/index.js";
import { ReqType } from "./ReqType.js";

export const environmentComponentReqIdPrefix = 'E.2.' as const;
export type EnvironmentComponentReqId = `${typeof environmentComponentReqIdPrefix}${number}`;

/**
* Represents a component that is part of an environment.
*/
@Entity({ discriminatorValue: ReqType.ENVIRONMENT_COMPONENT })
export class EnvironmentComponent extends Component {
constructor(props: Properties<Omit<EnvironmentComponent, 'id' | 'req_type'>>) {
super(props);
this.req_type = ReqType.ENVIRONMENT_COMPONENT;
}
static override reqIdPrefix = 'E.2.' as const;
static override req_type = ReqType.ENVIRONMENT_COMPONENT;

override get reqId(): EnvironmentComponentReqId | undefined { return super.reqId as EnvironmentComponentReqId | undefined }
override set reqId(value: EnvironmentComponentReqId | undefined) { super.reqId = value }
override get reqId() { return super.reqId as `${typeof EnvironmentComponent.reqIdPrefix}${number}` | undefined }
override set reqId(value) { super.reqId = value }
}
27 changes: 19 additions & 8 deletions domain/requirements/Epic.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import { Entity } from "@mikro-orm/core";
import { Entity, ManyToOne } from "@mikro-orm/core";
import { Scenario } from "./Scenario.js";
import { ReqType } from "./ReqType.js";

export const epicReqIdPrefix = 'G.5.' as const;
export type EpicReqId = `${typeof epicReqIdPrefix}${number}`;
import type { Properties } from "../types/index.js";
import { FunctionalBehavior } from "./FunctionalBehavior.js";

/**
* An Epic is a collection of Use Cases and User Stories all directed towards a common goal.
* Ex: "decrease the percentage of of fraudulent sellers by 20%"
*/
@Entity({ discriminatorValue: ReqType.EPIC })
export class Epic extends Scenario {
constructor(props: Omit<Epic, 'id' | 'req_type'>) {
static override reqIdPrefix = 'G.5.' as const;
static override req_type = ReqType.EPIC;

constructor(props: Properties<Omit<Epic, 'id' | 'req_type'>>) {
super(props);
this.req_type = ReqType.EPIC;
this.functionalBehavior = props.functionalBehavior;
}

override get reqId(): EpicReqId | undefined { return super.reqId as EpicReqId | undefined }
override set reqId(value: EpicReqId | undefined) { super.reqId = value }
override get reqId() { return super.reqId as `${typeof Epic.reqIdPrefix}${number}` | undefined }
override set reqId(value) { super.reqId = value }

private _functionalBehavior?: FunctionalBehavior;

/**
* The action that the user wants to perform.
*/
@ManyToOne({ entity: () => FunctionalBehavior })
get functionalBehavior(): FunctionalBehavior | undefined { return this._functionalBehavior; }
set functionalBehavior(value: FunctionalBehavior | undefined) { this._functionalBehavior = value; }
}
6 changes: 1 addition & 5 deletions domain/requirements/Example.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { Entity } from "@mikro-orm/core";
import { Behavior } from "./Behavior.js";
import { ReqType } from "./ReqType.js";
import { type Properties } from "../types/index.js";

/**
* Illustration of behavior through a usage scenario
*/
@Entity({ abstract: true, discriminatorValue: ReqType.EXAMPLE })
export abstract class Example extends Behavior {
constructor(props: Properties<Omit<Example, 'id' | 'req_type'>>) {
super(props)
this.req_type = ReqType.EXAMPLE
}
static override req_type: ReqType = ReqType.EXAMPLE;
}
14 changes: 4 additions & 10 deletions domain/requirements/FunctionalBehavior.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
import { Entity } from "@mikro-orm/core";
import { Functionality } from "./Functionality.js";
import { type Properties } from "../types/index.js";
import { ReqType } from "./ReqType.js";

export const functionalBehaviorReqIdPrefix = 'S.2.' as const;
export type FunctionalBehaviorReqId = `${typeof functionalBehaviorReqIdPrefix}${number}`;

/**
* FunctionalBehavior specifies **what** behavior the system should exhibit, i.e.,
* the results or effects of the system's operation.
* Generally expressed in the form "system must do <requirement>"
*/
@Entity({ discriminatorValue: ReqType.FUNCTIONAL_BEHAVIOR })
export class FunctionalBehavior extends Functionality {
constructor(props: Properties<Omit<FunctionalBehavior, 'id' | 'req_type'>>) {
super(props);
this.req_type = ReqType.FUNCTIONAL_BEHAVIOR;
}
static override reqIdPrefix = 'S.2.' as const;
static override req_type = ReqType.FUNCTIONAL_BEHAVIOR;

override get reqId(): FunctionalBehaviorReqId | undefined { return super.reqId as FunctionalBehaviorReqId | undefined }
override set reqId(value: FunctionalBehaviorReqId | undefined) { super.reqId = value }
override get reqId() { return super.reqId as `${typeof FunctionalBehavior.reqIdPrefix}${number}` | undefined }
override set reqId(value) { super.reqId = value }
}
6 changes: 1 addition & 5 deletions domain/requirements/Functionality.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { Entity } from "@mikro-orm/core";
import { Behavior } from "./Behavior.js";
import { ReqType } from "./ReqType.js";
import { type Properties } from "../types/index.js";

/**
* Functionality describes what system will do and how it will do it.
*/
@Entity({ abstract: true, discriminatorValue: ReqType.FUNCTIONALITY })
export abstract class Functionality extends Behavior {
constructor(props: Properties<Omit<Functionality, 'id' | 'req_type'>>) {
super(props)
this.req_type = ReqType.FUNCTIONALITY
}
static override req_type: ReqType = ReqType.FUNCTIONALITY;
}
14 changes: 4 additions & 10 deletions domain/requirements/GlossaryTerm.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import { Entity } from "@mikro-orm/core";
import { Component } from "./Component.js";
import { type Properties } from "../types/index.js";
import { ReqType } from "./ReqType.js";

export const glossaryTermReqIdPrefix = 'E.1.' as const;
export type GlossaryTermReqId = `${typeof glossaryTermReqIdPrefix}${number}`;

/**
* A word or phrase that is part of a glossary. Provides a definition for the term
*/
@Entity({ discriminatorValue: ReqType.GLOSSARY_TERM })
export class GlossaryTerm extends Component {
constructor(props: Properties<Omit<GlossaryTerm, 'id' | 'req_type'>>) {
super(props);
this.req_type = ReqType.GLOSSARY_TERM;
}
static override reqIdPrefix = 'E.1.' as const;
static override req_type = ReqType.GLOSSARY_TERM;

override get reqId(): GlossaryTermReqId | undefined { return super.reqId as GlossaryTermReqId | undefined }
override set reqId(value: GlossaryTermReqId | undefined) { super.reqId = value }
override get reqId() { return super.reqId as `${typeof GlossaryTerm.reqIdPrefix}${number}` | undefined }
override set reqId(value) { super.reqId = value }
}
6 changes: 1 addition & 5 deletions domain/requirements/Goal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Entity } from "@mikro-orm/core";
import { Requirement } from "./Requirement.js";
import { ReqType } from "./ReqType.js";
import { type Properties } from "../types/index.js";

/**
* A result desired by an organization.
Expand All @@ -10,8 +9,5 @@ import { type Properties } from "../types/index.js";
*/
@Entity({ abstract: true, discriminatorValue: ReqType.GOAL })
export abstract class Goal extends Requirement {
constructor(props: Properties<Omit<Goal, 'id' | 'req_type'>>) {
super(props)
this.req_type = ReqType.GOAL
}
static override req_type: ReqType = ReqType.GOAL;
}
6 changes: 1 addition & 5 deletions domain/requirements/Hint.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { Entity } from "@mikro-orm/core";
import { Noise } from "./Noise.js";
import { ReqType } from "./ReqType.js";
import { type Properties } from "../types/index.js";

/**
* Design or implementation suggestion
*/
@Entity({ discriminatorValue: ReqType.HINT })
export class Hint extends Noise {
constructor(props: Properties<Omit<Hint, 'id' | 'req_type'>>) {
super(props)
this.req_type = ReqType.HINT
}
static override req_type: ReqType = ReqType.HINT;
}
Loading

0 comments on commit 05aad6b

Please sign in to comment.