Skip to main content

Artifact First-Class Implementation Quest Chain

Overview

This quest chain provides a step-by-step implementation plan for elevating artifacts to first-class citizens in the Bike4Mind system. Each quest builds upon the previous ones, with clear deliverables and testing criteria.

Quest Chain Structure

graph TD
Q1[Quest 1: Foundation - Types & Models]
Q2[Quest 2: Database Schema & Migration]
Q3[Quest 3: Core Service Layer]
Q4[Quest 4: API Endpoints]
Q5[Quest 5: Version Management]
Q6[Quest 6: UI Components - Version Dropdown]
Q7[Quest 7: UI Components - Preview Cards]
Q8[Quest 8: Knowledge Viewer Integration]
Q9[Quest 9: WebSocket Real-time Updates]
Q10[Quest 10: Migration & Backward Compatibility]

Q1 --> Q2
Q2 --> Q3
Q3 --> Q4
Q4 --> Q5
Q5 --> Q6
Q6 --> Q7
Q7 --> Q8
Q8 --> Q9
Q9 --> Q10

style Q1 fill:#e1f5fe
style Q2 fill:#e1f5fe
style Q3 fill:#e1f5fe
style Q4 fill:#fff3e0
style Q5 fill:#fff3e0
style Q6 fill:#f3e5f5
style Q7 fill:#f3e5f5
style Q8 fill:#f3e5f5
style Q9 fill:#e8f5e9
style Q10 fill:#e8f5e9

Quest 1: Foundation - Types & Models 🏗️

Objective: Establish the type system foundation for artifacts

Sub-tasks:

1.1 Create Base Artifact Types

File: b4m-core/packages/core/common/types/entities/ArtifactTypes.ts

// Add to existing file
export interface BaseArtifact {
id: string;
type: ArtifactType;
title: string;
description?: string;
metadata: ArtifactMetadata;

// Versioning
version: number;
versionTag?: string;
parentVersionId?: string;

// Timestamps
createdAt: Date;
updatedAt: Date;
publishedAt?: Date;

// Ownership & Access
userId: string;
projectId?: string;
organizationId?: string;
visibility: 'private' | 'project' | 'organization' | 'public';
permissions: ArtifactPermissions;

// Relationships
sourceQuestId?: string;
sessionId?: string;
parentArtifactId?: string;

// Status
status: ArtifactStatus;
tags: string[];

// Content
contentHash: string;
contentSize: number;
}

export enum ArtifactStatus {
DRAFT = 'draft',
REVIEW = 'review',
PUBLISHED = 'published',
ARCHIVED = 'archived',
DELETED = 'deleted'
}

1.2 Create Specific Artifact Types

File: b4m-core/packages/core/common/types/entities/QuestMasterArtifactTypes.ts

export interface QuestMasterArtifact extends BaseArtifact {
type: ArtifactType.QUESTMASTER;
content: {
goal: string;
quests: Quest[];
totalSteps: number;
estimatedDuration?: number;
complexity: 'low' | 'medium' | 'high';
category?: string;
prerequisites?: string[];
};
}

1.3 Create Zod Schemas

File: b4m-core/packages/core/common/schemas/artifacts.ts

import { z } from 'zod';

export const BaseArtifactSchema = z.object({
id: z.string().uuid(),
type: ArtifactTypeSchema,
title: z.string().min(1).max(255),
description: z.string().optional(),
// ... rest of schema
});

export const QuestMasterArtifactSchema = BaseArtifactSchema.extend({
type: z.literal('questmaster'),
content: QuestMasterContentSchema
});

Testing Criteria:

  • All TypeScript types compile without errors
  • Zod schemas validate sample data correctly
  • Unit tests pass for type guards and validators

Deliverables:

  • Complete type definitions in b4m-core
  • Zod schemas for validation
  • Type guard functions
  • Unit tests for types

Quest 2: Database Schema & Migration 🗄️

Objective: Implement MongoDB collections and migration scripts

Sub-tasks:

2.1 Create Mongoose Models

File: b4m-core/packages/core/models/Artifact.ts

import { Schema, model } from 'mongoose';

