feat(knowledge): add database schema for Knowledge Module
Implements KNOW-001 - KnowledgeEntry, Version, Link, Tag, Embedding models - Full indexes and constraints - Seed data for testing
This commit is contained in:
@@ -0,0 +1,158 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "EntryStatus" AS ENUM ('DRAFT', 'PUBLISHED', 'ARCHIVED');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "Visibility" AS ENUM ('PRIVATE', 'WORKSPACE', 'PUBLIC');
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "user_layouts" ADD COLUMN "metadata" JSONB NOT NULL DEFAULT '{}';
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "knowledge_entries" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"workspace_id" UUID NOT NULL,
|
||||||
|
"slug" TEXT NOT NULL,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
"content" TEXT NOT NULL,
|
||||||
|
"content_html" TEXT,
|
||||||
|
"summary" TEXT,
|
||||||
|
"status" "EntryStatus" NOT NULL DEFAULT 'DRAFT',
|
||||||
|
"visibility" "Visibility" NOT NULL DEFAULT 'PRIVATE',
|
||||||
|
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||||
|
"created_by" UUID NOT NULL,
|
||||||
|
"updated_by" UUID NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "knowledge_entries_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "knowledge_entry_versions" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"entry_id" UUID NOT NULL,
|
||||||
|
"version" INTEGER NOT NULL,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
"content" TEXT NOT NULL,
|
||||||
|
"summary" TEXT,
|
||||||
|
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"created_by" UUID NOT NULL,
|
||||||
|
"change_note" TEXT,
|
||||||
|
|
||||||
|
CONSTRAINT "knowledge_entry_versions_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "knowledge_links" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"source_id" UUID NOT NULL,
|
||||||
|
"target_id" UUID NOT NULL,
|
||||||
|
"link_text" TEXT NOT NULL,
|
||||||
|
"context" TEXT,
|
||||||
|
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "knowledge_links_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "knowledge_tags" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"workspace_id" UUID NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"slug" TEXT NOT NULL,
|
||||||
|
"color" TEXT,
|
||||||
|
"description" TEXT,
|
||||||
|
|
||||||
|
CONSTRAINT "knowledge_tags_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "knowledge_entry_tags" (
|
||||||
|
"entry_id" UUID NOT NULL,
|
||||||
|
"tag_id" UUID NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "knowledge_entry_tags_pkey" PRIMARY KEY ("entry_id","tag_id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "knowledge_embeddings" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"entry_id" UUID NOT NULL,
|
||||||
|
"embedding" vector(1536) NOT NULL,
|
||||||
|
"model" TEXT NOT NULL,
|
||||||
|
"created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updated_at" TIMESTAMPTZ NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "knowledge_embeddings_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_entries_workspace_id_status_idx" ON "knowledge_entries"("workspace_id", "status");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_entries_workspace_id_updated_at_idx" ON "knowledge_entries"("workspace_id", "updated_at");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_entries_created_by_idx" ON "knowledge_entries"("created_by");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_entries_updated_by_idx" ON "knowledge_entries"("updated_by");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "knowledge_entries_workspace_id_slug_key" ON "knowledge_entries"("workspace_id", "slug");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_entry_versions_entry_id_version_idx" ON "knowledge_entry_versions"("entry_id", "version");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "knowledge_entry_versions_entry_id_version_key" ON "knowledge_entry_versions"("entry_id", "version");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_links_source_id_idx" ON "knowledge_links"("source_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_links_target_id_idx" ON "knowledge_links"("target_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "knowledge_links_source_id_target_id_key" ON "knowledge_links"("source_id", "target_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_tags_workspace_id_idx" ON "knowledge_tags"("workspace_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "knowledge_tags_workspace_id_slug_key" ON "knowledge_tags"("workspace_id", "slug");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_entry_tags_entry_id_idx" ON "knowledge_entry_tags"("entry_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_entry_tags_tag_id_idx" ON "knowledge_entry_tags"("tag_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "knowledge_embeddings_entry_id_key" ON "knowledge_embeddings"("entry_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "knowledge_embeddings_entry_id_idx" ON "knowledge_embeddings"("entry_id");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "knowledge_entries" ADD CONSTRAINT "knowledge_entries_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "workspaces"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "knowledge_entry_versions" ADD CONSTRAINT "knowledge_entry_versions_entry_id_fkey" FOREIGN KEY ("entry_id") REFERENCES "knowledge_entries"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "knowledge_links" ADD CONSTRAINT "knowledge_links_source_id_fkey" FOREIGN KEY ("source_id") REFERENCES "knowledge_entries"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "knowledge_links" ADD CONSTRAINT "knowledge_links_target_id_fkey" FOREIGN KEY ("target_id") REFERENCES "knowledge_entries"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "knowledge_tags" ADD CONSTRAINT "knowledge_tags_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "workspaces"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "knowledge_entry_tags" ADD CONSTRAINT "knowledge_entry_tags_entry_id_fkey" FOREIGN KEY ("entry_id") REFERENCES "knowledge_entries"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "knowledge_entry_tags" ADD CONSTRAINT "knowledge_entry_tags_tag_id_fkey" FOREIGN KEY ("tag_id") REFERENCES "knowledge_tags"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "knowledge_embeddings" ADD CONSTRAINT "knowledge_embeddings_entry_id_fkey" FOREIGN KEY ("entry_id") REFERENCES "knowledge_entries"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
@@ -96,6 +96,18 @@ enum AgentStatus {
|
|||||||
TERMINATED
|
TERMINATED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum EntryStatus {
|
||||||
|
DRAFT
|
||||||
|
PUBLISHED
|
||||||
|
ARCHIVED
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Visibility {
|
||||||
|
PRIVATE
|
||||||
|
WORKSPACE
|
||||||
|
PUBLIC
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// MODELS
|
// MODELS
|
||||||
// ============================================
|
// ============================================
|
||||||
@@ -151,6 +163,8 @@ model Workspace {
|
|||||||
agents Agent[]
|
agents Agent[]
|
||||||
agentSessions AgentSession[]
|
agentSessions AgentSession[]
|
||||||
userLayouts UserLayout[]
|
userLayouts UserLayout[]
|
||||||
|
knowledgeEntries KnowledgeEntry[]
|
||||||
|
knowledgeTags KnowledgeTag[]
|
||||||
|
|
||||||
@@index([ownerId])
|
@@index([ownerId])
|
||||||
@@map("workspaces")
|
@@map("workspaces")
|
||||||
@@ -605,3 +619,131 @@ model Verification {
|
|||||||
@@index([identifier])
|
@@index([identifier])
|
||||||
@@map("verifications")
|
@@map("verifications")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// KNOWLEDGE MODULE
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
model KnowledgeEntry {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
workspaceId String @map("workspace_id") @db.Uuid
|
||||||
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
// Identity
|
||||||
|
slug String
|
||||||
|
title String
|
||||||
|
|
||||||
|
// Content
|
||||||
|
content String @db.Text
|
||||||
|
contentHtml String? @map("content_html") @db.Text
|
||||||
|
summary String?
|
||||||
|
|
||||||
|
// Status
|
||||||
|
status EntryStatus @default(DRAFT)
|
||||||
|
visibility Visibility @default(PRIVATE)
|
||||||
|
|
||||||
|
// Audit
|
||||||
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
||||||
|
createdBy String @map("created_by") @db.Uuid
|
||||||
|
updatedBy String @map("updated_by") @db.Uuid
|
||||||
|
|
||||||
|
// Relations
|
||||||
|
tags KnowledgeEntryTag[]
|
||||||
|
outgoingLinks KnowledgeLink[] @relation("SourceEntry")
|
||||||
|
incomingLinks KnowledgeLink[] @relation("TargetEntry")
|
||||||
|
versions KnowledgeEntryVersion[]
|
||||||
|
embedding KnowledgeEmbedding?
|
||||||
|
|
||||||
|
@@unique([workspaceId, slug])
|
||||||
|
@@index([workspaceId, status])
|
||||||
|
@@index([workspaceId, updatedAt])
|
||||||
|
@@index([createdBy])
|
||||||
|
@@index([updatedBy])
|
||||||
|
@@map("knowledge_entries")
|
||||||
|
}
|
||||||
|
|
||||||
|
model KnowledgeEntryVersion {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
entryId String @map("entry_id") @db.Uuid
|
||||||
|
entry KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
version Int
|
||||||
|
title String
|
||||||
|
content String @db.Text
|
||||||
|
summary String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
||||||
|
createdBy String @map("created_by") @db.Uuid
|
||||||
|
changeNote String? @map("change_note")
|
||||||
|
|
||||||
|
@@unique([entryId, version])
|
||||||
|
@@index([entryId, version])
|
||||||
|
@@map("knowledge_entry_versions")
|
||||||
|
}
|
||||||
|
|
||||||
|
model KnowledgeLink {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
|
||||||
|
sourceId String @map("source_id") @db.Uuid
|
||||||
|
source KnowledgeEntry @relation("SourceEntry", fields: [sourceId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
targetId String @map("target_id") @db.Uuid
|
||||||
|
target KnowledgeEntry @relation("TargetEntry", fields: [targetId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
// Link metadata
|
||||||
|
linkText String @map("link_text")
|
||||||
|
context String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
||||||
|
|
||||||
|
@@unique([sourceId, targetId])
|
||||||
|
@@index([sourceId])
|
||||||
|
@@index([targetId])
|
||||||
|
@@map("knowledge_links")
|
||||||
|
}
|
||||||
|
|
||||||
|
model KnowledgeTag {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
workspaceId String @map("workspace_id") @db.Uuid
|
||||||
|
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
name String
|
||||||
|
slug String
|
||||||
|
color String?
|
||||||
|
description String?
|
||||||
|
|
||||||
|
entries KnowledgeEntryTag[]
|
||||||
|
|
||||||
|
@@unique([workspaceId, slug])
|
||||||
|
@@index([workspaceId])
|
||||||
|
@@map("knowledge_tags")
|
||||||
|
}
|
||||||
|
|
||||||
|
model KnowledgeEntryTag {
|
||||||
|
entryId String @map("entry_id") @db.Uuid
|
||||||
|
entry KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
tagId String @map("tag_id") @db.Uuid
|
||||||
|
tag KnowledgeTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@id([entryId, tagId])
|
||||||
|
@@index([entryId])
|
||||||
|
@@index([tagId])
|
||||||
|
@@map("knowledge_entry_tags")
|
||||||
|
}
|
||||||
|
|
||||||
|
model KnowledgeEmbedding {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
entryId String @unique @map("entry_id") @db.Uuid
|
||||||
|
entry KnowledgeEntry @relation(fields: [entryId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
embedding Unsupported("vector(1536)")
|
||||||
|
model String
|
||||||
|
|
||||||
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz
|
||||||
|
|
||||||
|
@@index([entryId])
|
||||||
|
@@map("knowledge_embeddings")
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import {
|
|||||||
TaskPriority,
|
TaskPriority,
|
||||||
ProjectStatus,
|
ProjectStatus,
|
||||||
WorkspaceMemberRole,
|
WorkspaceMemberRole,
|
||||||
|
EntryStatus,
|
||||||
|
Visibility,
|
||||||
} from "@prisma/client";
|
} from "@prisma/client";
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
@@ -145,6 +147,309 @@ async function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
console.log("Created sample event");
|
console.log("Created sample event");
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// KNOWLEDGE MODULE SEED DATA
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
// Delete existing knowledge data
|
||||||
|
await tx.knowledgeEmbedding.deleteMany({ where: { entry: { workspaceId: workspace.id } } });
|
||||||
|
await tx.knowledgeEntryTag.deleteMany({ where: { entry: { workspaceId: workspace.id } } });
|
||||||
|
await tx.knowledgeLink.deleteMany({ where: { source: { workspaceId: workspace.id } } });
|
||||||
|
await tx.knowledgeEntryVersion.deleteMany({ where: { entry: { workspaceId: workspace.id } } });
|
||||||
|
await tx.knowledgeEntry.deleteMany({ where: { workspaceId: workspace.id } });
|
||||||
|
await tx.knowledgeTag.deleteMany({ where: { workspaceId: workspace.id } });
|
||||||
|
|
||||||
|
// Create knowledge tags
|
||||||
|
const tags = await Promise.all([
|
||||||
|
tx.knowledgeTag.create({
|
||||||
|
data: {
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
name: "Architecture",
|
||||||
|
slug: "architecture",
|
||||||
|
color: "#3B82F6",
|
||||||
|
description: "System architecture and design decisions",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
tx.knowledgeTag.create({
|
||||||
|
data: {
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
name: "Development",
|
||||||
|
slug: "development",
|
||||||
|
color: "#10B981",
|
||||||
|
description: "Development practices and guidelines",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
tx.knowledgeTag.create({
|
||||||
|
data: {
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
name: "Getting Started",
|
||||||
|
slug: "getting-started",
|
||||||
|
color: "#F59E0B",
|
||||||
|
description: "Onboarding and setup guides",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log(`Created ${tags.length} knowledge tags`);
|
||||||
|
|
||||||
|
// Create knowledge entries
|
||||||
|
const entries = [
|
||||||
|
{
|
||||||
|
slug: "welcome",
|
||||||
|
title: "Welcome to Mosaic Stack Knowledge Base",
|
||||||
|
content: `# Welcome to Mosaic Stack
|
||||||
|
|
||||||
|
This is the knowledge base for the Mosaic Stack project. Here you'll find:
|
||||||
|
|
||||||
|
- **[[architecture-overview]]** - High-level system architecture
|
||||||
|
- **[[development-setup]]** - Getting started with development
|
||||||
|
- **[[database-schema]]** - Database design and conventions
|
||||||
|
|
||||||
|
## About This Knowledge Base
|
||||||
|
|
||||||
|
The Knowledge Module provides:
|
||||||
|
- Wiki-style linking between entries
|
||||||
|
- Full-text and semantic search
|
||||||
|
- Version history and change tracking
|
||||||
|
- Tag-based organization
|
||||||
|
|
||||||
|
Start exploring by following the links above!`,
|
||||||
|
summary: "Introduction to the Mosaic Stack knowledge base and navigation guide",
|
||||||
|
status: EntryStatus.PUBLISHED,
|
||||||
|
visibility: Visibility.WORKSPACE,
|
||||||
|
tags: ["getting-started"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "architecture-overview",
|
||||||
|
title: "Architecture Overview",
|
||||||
|
content: `# Architecture Overview
|
||||||
|
|
||||||
|
The Mosaic Stack is built on a modern, scalable architecture:
|
||||||
|
|
||||||
|
## Stack Components
|
||||||
|
|
||||||
|
- **Frontend**: Next.js 15+ with React 19
|
||||||
|
- **Backend**: NestJS with Prisma ORM
|
||||||
|
- **Database**: PostgreSQL 17 with pgvector
|
||||||
|
- **Cache**: Valkey (Redis fork)
|
||||||
|
|
||||||
|
## Key Modules
|
||||||
|
|
||||||
|
1. **Task Management** - See [[development-setup]] for local setup
|
||||||
|
2. **Event Calendar** - Integrated scheduling
|
||||||
|
3. **Knowledge Base** - This module! See [[database-schema]]
|
||||||
|
4. **Agent Orchestration** - AI agent coordination
|
||||||
|
|
||||||
|
The database schema is documented in [[database-schema]].`,
|
||||||
|
summary: "High-level overview of Mosaic Stack architecture and components",
|
||||||
|
status: EntryStatus.PUBLISHED,
|
||||||
|
visibility: Visibility.WORKSPACE,
|
||||||
|
tags: ["architecture"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "development-setup",
|
||||||
|
title: "Development Setup Guide",
|
||||||
|
content: `# Development Setup Guide
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Node.js 22+
|
||||||
|
- PostgreSQL 17
|
||||||
|
- pnpm 9+
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
# Clone the repository
|
||||||
|
git clone https://git.mosaicstack.dev/mosaic/stack.git
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# Set up database
|
||||||
|
cd apps/api
|
||||||
|
pnpm prisma migrate dev
|
||||||
|
pnpm prisma:seed
|
||||||
|
|
||||||
|
# Start development servers
|
||||||
|
pnpm dev
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
Before diving in, review the [[architecture-overview]] to understand the system design.
|
||||||
|
|
||||||
|
## Database
|
||||||
|
|
||||||
|
The database schema is documented in [[database-schema]]. All models use Prisma ORM.
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. Read the [[architecture-overview]]
|
||||||
|
2. Explore the codebase
|
||||||
|
3. Check out the [[database-schema]] documentation`,
|
||||||
|
summary: "Step-by-step guide to setting up the Mosaic Stack development environment",
|
||||||
|
status: EntryStatus.PUBLISHED,
|
||||||
|
visibility: Visibility.WORKSPACE,
|
||||||
|
tags: ["development", "getting-started"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "database-schema",
|
||||||
|
title: "Database Schema Documentation",
|
||||||
|
content: `# Database Schema Documentation
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Mosaic Stack uses PostgreSQL 17 with Prisma ORM. See [[architecture-overview]] for context.
|
||||||
|
|
||||||
|
## Key Conventions
|
||||||
|
|
||||||
|
- All IDs are UUIDs
|
||||||
|
- Timestamps use \`@db.Timestamptz\` (timezone-aware)
|
||||||
|
- Soft deletes via status fields (e.g., ARCHIVED)
|
||||||
|
- Relations enforce cascade deletes for data integrity
|
||||||
|
|
||||||
|
## Core Models
|
||||||
|
|
||||||
|
### Task Management
|
||||||
|
- \`Task\` - Individual work items
|
||||||
|
- \`Project\` - Task containers
|
||||||
|
- \`Domain\` - High-level categorization
|
||||||
|
|
||||||
|
### Knowledge Module
|
||||||
|
- \`KnowledgeEntry\` - Wiki pages
|
||||||
|
- \`KnowledgeLink\` - Page connections
|
||||||
|
- \`KnowledgeTag\` - Categorization
|
||||||
|
- \`KnowledgeEmbedding\` - Semantic search (pgvector)
|
||||||
|
|
||||||
|
### Agent System
|
||||||
|
- \`Agent\` - AI agent instances
|
||||||
|
- \`AgentSession\` - Conversation sessions
|
||||||
|
|
||||||
|
## Migrations
|
||||||
|
|
||||||
|
Migrations are managed via Prisma:
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
# Create migration
|
||||||
|
pnpm prisma migrate dev --name my_migration
|
||||||
|
|
||||||
|
# Apply in production
|
||||||
|
pnpm prisma migrate deploy
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
For setup instructions, see [[development-setup]].`,
|
||||||
|
summary: "Comprehensive documentation of the Mosaic Stack database schema and Prisma conventions",
|
||||||
|
status: EntryStatus.PUBLISHED,
|
||||||
|
visibility: Visibility.WORKSPACE,
|
||||||
|
tags: ["architecture", "development"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
slug: "future-ideas",
|
||||||
|
title: "Future Ideas and Roadmap",
|
||||||
|
content: `# Future Ideas and Roadmap
|
||||||
|
|
||||||
|
## Planned Features
|
||||||
|
|
||||||
|
- Real-time collaboration (CRDT)
|
||||||
|
- Advanced graph visualizations
|
||||||
|
- AI-powered summarization
|
||||||
|
- Mobile app
|
||||||
|
|
||||||
|
## Research Areas
|
||||||
|
|
||||||
|
- Vector search optimization
|
||||||
|
- Knowledge graph algorithms
|
||||||
|
- Agent memory systems
|
||||||
|
|
||||||
|
This is a draft document. See [[architecture-overview]] for current state.`,
|
||||||
|
summary: "Brainstorming document for future features and research directions",
|
||||||
|
status: EntryStatus.DRAFT,
|
||||||
|
visibility: Visibility.PRIVATE,
|
||||||
|
tags: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create entries and track them for linking
|
||||||
|
const createdEntries = new Map<string, any>();
|
||||||
|
|
||||||
|
for (const entryData of entries) {
|
||||||
|
const entry = await tx.knowledgeEntry.create({
|
||||||
|
data: {
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
slug: entryData.slug,
|
||||||
|
title: entryData.title,
|
||||||
|
content: entryData.content,
|
||||||
|
summary: entryData.summary,
|
||||||
|
status: entryData.status,
|
||||||
|
visibility: entryData.visibility,
|
||||||
|
createdBy: user.id,
|
||||||
|
updatedBy: user.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
createdEntries.set(entryData.slug, entry);
|
||||||
|
|
||||||
|
// Create initial version
|
||||||
|
await tx.knowledgeEntryVersion.create({
|
||||||
|
data: {
|
||||||
|
entryId: entry.id,
|
||||||
|
version: 1,
|
||||||
|
title: entry.title,
|
||||||
|
content: entry.content,
|
||||||
|
summary: entry.summary,
|
||||||
|
createdBy: user.id,
|
||||||
|
changeNote: "Initial version",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add tags
|
||||||
|
for (const tagSlug of entryData.tags) {
|
||||||
|
const tag = tags.find(t => t.slug === tagSlug);
|
||||||
|
if (tag) {
|
||||||
|
await tx.knowledgeEntryTag.create({
|
||||||
|
data: {
|
||||||
|
entryId: entry.id,
|
||||||
|
tagId: tag.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Created ${entries.length} knowledge entries`);
|
||||||
|
|
||||||
|
// Create wiki-links between entries
|
||||||
|
const links = [
|
||||||
|
{ source: "welcome", target: "architecture-overview", text: "architecture-overview" },
|
||||||
|
{ source: "welcome", target: "development-setup", text: "development-setup" },
|
||||||
|
{ source: "welcome", target: "database-schema", text: "database-schema" },
|
||||||
|
{ source: "architecture-overview", target: "development-setup", text: "development-setup" },
|
||||||
|
{ source: "architecture-overview", target: "database-schema", text: "database-schema" },
|
||||||
|
{ source: "development-setup", target: "architecture-overview", text: "architecture-overview" },
|
||||||
|
{ source: "development-setup", target: "database-schema", text: "database-schema" },
|
||||||
|
{ source: "database-schema", target: "architecture-overview", text: "architecture-overview" },
|
||||||
|
{ source: "database-schema", target: "development-setup", text: "development-setup" },
|
||||||
|
{ source: "future-ideas", target: "architecture-overview", text: "architecture-overview" },
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const link of links) {
|
||||||
|
const sourceEntry = createdEntries.get(link.source);
|
||||||
|
const targetEntry = createdEntries.get(link.target);
|
||||||
|
|
||||||
|
if (sourceEntry && targetEntry) {
|
||||||
|
await tx.knowledgeLink.create({
|
||||||
|
data: {
|
||||||
|
sourceId: sourceEntry.id,
|
||||||
|
targetId: targetEntry.id,
|
||||||
|
linkText: link.text,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Created ${links.length} knowledge links`);
|
||||||
});
|
});
|
||||||
console.log("Seeding completed successfully!");
|
console.log("Seeding completed successfully!");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user