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>
6.1 KiB
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 inputtextarea-> Multi-line text fieldnumber-> Number inputtoggle-> Obsidian Toggle componentdate-> Native HTML date pickerdropdown-> Obsidian Dropdown componenttags-> Multi-select with autocomplete (from existing vault tags)note-link-> Text input with vault file suggestfolder-picker-> Text input with folder suggestrating-> 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