const ArtifactSchema = new Schema({
id: { type: String, required: true, unique: true },
type: { type: String, required: true, enum: Object.values(ArtifactType) },
title: { type: String, required: true },
description: String,

// Version info
version: { type: Number, default: 1 },
versionTag: String,
currentVersionId: { type: Schema.Types.ObjectId, ref: 'ArtifactVersion' },

// Timestamps
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now },
publishedAt: Date,

// Ownership
userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },
projectId: { type: Schema.Types.ObjectId, ref: 'Project' },
organizationId: { type: Schema.Types.ObjectId, ref: 'Organization' },

// Access control
visibility: {
type: String,
enum: ['private', 'project', 'organization', 'public'],
default: 'private'
},
permissions: {
canRead: [{ type: Schema.Types.ObjectId, ref: 'User' }],
canWrite: [{ type: Schema.Types.ObjectId, ref: 'User' }],
canDelete: [{ type: Schema.Types.ObjectId, ref: 'User' }],
isPublic: { type: Boolean, default: false },
inheritFromProject: { type: Boolean, default: true }
},

// Content reference
contentId: { type: Schema.Types.ObjectId, ref: 'ArtifactContent' },
contentHash: String,
contentSize: Number,

// Soft delete
deletedAt: Date
});

// Indexes
ArtifactSchema.index({ userId: 1, status: 1 });
ArtifactSchema.index({ type: 1, status: 1, visibility: 1 });
ArtifactSchema.index({ tags: 1 });
ArtifactSchema.index({ createdAt: -1 });

export const Artifact = model('Artifact', ArtifactSchema);

2.2 Create Migration Script

File: packages/client/server/migrations/001-create-artifact-collections.ts

export async function up(db: Db) {
// Create artifacts collection
await db.createCollection('artifacts');

// Create artifact_contents collection
await db.createCollection('artifact_contents');

// Create artifact_versions collection
await db.createCollection('artifact_versions');

// Create indexes
await db.collection('artifacts').createIndex({ userId: 1, status: 1 });
// ... more indexes
}

export async function down(db: Db) {
await db.dropCollection('artifacts');
await db.dropCollection('artifact_contents');
await db.dropCollection('artifact_versions');
}

Testing Criteria:

  • Migration runs successfully on test database
  • All indexes are created correctly
  • Rollback works properly
  • Performance queries execute within acceptable time

Deliverables:

  • Mongoose models for all collections
  • Migration scripts with up/down functions
  • Index performance tests
  • Sample data seeders

Quest 3: Core Service Layer 🛠️

Objective: Build the artifact service with CRUD operations

Sub-tasks:

3.1 Create Base Artifact Service

File: b4m-core/packages/core/services/ArtifactService.ts

export class ArtifactService {
constructor(
private db: DatabaseConnection,
private storage: StorageService,
private search: SearchService,
private cache: CacheService,
private events: EventService
) {}

async createArtifact(
data: CreateArtifactRequest,
userId: string
): Promise<Artifact> {
// Validate input
const validated = await this.validateArtifactData(data);

// Create artifact document
const artifact = await this.db.artifacts.create({
...validated,
id: generateUUID(),
version: 1,
userId,
createdAt: new Date(),
updatedAt: new Date(),
status: ArtifactStatus.DRAFT,
contentHash: await this.hashContent(validated.content),
contentSize: this.calculateSize(validated.content)
});

// Store content separately
await this.db.artifactContents.create({
artifactId: artifact.id,
content: validated.content
});

// Create initial version
await this.createVersion(artifact, 'Initial version', userId);

// Index for search
await this.search.indexArtifact(artifact);

// Emit event
await this.events.emit('artifact.created', { artifact, userId });

// Cache
await this.cache.set(`artifact:${artifact.id}`, artifact);

return artifact;
}

// ... other CRUD methods
}

3.2 Create Repository Pattern

File: b4m-core/packages/core/repositories/ArtifactRepository.ts

