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>
This commit is contained in:
Luca Oelfke 2026-02-13 12:58:52 +01:00
commit 4f02ba3d37

View file

@ -0,0 +1,182 @@
# 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
```typescript
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