first commit

This commit is contained in:
2026-10-03 13:40:26 +02:00
parent 732a5b5a16
commit 566f415fa7
555 changed files with 62704 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
import {
ActivityReadModel,
CommentReadModel,
IssueLinkReadModel,
IssueReadModel,
ProjectReadModel,
ReleaseReadModel,
} from '@task-stream/api/tracker/domain';
import { Schema } from 'mongoose';
/* Read model (MongoDB): denormalised documents shaped for the GraphQL queries. */
type Doc<T extends { id: string }> = Omit<T, 'id'> & { _id: string };
export type ProjectDoc = Doc<ProjectReadModel> & { memberIds: string[] };
/** Links are split: outward ones come from the issue itself, inward ones from other issues' events. */
export type IssueDoc = Doc<Omit<IssueReadModel, 'links'>> & {
outwardLinks: IssueLinkReadModel[];
inwardLinks: IssueLinkReadModel[];
};
export type CommentDoc = Doc<CommentReadModel>;
export type ReleaseDoc = Doc<ReleaseReadModel>;
export type ActivityDoc = Doc<ActivityReadModel>;
export const ReadModels = {
Project: 'ProjectReadModel',
Issue: 'IssueReadModel',
Comment: 'CommentReadModel',
Release: 'ReleaseReadModel',
Activity: 'ActivityReadModel',
} as const;
const userRef = { _id: false, id: String, name: String };
// `type` must be wrapped: a bare `type` key would declare the whole subdocument a String.
const link = {
_id: false,
type: { type: String },
direction: String,
issueId: String,
issueKey: String,
};
const loose = { strict: false, versionKey: false, _id: false } as const;
export const ProjectSchema = new Schema<ProjectDoc>(
{
_id: String,
key: { type: String, unique: true },
memberIds: { type: [String], index: true },
owner: userRef,
members: [{ _id: false, user: userRef, role: String }],
version: Number,
},
{ ...loose, collection: 'projects_view' },
);
export const IssueSchema = new Schema<IssueDoc>(
{
_id: String,
projectId: { type: String, index: true },
key: { type: String, unique: true },
status: String,
reporter: userRef,
assignee: userRef,
release: { _id: false, id: String, name: String },
outwardLinks: [link],
inwardLinks: [link],
labels: [String],
version: Number,
},
{ ...loose, collection: 'issues_view' },
);
IssueSchema.index({ projectId: 1, status: 1, updatedAt: -1 });
IssueSchema.index({ 'assignee.id': 1 });
IssueSchema.index({ 'release.id': 1 });
IssueSchema.index({ title: 'text', description: 'text', key: 'text' });
export const CommentSchema = new Schema<CommentDoc>(
{
_id: String,
issueId: { type: String, index: true },
author: userRef,
version: Number,
},
{ ...loose, collection: 'comments_view' },
);
CommentSchema.index({ issueId: 1, createdAt: 1 });
export const ReleaseSchema = new Schema<ReleaseDoc>(
{ _id: String, projectId: { type: String, index: true }, version: Number },
{ ...loose, collection: 'releases_view' },
);
export const ActivitySchema = new Schema<ActivityDoc>(
{
_id: String,
projectId: String,
issueId: String,
actor: userRef,
},
{ ...loose, collection: 'activity' },
);
ActivitySchema.index({ projectId: 1, occurredAt: -1 });
ActivitySchema.index({ issueId: 1, occurredAt: -1 });
export const READ_MODEL_SCHEMAS = [
{ name: ReadModels.Project, schema: ProjectSchema },
{ name: ReadModels.Issue, schema: IssueSchema },
{ name: ReadModels.Comment, schema: CommentSchema },
{ name: ReadModels.Release, schema: ReleaseSchema },
{ name: ReadModels.Activity, schema: ActivitySchema },
];
export function fromDoc<T extends { _id: string }>(
doc: T,
): Omit<T, '_id'> & { id: string } {
const { _id, ...rest } = doc;
return { id: _id, ...rest };
}
export function issueFromDoc(doc: IssueDoc): IssueReadModel {
const { _id, outwardLinks, inwardLinks, ...rest } = doc;
return {
id: _id,
...rest,
links: [...(outwardLinks ?? []), ...(inwardLinks ?? [])],
};
}