export class ArtifactRepository {
async findById(id: string): Promise<Artifact | null> {
return Artifact.findOne({ id, deletedAt: null });
}

async findByUser(userId: string, options?: FindOptions): Promise<Artifact[]> {
const query = { userId, deletedAt: null };
return this.applyOptions(Artifact.find(query), options);
}

async create(data: CreateArtifactData): Promise<Artifact> {
const artifact = new Artifact(data);
return artifact.save();
}

async update(id: string, updates: UpdateArtifactData): Promise<Artifact | null> {
return Artifact.findOneAndUpdate(
{ id, deletedAt: null },
{ ...updates, updatedAt: new Date() },
{ new: true }
);
}

async softDelete(id: string): Promise<boolean> {
const result = await Artifact.updateOne(
{ id, deletedAt: null },
{ deletedAt: new Date(), status: ArtifactStatus.DELETED }
);
return result.modifiedCount > 0;
}
}

Testing Criteria:

  • All CRUD operations work correctly
  • Validation catches invalid data
  • Events are emitted properly
  • Cache is updated correctly
  • Unit tests cover all methods

Deliverables:

  • Complete ArtifactService implementation
  • Repository pattern implementation
  • Service unit tests
  • Integration tests with database

Quest 4: API Endpoints 🌐

Objective: Create RESTful API endpoints for artifact operations

Sub-tasks:

4.1 Create Artifact Controller

File: packages/client/pages/api/artifacts/index.ts

import { baseApi } from '@client/server/routers/base';
import { asyncHandler } from '@client/server/middleware/asyncHandler';

export default baseApi()
.get(asyncHandler(async (req, res) => {
const { type, status, search, page = 1, limit = 20 } = req.query;

const artifacts = await artifactService.listArtifacts({
filters: {
type: type ? [type as ArtifactType] : undefined,
status: status ? [status as ArtifactStatus] : undefined,
search: search as string,
userId: req.user.id
},
pagination: {
page: Number(page),
limit: Number(limit)
}
});

res.json({ success: true, data: artifacts });
}))
.post(asyncHandler(async (req, res) => {
const artifact = await artifactService.createArtifact(
req.body,
req.user.id
);

res.status(201).json({ success: true, data: artifact });
}));

4.2 Create Version Endpoints

File: packages/client/pages/api/artifacts/[id]/versions.ts

export default baseApi()
.get(asyncHandler(async (req, res) => {
const { id } = req.query;
const versions = await artifactService.getArtifactVersions(id as string);
res.json({ success: true, data: versions });
}))
.post(asyncHandler(async (req, res) => {
const { id } = req.query;
const newVersion = await artifactService.createNewVersion(
id as string,
req.body,
req.user.id
);
res.status(201).json({ success: true, data: newVersion });
}));

Testing Criteria:

  • All endpoints return correct status codes
  • Authentication/authorization works properly
  • Validation errors are handled gracefully
  • Pagination works correctly
  • API tests cover all endpoints

Deliverables:

  • Complete REST API implementation
  • OpenAPI/Swagger documentation
  • Postman collection
  • API integration tests

Quest 5: Version Management 📚

Objective: Implement comprehensive version control system

Sub-tasks:

5.1 Create Version Service

File: b4m-core/packages/core/services/ArtifactVersionService.ts

export class ArtifactVersionService {
async createVersion(
artifact: Artifact,
changes: VersionChange[],
message: string,
userId: string
): Promise<ArtifactVersion> {
const version = await ArtifactVersion.create({
artifactId: artifact.id,
version: artifact.version + 1,
versionTag: message,
createdAt: new Date(),
createdBy: userId,
parentVersionId: artifact.currentVersionId,
contentSnapshot: artifact.content,
changes
});

// Update artifact's current version
artifact.version = version.version;
artifact.currentVersionId = version.id;
await artifact.save();

return version;
}

async compareVersions(
artifactId: string,
fromVersion: number,
toVersion: number
): Promise<VersionDiff> {
const from = await ArtifactVersion.findOne({ artifactId, version: fromVersion });
const to = await ArtifactVersion.findOne({ artifactId, version: toVersion });

const changes = this.calculateDiff(from.contentSnapshot, to.contentSnapshot);

return {
fromVersion,
toVersion,
changes,
summary: this.generateDiffSummary(changes)
};
}

private calculateDiff(from: any, to: any): VersionChange[] {
// Implement diff algorithm
return [];
}
}

5.2 Create Version UI Components

File: packages/client/app/components/Artifacts/VersionHistory.tsx

