Schema Editor (VS Code Extension)

The Kalp Schema Editor is a VS Code extension (kalp-schema-editor) that provides a graphical, Guidewire PCF-style screen designer for PolicyOne screens. Open it with Cmd+Shift+P → "Kalp: Open Schema Editor".

All screen definitions live in co-located _screen.meta.ts files next to each page component. The extension reads and writes these files directly. Changes are buffered in memory and only written to disk when you explicitly click Save — there is no auto-save.


Concepts

ConceptDescription
ScreenA single page (ScreenMeta). Has a layout (wizard, form, detail, list), route, and server linkage.
StepOne page of a multi-step wizard. Each step contains sections.
SectionA labeled group of fields within a step or form. Supports visibleFor conditional display.
FieldA single input. Defined by id, label, type, and optional metadata.
RepeaterA field of type repeater — renders as an inline table with configurable sub-columns (vehicles, drivers, locations, etc.).

Interface Overview

Screen Sidebar (left panel)

Lists all _screen.meta.ts files found in apps/policyone/app. Screens are grouped by the first segment of their route (e.g. all /submissions/... screens appear under Submissions). Each entry shows the screen title and a layout badge (wizard, form, detail, list).

Click a screen to select it and load it into the main panel.

Header buttons:

  • ↻ Refresh — re-reads all _screen.meta.ts files from disk, discarding any unsaved in-memory edits
  • Open File — opens the selected screen's _screen.meta.ts directly in the VS Code editor
  • Save Changes — writes the current in-memory state back to the _screen.meta.ts file on disk. A ● dot appears next to "Save Changes" whenever there are unsaved edits.

Preview / Schema Toggle

The header has a two-button toggle:

ModeDescription
PreviewRenders a pixel-accurate simulation of the screen UI. Fields are interactive. Inspector panel is on the right.
SchemaTabbed table view — one tab per section, showing all fields as rows with inline-editable ID and Label cells. Good for bulk editing IDs and labels without clicking through each field.

Preview Mode

Preview mode renders the screen using the same layout rules as the actual app. Click any element to inspect and edit it.

Layout Rendering

LayoutWhat renders
wizardSidebar stepper + main content area + nav buttons (Back / Continue / Submit). Transaction toolbar at the top.
formSingle-page form with Save / Cancel buttons in the page header.
detailDetail view — same as form.
listStats bar, filter bar, and data table — each driven by named sections (stats, filter, table, and any others).

Working with Fields

  • Select a field — click anywhere on the field wrapper. The inspector panel opens on the right and switches to the Field tab.
  • Reorder fields — grab the ⠿ drag handle on the left of any field wrapper and drag it up or down within the same section. Drop position is indicated by a blue line.
  • Delete a field — click the ✕ button that appears on the right of the field wrapper (visible on hover).
  • Add a field — click the + Add Field button at the bottom of any section. A new text field is appended and immediately selected in the inspector so you can set its properties.

Working with Sections

  • Select a section — click the section title bar. The inspector switches to the Section tab.
  • Delete a section — click ✕ on the right of the section title bar.
  • Add a section — click + Add Section at the bottom of the page content area. Sections are always added to the current step (wizard) or to the flat section list (form/detail).

Interactive Preview Widgets

radio-cards, pill-toggle, and select fields are fully interactive in preview mode — clicking them updates the live visibleFor simulation without a reload (see Live visibleFor Simulation).


Schema (Table) Mode

Schema mode shows all sections as tabs across the top. Each tab renders a table of that section's fields:

ColumnDescription
IDThe field's id. Click to edit inline (contenteditable).
LabelThe display label. Click to edit inline.
Type / VisibilityType badge, plus visibleFor and permissions indicators if set.
DB ColumnThe dbColumn mapping, or — if not set.
Requiredrequired badge, req:<context> if requiredFor is set, or —.
(actions)Delete button — removes the field immediately (still requires Save to persist).

Inline editing: click any ID or Label cell to edit it in place. Changes are committed when focus leaves the cell.

Add Field form at the bottom of each section: enter an ID, label, and type and click Add. The new field is appended to the section and the table re-renders.


Inspector Tabs

The inspector panel (right side, Preview mode only) has three tabs:

Field Tab

Click any field in the preview to open this tab.

