Release: CI/CD Pipeline & Architecture Updates #177

Merged
jason.woltje merged 173 commits from develop into main 2026-02-01 19:18:48 +00:00
4 changed files with 99 additions and 8 deletions
Showing only changes of commit 8a24c2f5fd - Show all commits

View File

@@ -11,6 +11,7 @@ import {
ParseIntPipe,
DefaultValuePipe,
} from "@nestjs/common";
import type { AuthUser } from "@mosaic/shared";
import { KnowledgeService } from "./knowledge.service";
import { CreateEntryDto, UpdateEntryDto, EntryQueryDto, RestoreVersionDto } from "./dto";
import { AuthGuard } from "../auth/guards/auth.guard";
@@ -69,7 +70,7 @@ export class KnowledgeController {
@RequirePermission(Permission.WORKSPACE_MEMBER)
async create(
@Workspace() workspaceId: string,
@CurrentUser() user: any,
@CurrentUser() user: AuthUser,
@Body() createDto: CreateEntryDto
) {
return this.knowledgeService.create(workspaceId, user.id, createDto);
@@ -85,7 +86,7 @@ export class KnowledgeController {
async update(
@Workspace() workspaceId: string,
@Param("slug") slug: string,
@CurrentUser() user: any,
@CurrentUser() user: AuthUser,
@Body() updateDto: UpdateEntryDto
) {
return this.knowledgeService.update(workspaceId, slug, user.id, updateDto);
@@ -101,7 +102,7 @@ export class KnowledgeController {
async remove(
@Workspace() workspaceId: string,
@Param("slug") slug: string,
@CurrentUser() user: any
@CurrentUser() user: AuthUser
) {
await this.knowledgeService.remove(workspaceId, slug, user.id);
return { message: "Entry archived successfully" };
@@ -177,7 +178,7 @@ export class KnowledgeController {
@Workspace() workspaceId: string,
@Param("slug") slug: string,
@Param("version", ParseIntPipe) version: number,
@CurrentUser() user: any,
@CurrentUser() user: AuthUser,
@Body() restoreDto: RestoreVersionDto
) {
return this.knowledgeService.restoreVersion(

View File

@@ -3,7 +3,7 @@ import {
NotFoundException,
ConflictException,
} from "@nestjs/common";
import { EntryStatus } from "@prisma/client";
import { EntryStatus, Prisma } from "@prisma/client";
import slugify from "slugify";
import { PrismaService } from "../prisma/prisma.service";
import type { CreateEntryDto, UpdateEntryDto, EntryQueryDto } from "./dto";
@@ -41,7 +41,7 @@ export class KnowledgeService {
const skip = (page - 1) * limit;
// Build where clause
const where: any = {
const where: Prisma.KnowledgeEntryWhereInput = {
workspaceId,
};
@@ -308,7 +308,7 @@ export class KnowledgeService {
}
// Build update data object conditionally
const updateData: any = {
const updateData: Prisma.KnowledgeEntryUpdateInput = {
updatedBy: userId,
};
@@ -764,7 +764,7 @@ export class KnowledgeService {
* Sync tags for an entry (create missing tags, update associations)
*/
private async syncTags(
tx: any,
tx: Prisma.TransactionClient,
workspaceId: string,
entryId: string,
tagNames: string[]

View File

@@ -7,3 +7,5 @@ export { EntryViewer } from "./EntryViewer";
export { EntryEditor } from "./EntryEditor";
export { EntryMetadata } from "./EntryMetadata";
export { VersionHistory } from "./VersionHistory";
export { StatsDashboard } from "./StatsDashboard";
export { EntryGraphViewer } from "./EntryGraphViewer";

View File

@@ -230,6 +230,94 @@ export async function fetchBacklinks(slug: string): Promise<{
}>(`/api/knowledge/entries/${slug}/backlinks`);
}
/**
* Fetch knowledge base statistics
*/
export async function fetchKnowledgeStats(): Promise<{
overview: {
totalEntries: number;
totalTags: number;
totalLinks: number;
publishedEntries: number;
draftEntries: number;
archivedEntries: number;
};
mostConnected: Array<{
id: string;
slug: string;
title: string;
incomingLinks: number;
outgoingLinks: number;
totalConnections: number;
}>;
recentActivity: Array<{
id: string;
slug: string;
title: string;
updatedAt: string;
status: string;
}>;
tagDistribution: Array<{
id: string;
name: string;
slug: string;
color: string | null;
entryCount: number;
}>;
}> {
return apiGet(`/api/knowledge/stats`);
}
/**
* Fetch entry graph (network of connected entries)
*/
export async function fetchEntryGraph(
slug: string,
depth: number = 1
): Promise<{
centerNode: {
id: string;
slug: string;
title: string;
summary: string | null;
tags: Array<{
id: string;
name: string;
slug: string;
color: string | null;
}>;
depth: number;
};
nodes: Array<{
id: string;
slug: string;
title: string;
summary: string | null;
tags: Array<{
id: string;
name: string;
slug: string;
color: string | null;
}>;
depth: number;
}>;
edges: Array<{
id: string;
sourceId: string;
targetId: string;
linkText: string;
}>;
stats: {
totalNodes: number;
totalEdges: number;
maxDepth: number;
};
}> {
const params = new URLSearchParams();
params.append("depth", depth.toString());
return apiGet(`/api/knowledge/entries/${slug}/graph?${params.toString()}`);
}
/**
* Mock entries for development (until backend endpoints are ready)
*/