export const VersionHistory: React.FC<{ artifactId: string }> = ({ artifactId }) => {
const { data: versions } = useArtifactVersions(artifactId);

return (
<Timeline>
{versions?.map(version => (
<TimelineItem key={version.id}>
<TimelineSeparator>
<TimelineDot color={version.isCurrent ? 'primary' : 'grey'} />
<TimelineConnector />
</TimelineSeparator>
<TimelineContent>
<Typography level="title-sm">
Version {version.version}
{version.versionTag && ` - ${version.versionTag}`}
</Typography>
<Typography level="body-xs">
{formatRelativeTime(version.createdAt)} by {version.createdBy}
</Typography>
<Button size="sm" onClick={() => restoreVersion(version.version)}>
Restore
</Button>
</TimelineContent>
</TimelineItem>
))}
</Timeline>
);
};

Testing Criteria:

  • Version creation works correctly
  • Version comparison shows accurate diffs
  • Version restoration works properly
  • UI displays version history correctly

Deliverables:

  • Version service implementation
  • Diff algorithm implementation
  • Version history UI component
  • Version comparison UI

Quest 6: UI Components - Version Dropdown 🎨

Objective: Build the version dropdown component

Sub-tasks:

6.1 Create Version Dropdown Component

File: packages/client/app/components/Artifacts/VersionDropdown.tsx

interface VersionDropdownProps {
artifact: Artifact;
currentVersion: number;
onVersionChange: (version: number) => void;
showDiff?: boolean;
}

export const VersionDropdown: React.FC<VersionDropdownProps> = ({
artifact,
currentVersion,
onVersionChange,
showDiff = false
}) => {
const { data: versions } = useArtifactVersions(artifact.id);
const [compareMode, setCompareMode] = useState(false);
const [compareVersion, setCompareVersion] = useState<number | null>(null);

return (
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
<Select
value={currentVersion}
onChange={(_, value) => onVersionChange(value as number)}
startDecorator={<HistoryIcon />}
endDecorator={
<Chip size="sm" variant="soft">
v{currentVersion}
</Chip>
}
>
{versions?.map(version => (
<Option key={version.version} value={version.version}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}>
<Typography level="body-sm">
Version {version.version}
{version.versionTag && ` - ${version.versionTag}`}
</Typography>
<Typography level="body-xs" sx={{ color: 'text.secondary' }}>
{formatRelativeTime(version.createdAt)}
</Typography>
</Box>
</Option>
))}
</Select>

{showDiff && (
<IconButton
size="sm"
variant={compareMode ? 'solid' : 'plain'}
onClick={() => setCompareMode(!compareMode)}
>
<CompareIcon />
</IconButton>
)}
</Box>
);
};

6.2 Create Version Diff Viewer

File: packages/client/app/components/Artifacts/VersionDiffViewer.tsx

export const VersionDiffViewer: React.FC<{
artifactId: string;
fromVersion: number;
toVersion: number;
}> = ({ artifactId, fromVersion, toVersion }) => {
const { data: diff } = useVersionDiff(artifactId, fromVersion, toVersion);

return (
<Box>
<Typography level="title-md">
Changes from v{fromVersion} to v{toVersion}
</Typography>
<Stack spacing={2}>
{diff?.changes.map((change, index) => (
<DiffItem key={index} change={change} />
))}
</Stack>
</Box>
);
};

Testing Criteria:

  • Dropdown displays all versions correctly
  • Version selection updates artifact view
  • Compare mode works properly
  • Diff viewer shows accurate changes

Deliverables:

  • Version dropdown component
  • Version diff viewer
  • Storybook stories
  • Component tests

Quest 7: UI Components - Preview Cards 🃏

Objective: Create artifact preview cards with version support

Sub-tasks:

7.1 Create Artifact Preview Card

File: packages/client/app/components/Artifacts/ArtifactPreviewCard.tsx

export const ArtifactPreviewCard: React.FC<ArtifactPreviewCardProps> = ({
artifact,
onClick,
showVersions = true,
showActions = true
}) => {
const [currentVersion, setCurrentVersion] = useState(artifact.version);
const { data: versionData } = useArtifactVersion(artifact.id, currentVersion);

return (
<Card
variant="outlined"
sx={{
cursor: onClick ? 'pointer' : 'default',
transition: 'all 0.2s',
'&:hover': onClick ? {
transform: 'translateY(-2px)',
boxShadow: 'md'
} : {}
}}
onClick={onClick}
>
<CardContent>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 2 }}>
<Stack direction="row" spacing={1} alignItems="center">
{getArtifactIcon(artifact.type)}
<Typography level="h4">{artifact.title}</Typography>
</Stack>

