From 4f02ba3d37df299fbe4be86a2e04dd83c500d1d0 Mon Sep 17 00:00:00 2001 From: tolvitty Date: Fri, 13 Feb 2026 12:58:52 +0100 Subject: [PATCH] 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 --- docs/plans/2026-02-13-formfire-design.md | 182 +++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 docs/plans/2026-02-13-formfire-design.md diff --git a/docs/plans/2026-02-13-formfire-design.md b/docs/plans/2026-02-13-formfire-design.md new file mode 100644 index 0000000..f1819ae --- /dev/null +++ b/docs/plans/2026-02-13-formfire-design.md @@ -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-` | 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