PropertyDescription
idcamelCase key matching form state
labelDisplay label
typeField type (see Field Types below)
dbColumnReference mapping e.g. party.first_name
requiredBoolean — marks field as always required
requiredForContext-specific required e.g. all, new_renewal
visibleForCondition to show this field e.g. partyType:person
permissionsRole gate — field is hidden from users without this role e.g. carrier_admin
placeholderInput placeholder text
hintHelper text shown below the field
defaultValuePre-filled value
dependsOnField ID whose change should reload this field's options (cascading selects)
fetchesOnField ID whose change triggers an async data fetch
columnsSub-column definitions for repeater type fields
optionsValue/label pairs for select, radio-cards, pill-toggle

All changes in the Field tab take effect instantly in the preview and are buffered in memory until saved.

Section Tab

Click a section title bar to open this tab.

PropertyDescription
idSection identifier
titleSection heading displayed above the fields
descriptionOptional subtitle below the heading
visibleForCondition to show/hide the entire section (see Live visibleFor Simulation)

⚙ Page Tab

Always accessible — shows screen-level metadata. This tab is the default when no field or section is selected.

PropertyDescription
idUnique screen ID e.g. submissions.new
titlePage heading
descriptionOptional subtitle
routeNext.js route e.g. /submissions/new
layoutwizard | form | detail | list
componentFilePath to the .tsx component relative to apps/policyone
serverActionForm submit handler e.g. lib/actions/submissions.ts → createSubmission()
dataSourceQuery that populates the page e.g. packages/db/src/queries/submissions.ts → fetchSubmissions()

Changes on the Page tab update the screen sidebar title immediately.


Field Types

TypeRenders asInteractive in preview
textSingle-line text inputNo
emailEmail inputNo
telPhone number inputNo
dateDate pickerNo
numberNumeric inputNo
selectDropdownYes — updates visibleFor state
radio-cardsCard-style radio buttonsYes — updates visibleFor state
pill-toggleInline pill buttonsYes — updates visibleFor state
checkboxBoolean checkboxNo
textareaMulti-line text areaNo
repeaterInline table with sub-columnsNo (skeleton rows shown)

Live visibleFor Simulation

The preview evaluates visibleFor conditions in real time — no reload or save needed.

Syntax:

FormatExampleMeaning
fieldId:valuepartyType:personShow when the named field equals the given value
OR conditions (comma-separated)lob:auto,lob:homeShow when any condition is met
Bare role stringcarrier_adminAlways shown in preview (roles are not simulated)

Both section-level and field-level visibleFor are evaluated. When a condition is not met the section or field is hidden instantly. A ◎ condition badge appears next to the section title or field label to indicate it is conditional.

When you click an interactive field (radio-cards, pill-toggle, select), the selection is recorded and all visibleFor conditions across the entire screen are re-evaluated immediately.

Note: Field values reset to defaults when you switch to a different screen.


Wizard Step Management

In wizard screens the left sidebar shows the step list and supports full CRUD:

ActionHow
Add stepClick + Add Step at the bottom of the step sidebar
Navigate to stepClick the step in the sidebar (or use Back / Continue buttons in the preview)
Rename stepDouble-click the step label to edit it inline; press Enter to commit or Escape to cancel
Reorder stepsHover a step to reveal ↑ / ↓ arrow buttons
Delete stepHover a step and click ✕ — blocked if only one step remains

The current step indicator in the transaction toolbar (e.g. "Draft · Step 2 of 4") updates automatically as you add, remove, and navigate steps.


Transaction Toolbar

Wizard screens automatically show a color-coded transaction toolbar above the content area. The transaction type is detected from the screen's id:

Screen ID containsTransaction typeAction buttons shown
endorseEndorsement (indigo)Save Draft, Calculate Premium, Bind Endorsement, Withdraw
cancelCancellation (red)Save Draft, Compute Refund, Process Cancellation, Withdraw
reinstateReinstatement (emerald)Save Draft, Bind Reinstatement, Withdraw
renewRenewal (amber)Save Draft, Quote Renewal, Bind Renewal, Non-Renew
(anything else)New Submission (orange)Save Draft, Quote, Bind / Issue, Withdraw

The toolbar also shows the current step count (e.g. "Draft · Step 1 of 3"). All buttons are display-only in the editor preview — they do not trigger any server action.