{showVersions && (
<VersionDropdown
artifact={artifact}
currentVersion={currentVersion}
onVersionChange={setCurrentVersion}
/>
)}
</Box>

<Box sx={{ mb: 2 }}>
{getPreviewContent(artifact, versionData)}
</Box>

{showActions && (
<Stack direction="row" spacing={1} justifyContent="flex-end">
<IconButton size="sm" variant="plain">
<ShareIcon />
</IconButton>
<IconButton size="sm" variant="plain">
<EditIcon />
</IconButton>
</Stack>
)}
</CardContent>
</Card>
);
};

7.2 Create Artifact Grid View

File: packages/client/app/components/Artifacts/ArtifactGrid.tsx

export const ArtifactGrid: React.FC<{
artifacts: Artifact[];
onArtifactClick: (artifact: Artifact) => void;
}> = ({ artifacts, onArtifactClick }) => {
return (
<Grid container spacing={2}>
{artifacts.map(artifact => (
<Grid key={artifact.id} xs={12} sm={6} md={4} lg={3}>
<ArtifactPreviewCard
artifact={artifact}
onClick={() => onArtifactClick(artifact)}
/>
</Grid>
))}
</Grid>
);
};

Testing Criteria:

  • Preview cards render all artifact types correctly
  • Version dropdown works within cards
  • Actions trigger appropriate callbacks
  • Grid layout is responsive

Deliverables:

  • Artifact preview card component
  • Artifact grid component
  • Type-specific preview renderers
  • Visual regression tests

Quest 8: Knowledge Viewer Integration 🔗

Objective: Integrate artifact system with existing Knowledge Viewer

Sub-tasks:

8.1 Update Knowledge Viewer

File: packages/client/app/components/Knowledge/KnowledgeViewer.tsx

const KnowledgeViewer: React.FC = () => {
const { currentSession } = useSessions();
const [selectedArtifact, setSelectedArtifact] = useState<Artifact | null>(null);
const [selectedVersion, setSelectedVersion] = useState<number | null>(null);

// Fetch artifacts for current session
const { data: artifacts } = useArtifacts({
filters: {
sessionId: currentSession?.id,
status: [ArtifactStatus.PUBLISHED, ArtifactStatus.DRAFT]
},
sort: { field: 'updatedAt', order: 'desc' }
});

return (
<Stack sx={{ height: '100%' }}>
{/* Artifact selector */}
<Box sx={{ p: 2, borderBottom: 1, borderColor: 'divider' }}>
<Select
placeholder="Select an artifact..."
value={selectedArtifact?.id}
onChange={(_, value) => {
const artifact = artifacts?.find(a => a.id === value);
if (artifact) setSelectedArtifact(artifact);
}}
>
{artifacts?.map(artifact => (
<Option key={artifact.id} value={artifact.id}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
{getArtifactIcon(artifact.type)}
<Typography>{artifact.title}</Typography>
<Chip size="sm" variant="soft">
v{artifact.version}
</Chip>
</Box>
</Option>
))}
</Select>
</Box>

{/* Version selector */}
{selectedArtifact && (
<Box sx={{ p: 2, borderBottom: 1, borderColor: 'divider' }}>
<VersionDropdown
artifact={selectedArtifact}
currentVersion={selectedVersion || selectedArtifact.version}
onVersionChange={setSelectedVersion}
showDiff
/>
</Box>
)}

{/* Content viewer */}
<Box sx={{ flex: 1, overflow: 'auto', p: 2 }}>
{selectedArtifact && selectedVersion && (
<ArtifactViewer
artifact={selectedArtifact}
version={selectedVersion}
onSave={handleSaveArtifact}
editable={selectedVersion === selectedArtifact.version}
/>
)}
</Box>
</Stack>
);
};

8.2 Create Artifact Creation Flow

File: packages/client/app/components/Artifacts/CreateArtifactDialog.tsx

