obsidian-formfire/docs/plans/2026-02-13-formfire-design.md
tolvitty 4f02ba3d37 Add Formfire design document
Design for structured data input plugin completing the Fire-Suite
(Input -> Observe -> Output). Covers data model, architecture,
UI concept, and scope for V1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 12:58:52 +01:00

6.1 KiB

Formfire Design Document

Date: 2026-02-13 Status: Approved Plugin: obsidian-formfire Suite: Fire-Suite (Promptfire = Output, Logfire = Observe, Formfire = Input)

Problem

Obsidian has no native solution for structured data input. Every vault power user reaches a point where they want a form instead of manually typing frontmatter. Existing community solutions (Templater, MetaEdit) solve this only fragmentarily.

Formfire closes the Input gap in the Fire-Suite triangle: Input (Formfire) -> Observe (Logfire) -> Output (Promptfire).

Decisions

Aspect Decision
Form Storage Plugin Settings
Output Mode Both: create new note OR update existing frontmatter
Access Command Palette + Sidebar View
Field Types Text, Textarea, Number, Toggle, Date, Dropdown, Tags, Note-Link, Folder-Picker, Rating
Body Template Yes, with {{variable}} substitution
Form Editor Visual Form Builder in Settings Tab
Architecture A+B Hybrid (pragmatic with clean separation)

Data Model

interface FormDefinition {
  id: string;                          // UUID
  name: string;                        // "Meeting-Notiz", "Buchrezension"
  icon: string;                        // Obsidian icon name
  mode: "create" | "update";

  // mode: "create" only
  targetFolder?: string;
  fileNameTemplate?: string;           // e.g. "{{datum}}-{{titel}}"
  bodyTemplate?: string;               // Markdown with {{variables}}

  // mode: "update" only
  targetFile?: "active" | "prompt";

  fields: FormField[];
}

interface FormField {
  id: string;                          // Unique key (becomes frontmatter property)
  label: string;                       // Display name
  type: FieldType;
  required: boolean;
  defaultValue?: any;
  placeholder?: string;
  options?: string[];                  // For dropdown/tags
  folder?: string;                     // For note-link: which folder to search
}

type FieldType =
  | "text" | "textarea" | "number" | "toggle"
  | "date" | "dropdown" | "tags"
  | "note-link" | "folder-picker" | "rating";

Architecture

obsidian-formfire/
├── src/
│   ├── main.ts                    // Plugin class, commands, view registration
│   ├── types.ts                   // All interfaces
│   ├── core/
│   │   ├── form-store.ts          // CRUD for FormDefinitions in Settings
│   │   └── form-processor.ts      // Create note / update frontmatter
│   ├── ui/
│   │   ├── settings-tab.ts        // Settings tab with form builder
│   │   ├── form-builder.ts        // Visual form builder (add/edit fields)
│   │   ├── form-modal.ts          // The form modal for filling out
│   │   ├── form-sidebar.ts        // Sidebar view with form list
│   │   └── field-renderers.ts     // Renderer per field type
│   └── utils/
│       ├── template-engine.ts     // {{variable}} substitution
│       └── validators.ts          // Field validation
├── styles.css
├── manifest.json
├── package.json
├── tsconfig.json
└── esbuild.config.mjs

Data Flow

User opens form (Command/Sidebar)
        |
FormStore loads FormDefinition from Settings
        |
FormModal renders fields via FieldRenderers
        |
User fills out -> Submit
        |
FormProcessor:
  mode:"create" -> Template Engine -> vault.create()
  mode:"update" -> processFrontMatter() on active/chosen note

UI Concept

A) Settings Tab: Visual Form Builder

  • Top: List of all forms (name, mode, field count) with Add/Edit/Delete/Duplicate buttons
  • Bottom / Modal: Form builder opens on edit with:
    • Name, Icon, Mode selector (create/update)
    • Field list with reorder (up/down buttons)
    • Per field: type dropdown, label, key, required toggle, type-specific options
    • For create mode: target folder, filename template, body template textarea

B) Form Modal (for filling out)

  • Title: form name + icon
  • Fields rendered vertically by type:
    • text -> Obsidian Setting with text input
    • textarea -> Multi-line text field
    • number -> Number input
    • toggle -> Obsidian Toggle component
    • date -> Native HTML date picker
    • dropdown -> Obsidian Dropdown component
    • tags -> Multi-select with autocomplete (from existing vault tags)
    • note-link -> Text input with vault file suggest
    • folder-picker -> Text input with folder suggest
    • rating -> 5 clickable stars
  • Bottom: Submit button + validation feedback for required fields
  • For mode: "update" + targetFile: "prompt": File picker first, then form (pre-filled with existing frontmatter values)

C) Sidebar View

  • Simple list of all forms with icon + name
  • Click -> opens FormModal
  • Gear icon -> opens Settings directly

Note: Detailed UI will be designed using the frontend-design skill during implementation.

Commands

Command Description
formfire:open-form Opens picker modal with all forms, then the chosen FormModal
formfire:open-form-<name> Dynamically registered commands per form (direct access)
formfire:open-sidebar Open/focus sidebar view
formfire:open-settings Jump directly to Formfire settings

Ribbon Icon: Form icon in left sidebar, opens form picker.

Template Engine

Intentionally simple:

{{fieldname}}    -> Value of the field
{{date}}         -> Current date (YYYY-MM-DD)
{{time}}         -> Current time (HH:mm)
{{datetime}}     -> Date + time

Used in:

  • fileNameTemplate (filename for new notes)
  • bodyTemplate (markdown content of new notes)

Out of Scope for V1

  • No conditional logic (show field X only if field Y = ...)
  • No multi-step wizard
  • No export/import of form definitions
  • No computed fields
  • No custom CSS per form
  • No API for other plugins

Technical Conventions (from Fire-Suite)

  • Build: esbuild, ES2022 target
  • Settings: deep merge pattern (from Logfire)
  • Plugin lifecycle: standard Obsidian pattern (loadSettings -> register -> start)
  • Feedback: Obsidian Notice API
  • File access: vault.create(), processFrontMatter(), metadataCache