Repeater Columns

When a field's type is repeater, the Field inspector shows a Columns editor below the standard properties:

Column propertyDescription
idColumn key
labelColumn header label
typeCell widget: text, number, date, select, checkbox

Use + Add to append a column and ✕ to remove one. The preview renders the repeater as a mini inline table with column headers, 2 skeleton data rows, and a disabled "+ Add Row" button.


Save and File Workflow

  1. Make edits in the editor (preview or schema view).
  2. The Save Changes ● button in the header gets a ● dot indicating unsaved changes.
  3. Click Save Changes (or your keyboard shortcut) to write the updated _screen.meta.ts to disk.
  4. A success toast confirms the save. The ● dot clears.
  5. Click Open File to jump to the raw _screen.meta.ts in the VS Code editor if you need to make changes outside the UI.
  6. Click ↻ Refresh to discard all in-memory edits and re-read from disk.

Changes written to disk take effect immediately in the running Next.js dev server — Next.js hot-reloads the updated _screen.meta.ts module automatically.


ScreenMeta File Format

Every screen has a _screen.meta.ts file co-located with its page component:

import type { ScreenMeta } from '@/lib/screen-meta/types'

export const meta: ScreenMeta = {
  id:            'submissions.new',
  title:         'New Submission',
  route:         '/submissions/new',
  layout:        'wizard',
  componentFile: 'app/(shell)/submissions/new/page.tsx',
  serverAction:  'lib/actions/submissions.ts → createSubmission()',
  dataSource:    'packages/db/src/queries/submissions.ts → fetchProductCatalog()',

  steps: [
    {
      id:    'step_policy_type',
      title: 'Policy Type',
      sections: [
        {
          id:     'section_lob',
          title:  'Line of Business',
          fields: [
            {
              id:      'lob',
              label:   'What would you like to insure?',
              type:    'radio-cards',
              options: [
                { value: 'personal_auto', label: 'Personal Auto' },
                { value: 'homeowners',    label: 'Homeowners' },
              ],
            },
            {
              id:         'vehicleCount',
              label:      'Number of vehicles',
              type:       'number',
              visibleFor: 'lob:personal_auto',  // hidden unless lob = personal_auto
            },
          ],
        },
      ],
    },
    {
      id:    'step_named_insureds',
      title: 'Named Insureds',
      sections: [
        {
          id:     'section_drivers',
          title:  'Drivers',
          visibleFor: 'lob:personal_auto',  // entire section hidden for non-auto
          fields: [
            {
              id:      'drivers',
              label:   'Driver list',
              type:    'repeater',
              columns: [
                { id: 'firstName', label: 'First Name' },
                { id: 'lastName',  label: 'Last Name' },
                { id: 'dob',       label: 'Date of Birth', type: 'date' },
                { id: 'license',   label: 'License #' },
              ],
            },
          ],
        },
      ],
    },
  ],
}

Building the Extension

pnpm --filter kalp-schema-editor compile

Output is written to packages/schema-editor/out/. After every change to the extension source, run compile then use "Developer: Reload Window" in VS Code to pick up the new build.


Concepts

ConceptDescription
ScreenA single page (ScreenMeta). Has a layout (wizard, form, detail, list), route, and server linkage.
StepOne page of a multi-step wizard. Each step contains sections.
SectionA labeled group of fields within a step or form. Supports visibleFor conditional display.
FieldA single input. Defined by id, label, type, and optional metadata.
RepeaterA field of type repeater — renders as an inline table with configurable sub-columns (vehicles, drivers, locations, etc.).

Field Types

TypeRenders as
textSingle-line text input
emailEmail input
telPhone number input
dateDate picker
numberNumeric input
selectDropdown
radio-cardsCard-style radio buttons (interactive in preview)
pill-toggleInline pill buttons (interactive in preview)
checkboxBoolean checkbox
textareaMulti-line text area
repeaterInline table with configurable sub-columns

Inspector Tabs

The inspector panel on the right has three tabs:

Field Tab

Edit the selected field's properties:

