From opensaas-migration
Migrate Keystone document fields (@keystone-6/fields-document) to OpenSaaS Stack tiptap rich text fields. Invoke as a forked subagent, passing the config file path and document field details.
npx claudepluginhub opensaasau/stack --plugin opensaas-migrationThis skill uses the workspace's default tool permissions.
Migrate the Keystone document fields described below to OpenSaaS Stack's Tiptap rich text fields. This involves config changes, package updates, and a data format note for existing content.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
Migrate the Keystone document fields described below to OpenSaaS Stack's Tiptap rich text fields. This involves config changes, package updates, and a data format note for existing content.
$ARGUMENTS
Keystone uses a proprietary document editor from @keystone-6/fields-document:
import { document } from '@keystone-6/fields-document'
content: document({
formatting: true,
links: true,
dividers: true,
layouts: [
[1, 1],
[1, 1, 1],
],
})
OpenSaaS Stack uses Tiptap (ProseMirror-based) from @opensaas/stack-tiptap:
import { richText } from '@opensaas/stack-tiptap/fields'
content: richText()
Both store JSON in the database, but the JSON formats are different (see data migration note below).
- import { document } from '@keystone-6/fields-document'
+ import { richText } from '@opensaas/stack-tiptap/fields'
content: document({
- formatting: true,
- links: true,
- dividers: true,
- layouts: [[1, 1]],
- })
+ content: richText()
All document field options (formatting, links, dividers, layouts) are dropped — Tiptap's toolbar is configured at the UI level, not the field level.
The user needs to install @opensaas/stack-tiptap and its peer dependencies:
pnpm add @opensaas/stack-tiptap
pnpm remove @keystone-6/fields-document
In the admin page (app/admin/[[...admin]]/page.tsx or similar):
// lib/register-fields.ts
'use client'
import { registerFieldComponent } from '@opensaas/stack-ui'
import { RichTextFieldComponent } from '@opensaas/stack-tiptap'
registerFieldComponent('richText', RichTextFieldComponent)
Then import it in the admin page as a side effect:
import '../../../lib/register-fields'
The Keystone document format and Tiptap's ProseMirror JSON format are different. Existing content stored in the database will not automatically render correctly in the Tiptap editor.
If the project has existing document content that must be preserved:
[{ "type": "paragraph", "children": [{ "text": "..." }] }] (Slate-based){ "type": "doc", "content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "..." }] }] }Options:
Write a comment in the code for any document fields that had existing content so the user knows to address it:
// NOTE: This field was migrated from Keystone document format.
// Existing content may not render correctly until re-saved in the Tiptap editor.
// See specs/keystone-document-migration.md for data migration guidance.
content: richText()
document() fieldsrichText(), update importspnpm add @opensaas/stack-tiptap, pnpm remove @keystone-6/fields-document)// NOTE: comment above each migrated field