export const CreateArtifactDialog: React.FC<{
open: boolean;
onClose: () => void;
onCreated: (artifact: Artifact) => void;
initialContent?: any;
initialType?: ArtifactType;
}> = ({ open, onClose, onCreated, initialContent, initialType }) => {
const [type, setType] = useState<ArtifactType>(initialType || ArtifactType.CODE);
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');

const handleCreate = async () => {
const artifact = await createArtifact({
type,
title,
description,
content: initialContent || getDefaultContent(type)
});

onCreated(artifact);
onClose();
};

return (
<Modal open={open} onClose={onClose}>
<ModalDialog>
<DialogTitle>Create New Artifact</DialogTitle>
<DialogContent>
<Stack spacing={2}>
<FormControl>
<FormLabel>Type</FormLabel>
<Select value={type} onChange={(_, value) => setType(value as ArtifactType)}>
{Object.values(ArtifactType).map(t => (
<Option key={t} value={t}>{t}</Option>
))}
</Select>
</FormControl>

<FormControl>
<FormLabel>Title</FormLabel>
<Input value={title} onChange={e => setTitle(e.target.value)} />
</FormControl>

<FormControl>
<FormLabel>Description</FormLabel>
<Textarea value={description} onChange={e => setDescription(e.target.value)} />
</FormControl>
</Stack>
</DialogContent>
<DialogActions>
<Button variant="plain" onClick={onClose}>Cancel</Button>
<Button onClick={handleCreate} disabled={!title}>Create</Button>
</DialogActions>
</ModalDialog>
</Modal>
);
};

Testing Criteria:

  • Knowledge Viewer displays artifacts correctly
  • Version switching works seamlessly
  • Save functionality creates new versions
  • Creation flow works for all artifact types

Deliverables:

  • Updated Knowledge Viewer
  • Artifact creation dialog
  • Integration with existing viewers
  • E2E tests

Quest 9: WebSocket Real-time Updates 🔄

Objective: Implement real-time collaboration features

Sub-tasks:

9.1 Create WebSocket Events

File: b4m-core/packages/core/common/schemas/artifactActions.ts

export const ArtifactCreatedAction = z.object({
action: z.literal('artifact.created'),
artifact: ArtifactSchema,
userId: z.string()
});

export const ArtifactUpdatedAction = z.object({
action: z.literal('artifact.updated'),
artifactId: z.string(),
changes: z.array(VersionChangeSchema),
userId: z.string()
});

export const QuestUpdatedAction = z.object({
action: z.literal('artifact.quest.updated'),
artifactId: z.string(),
questId: z.string(),
updates: z.record(z.unknown()),
userId: z.string()
});

9.2 Create Real-time Hook

File: packages/client/app/hooks/useArtifactSubscription.ts

export const useArtifactSubscription = (artifactId: string) => {
const queryClient = useQueryClient();
const { subscribeToAction } = useWebsocket();

useEffect(() => {
const unsubscribes = [
// Subscribe to artifact updates
subscribeToAction('artifact.updated', async (msg) => {
if (msg.artifactId === artifactId) {
queryClient.invalidateQueries(['artifact', artifactId]);
}
}),

// Subscribe to version updates
subscribeToAction('artifact.version.created', async (msg) => {
if (msg.artifactId === artifactId) {
queryClient.invalidateQueries(['artifact-versions', artifactId]);
}
}),

// Subscribe to quest updates for QuestMaster artifacts
subscribeToAction('artifact.quest.updated', async (msg) => {
if (msg.artifactId === artifactId) {
queryClient.setQueryData(
['artifact', artifactId],
(old: Artifact) => updateQuestInArtifact(old, msg.questId, msg.updates)
);
}
})
];

return () => {
unsubscribes.forEach(unsubscribe => unsubscribe());
};
}, [artifactId, subscribeToAction, queryClient]);
};

Testing Criteria:

  • Real-time updates work across multiple clients
  • Quest status updates propagate correctly
  • Version changes are reflected immediately
  • No race conditions or conflicts

Deliverables:

  • WebSocket event definitions
  • Real-time subscription hooks
  • Collaborative editing support
  • Integration tests

Quest 10: Migration & Backward Compatibility 🔄

Objective: Migrate existing artifacts and ensure backward compatibility

Sub-tasks:

10.1 Create Migration Script