PropertyDescription
idcamelCase key matching form state
labelDisplay label
typeField type (see table above)
dbColumnReference mapping e.g. party.first_name
requiredMarks field as required
requiredForContext-specific required e.g. all, new_renewal
visibleForCondition to show field e.g. partyType:person
permissionsRole gate e.g. carrier_admin
placeholderInput placeholder text
hintHelper text shown below the field
defaultValuePre-filled value
dependsOnField ID whose change reloads this field's options
fetchesOnField ID whose change triggers an async data load
columnsSub-columns for repeater type fields
optionsValue/label pairs for select, radio-cards, pill-toggle

Section Tab

Edit the selected section's id, title, description, and visibleFor condition.

⚙ Page Tab

Edit screen-level metadata:

PropertyDescription
idUnique screen ID e.g. submissions.new
titlePage heading
descriptionOptional subtitle
routeNext.js route e.g. /submissions/new
layoutwizard | form | detail | list
componentFilePath to the .tsx component relative to apps/policyone
serverActionForm submit handler e.g. lib/actions/submissions.ts → createSubmission()
dataSourceQuery that populates the page e.g. packages/db/src/queries/...

Live visibleFor Simulation

The preview evaluates visibleFor conditions in real time — no reload needed.

  • Format: fieldId:value — e.g. partyType:person hides/shows the section or field based on the current radio-card or pill selection in the preview
  • OR conditions: comma-separated — e.g. lob:auto,lob:home shows when either condition is met
  • Role-based: a bare string with no : (e.g. carrier_admin) is always shown in preview since roles are not simulated

When you click a radio-cards, pill-toggle, or select widget in the preview, the extension instantly hides or reveals sections and fields whose visibleFor condition is or is not met. Both section-level and field-level visibleFor are supported.


Wizard Step Management

In wizard screens, the step sidebar supports full CRUD:

  • Add step — click the "+ Add Step" button at the bottom of the step sidebar
  • Rename step — double-click the step label to edit it inline; press Enter or Escape to commit/cancel
  • Reorder steps — hover a step to reveal ↑ / ↓ arrow buttons
  • Delete step — hover a step and click ✕ (the last remaining step cannot be deleted)

Transaction Toolbar

Wizard screens automatically show a color-coded transaction toolbar above the content area based on the screen's id:

Screen ID containsTransaction typeAccent color
endorseEndorsementIndigo
cancelCancellationRed
reinstateReinstatementEmerald
renewRenewalAmber
(anything else)New SubmissionOrange

The toolbar shows the transaction type chip, current step position (e.g. "Draft · Step 2 of 4"), and contextual action buttons (Save Draft, Quote, Bind / Issue, etc.). These buttons are display-only in the editor preview.


Repeater Columns

When a field's type is set to repeater, the Field inspector shows a Columns editor below the standard properties. Each column has:

PropertyDescription
idColumn key
labelColumn header label
typeCell widget type (text, number, date, select, checkbox)

The preview renders the repeater as a mini inline table with 2 skeleton rows and a disabled "+ Add Row" button.


ScreenMeta File Format

Every screen has a _screen.meta.ts file co-located with its page component:

import type { ScreenMeta } from '@/lib/screen-meta/types'

export const meta: ScreenMeta = {
  id:            'submissions.new',
  title:         'New Submission',
  route:         '/submissions/new',
  layout:        'wizard',
  componentFile: 'app/(shell)/submissions/new/page.tsx',
  serverAction:  'lib/actions/submissions.ts → createSubmission()',
  dataSource:    'packages/db/src/queries/submissions.ts → fetchProductCatalog()',

  steps: [
    {
      id:    'step_policy_type',
      title: 'Policy Type',
      sections: [
        {
          id:     'section_lob',
          title:  'Line of Business',
          fields: [
            {
              id:      'lob',
              label:   'What would you like to insure?',
              type:    'radio-cards',
              options: [
                { value: 'personal_auto', label: 'Personal Auto' },
                { value: 'homeowners',    label: 'Homeowners' },
              ],
            },
            {
              id:         'vehicleCount',
              label:      'Number of vehicles',
              type:       'number',
              visibleFor: 'lob:personal_auto',  // hidden unless lob = personal_auto
            },
          ],
        },
      ],
    },
  ],
}

Building the Extension

pnpm --filter kalp-schema-editor compile

Output is written to packages/schema-editor/out/. After every change to the extension source, run compile then use "Developer: Reload Window" in VS Code to pick up the new build.