File: packages/client/server/migrations/002-migrate-existing-artifacts.ts

export async function up(db: Db) {
// Find all sessions with artifacts
const sessions = await db.collection('sessions').find({
'chatHistory.replies': { $regex: '<artifact' }
}).toArray();

for (const session of sessions) {
for (const quest of session.chatHistory) {
if (!quest.replies) continue;

for (const reply of quest.replies) {
const artifacts = parseArtifacts(reply);

for (const artifact of artifacts) {
// Create artifact document
await db.collection('artifacts').insertOne({
id: artifact.identifier || generateUUID(),
type: mapToArtifactType(artifact.type),
title: artifact.title,
content: artifact.content,
sourceQuestId: quest.id,
sessionId: session.id,
userId: session.userId,
createdAt: quest.timestamp,
updatedAt: quest.timestamp,
version: 1,
status: 'published'
});

// Replace artifact content with reference
reply = reply.replace(
artifact.fullMatch,
`<artifact-ref id="${artifact.id}" />`
);
}

// Update quest reply
await db.collection('sessions').updateOne(
{ _id: session._id, 'chatHistory.id': quest.id },
{ $set: { 'chatHistory.$.reply': reply } }
);
}
}
}
}

10.2 Create Compatibility Layer

File: packages/client/app/utils/artifactCompatibility.ts

export const getArtifactFromLegacy = async (
questId: string,
artifactId: string
): Promise<Artifact | null> => {
// First try to get from new artifact system
const artifact = await artifactService.getArtifact(artifactId);
if (artifact) return artifact;

// Fallback to parsing from quest reply
const quest = await questService.getQuest(questId);
if (!quest?.reply) return null;

const { artifacts } = parseArtifacts(quest.reply);
const legacyArtifact = artifacts.find(a => a.identifier === artifactId);

if (!legacyArtifact) return null;

// Convert to new format
return {
id: artifactId,
type: mapToArtifactType(legacyArtifact.type),
title: legacyArtifact.title,
content: legacyArtifact.content,
version: 1,
status: ArtifactStatus.PUBLISHED,
createdAt: quest.timestamp,
updatedAt: quest.timestamp,
userId: quest.userId,
sessionId: quest.sessionId
};
};

Testing Criteria:

  • Migration successfully converts all existing artifacts
  • No data loss during migration
  • Backward compatibility works for old sessions
  • Performance is acceptable for large datasets

Deliverables:

  • Migration scripts with progress tracking
  • Compatibility layer for legacy artifacts
  • Rollback procedures
  • Migration documentation

Implementation Timeline

Phase 1: Foundation (Quests 1-3) - 2 weeks

  • Week 1: Types, schemas, and database models
  • Week 2: Core service implementation

Phase 2: API Layer (Quests 4-5) - 2 weeks

  • Week 3: REST API endpoints
  • Week 4: Version management system

Phase 3: UI Components (Quests 6-8) - 3 weeks

  • Week 5: Version dropdown and diff viewer
  • Week 6: Preview cards and grid
  • Week 7: Knowledge Viewer integration

Phase 4: Advanced Features (Quests 9-10) - 2 weeks

  • Week 8: WebSocket real-time updates
  • Week 9: Migration and compatibility

Total Timeline: 9 weeks

Success Metrics

  1. Performance

    • Artifact loading < 200ms
    • Version switching < 100ms
    • Search results < 500ms
  2. Reliability

    • 99.9% uptime for artifact service
    • Zero data loss during migrations
    • Successful rollback capability
  3. User Experience

    • Intuitive version management
    • Seamless Knowledge Viewer integration
    • Real-time collaboration features
  4. Developer Experience

    • Clear API documentation
    • Comprehensive test coverage (>80%)
    • Easy extension for new artifact types

Risk Mitigation

  1. Data Migration Risks

    • Create comprehensive backups
    • Test on staging environment first
    • Implement gradual rollout
  2. Performance Risks

    • Implement caching early
    • Use pagination for large datasets
    • Monitor query performance
  3. Compatibility Risks

    • Maintain legacy support for 6 months
    • Provide clear migration guides
    • Implement feature flags

This quest chain provides a structured, incremental approach to implementing artifacts as first-class citizens, with clear deliverables and testing criteria at each step.