1. Product Overview

Product Name: Inserable

Target Platform: macOS

Tech Stack: Swift + SwiftUI

Core Function: Manage image assets for Hugo blogs, auto-rename images, and generate Markdown image-reference text.

Problem It Solves: Chaotic image organization, inconsistent naming, and tedious manual image reference writing in Hugo blogs.

2. Core Concepts

2.1 Hierarchy

Inserable

├── Root Folder 1
│   ├── Session A (Folder A)
│   │   ├── formatA_001.png
│   │   ├── formatA_002.png
│   │   └── ...
│   ├── Session B (Folder B)
│   │   └── ...
│   └── ...
└── Root Folder 2
    ├── Session X (Folder X)
    │   └── ...
    └── ...

2.2 Core Relationships

ConceptDescription
Root FolderUser’s Hugo image storage path, e.g. /Users/alex/myblog/static/images/. Up to 2 supported.
Session1:1 bound to one folder under a root folder. Session name = folder name.
ImageImage file inside a Session folder, named under unified rules.

2.3 Naming Rules

Image naming format: <formatting_1>_<###>.<ext>

  • <formatting_1>: user-defined naming prefix per Session
  • <###>: 3-digit zero-padded sequence (001, 002, 003…), ordered by creation time, independently counted per Session
  • <ext>: unified to PNG

Markdown output format:

![<formatting_1>_<###>.png](/images/<session_folder>/<formatting_1>_<###>.png)

3. Data Integrity Mechanism

3.1 Mirror Backup

ItemDescription
TriggerAuto-run every 5 minutes
StorageApplication Support/Inserable/Mirror/
RetentionKeep latest snapshot only
Snapshot ContentRoot structure (Session folder names + image filename lists)

3.2 Integrity Validation

Validation scope:

  • Root level: Session folder names + count
  • Session level: image filenames + count

Validation timing:

  • On app startup
  • On each mirror cycle (every 5 minutes)
  • When user clicks IN SYNC

Inconsistency handling (Integrity Error):

When any external modification is detected, mark ERROR and lock affected area. User must pick one action from the popup:

OptionBehavior
Restore from MirrorRestore disk files to mirror snapshot state (revert external changes).
Delete SessionRemove Session; move folder to Trash.
Re-sync (Accept Changes)Use current disk state as source of truth; update metadata and mirror.

Detailed Re-sync (Accept Changes) logic:

  1. Scan current Session folder.
  2. Classify and process:
    • Compliant files (match <formatting_1>_<###>.png): keep and update metadata.
    • Non-compliant images: force-standardize; treat as newly added images, assign new sequence (max+1), convert to PNG, rename, set originalPath to unknown (re-synced).
    • Non-image files: prompt user to remove manually or move to Trash.
  3. Update state: update nextSequenceNumber and persist immediately.
  4. Snapshot: generate new mirror snapshot and unlock.

3.3 Allowed Exceptions

  • .DS_Store: auto-ignored.
  • Same-name content replacement: validate filenames only, not file contents (allows users to edit and save in Preview).

4. Root Folder Management

4.1 Root Folder Requirements

  • Maximum 2 root folders.
  • Root folder may contain only subfolders or be empty.
  • If non-folder files are found (e.g., loose .png), prompt user to clean up before continuing.

4.2 Root Folder Initialization Flow

User selects folder
Scan folder contents
[Illegal files exist?] -> Yes: prompt cleanup, block flow
↓ No
Create corresponding Session for each subfolder (name = folder name)
Sort Sessions alphabetically
Initialization complete (Sessions in "pending standardization" state)

4.3 Root Folder Switching

  • Switching root folder means migrating all Session folders to the new location.
  • Existing data (Sessions, mirror) for the old root is cleared and rebuilt.

5. Session Management

5.1 Session Creation Methods

Method A: Click New Session

  1. Create empty folder under current root, default newsession<#>.
  2. New item appears in Session list.
  3. User may rename Session (sync-rename folder).
  4. Session remains empty until images are dropped.

Method B: Drop a folder onto New Session

  1. Staging: app reads/stages absolute paths for all images in source folder.
  2. User input: popup requests <formatting_1>.
    • If canceled: abort and clear staged data.
  3. Copy folder to current root.
  4. Atomic safety check:
    • Verify target files exist and size > 0.
    • If verification fails: rollback (remove incomplete copied files), abort, keep source folder.
  5. Standardize using staged original paths to build metadata.
  6. Source handling: only after steps 4+5 succeed, move source folder to Trash based on settings.

5.2 Session Standardization Flow

When first dropping images into an empty Session, or creating Session from a folder:

Prompt user for <formatting_1>
[User canceled?] -> Yes: abort, keep Session unchanged
↓ No
Sort all images by creation time
Convert all images to PNG
Rename to: <formatting_1>_001.png, <formatting_1>_002.png, ...
Generate change log (first standardization)
Persist nextSequenceNumber + metadata immediately
Create mirror snapshot

5.3 Session Deletion

  • On delete, folder is renamed to <original_name>_Inserable_conflict then moved to Trash.
  • Session record is removed from Inserable.

6. Image Operations

6.1 Add Image

Action: drop images onto selected Session area.

Processing:

  1. Stage original absolute path.
  2. Pre-check: if Session is not standardized, trigger standardization first.
  3. Copy file into Session folder.
  4. Atomic safety check:
    • target file exists and size > 0;
    • if fail: rollback + abort + keep original file.
  5. Standardize:
    • convert to PNG,
    • assign next available sequence number,
    • rename to <formatting_1>_<###>.png,
    • write staged original path into metadata.
  6. Immediate persistence: write updated nextSequenceNumber to disk immediately.
  7. Source handling: only after success of all above, optionally move source image to Trash.
  8. Mirror update.

6.2 View Image

  • Click image row (outside COPY button) to open image with system Preview.app.

6.3 Image Format Conversion

Priority: PNG > JPG > WEBP

Rule: all images are standardized to PNG.

7. Output Functions

7.1 Copy Single

Click COPY on an image row to copy that image’s Markdown reference to clipboard.

7.2 Copy All

  • After first standardization: output includes Markdown references + Original Path log.
  • Subsequent copy-all: concise Markdown reference list only.

7.3 Change Log Backup

  • Location: Application Support/Inserable/past_change_log/
  • Filename: <session_folder>_<dd-mm-yyyy>_change_log_backup.txt
  • Content: full output from first standardization (with Original Path)

8. Global Settings

SettingTypeDescription
Root Folder 1 pathPath pickerFirst Hugo image root directory
Root Folder 2 pathPath pickerSecond Hugo image root directory
Delete original imageCheckboxMove source image to Trash after import
Delete original folderCheckboxMove source folder to Trash after folder import
Dark/Light modeToggleUI theme switch

9. UI Layout

9.1 Main UI Structure

┌─────────────────────────────────────────────────────────────┐
│ ● ● ●                                                       │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐   ┌─────────────────────────────────────┐  │
│  │ ROOT_FOLDER │   │         SESSION NAME                │  │
│  │ (switchable)│   │  ┌─────────────────────────────────┐│  │
│  ├─────────────┤   │  │ COPY │      pic_001.png        │││  │
│  │             │   │  ├─────────────────────────────────┤│  │
│  │ SESSION 1   │   │  │ COPY │      pic_002.png        │││  │
│  │ SESSION 2   │   │  ├─────────────────────────────────┤│  │
│  │ SESSION 3   │   │  │ COPY │      pic_003.png        │││  │
│  │ ...         │   │  │ ...                             ││  │
│  │             │   │  │                          [scroll]│  │
│  │             │   │  └─────────────────────────────────┘│  │
│  │             │   └─────────────────────────────────────┘  │
│  │ ┌─────────┐ │                                            │
│  │ │NEW SESS.│ │                                            │
│  │ └─────────┘ │                                            │
│  └─────────────┘                                            │
├─────────────────────────────────────────────────────────────┤
│ [IN SYNC] [SETTINGS]                        [COPY ALL]      │
└─────────────────────────────────────────────────────────────┘

inverable_deve_pic_002.png

inverable_deve_pic_003.png

inverable_deve_pic_004.png

9.2 Status Indicator

StateDisplayDescription
NormalIN SYNC (green)Integrity status is healthy
SyncingSpinner iconMirror operation running
ErrorERROR (red)Integrity issue detected

9.3 Integrity Error UI

  • Main UI is blurred; “INTEGRITY ERROR” is shown.
  • Popup options:
    1. Restore from Mirror: restore to last synced state.
    2. Re-sync (Accept Changes): accept current disk state and force-standardize non-compliant files.
    3. Delete Session: remove this Session.

10. First Launch Flow

Launch Inserable -> check configuration -> if unconfigured, show empty UI -> user clicks Root Folder -> choose folder -> initialize root -> done.

11. Error Handling

11.1 Root Folder Errors

Error TypeTriggerHandling
Illegal filenon-folder file under rootblock selection, prompt cleanup
Session name conflictcreating Session with existing namepopup for replacement (old folder to Trash)
Integrity errorSession folder name/count changedlock whole root and require repair

11.2 Session Errors

Error TypeTriggerHandling
Illegal filenon-image file in Session folderprompt cleanup or move to Trash
Integrity errorimage filename/count changedlock this Session and require repair

12. Data Storage

12.1 Storage Location

~/Library/Application Support/Inserable/

  • config.json (global settings)
  • sessions/ (Session metadata)
  • mirror/ (mirror snapshots)
  • past_change_log/ (change-log backups)

12.2 Session Metadata Structure

{
  "sessionName": "Banff_Travel",
  "formattingPrefix": "banff_picture",
  "nextSequenceNumber": 5,
  "lastUpdated": "2026-01-14T15:30:00Z",
  "isStandardized": true,
  "files": [
    {
      "currentName": "banff_picture_001.png",
      "originalName": "IMG_1190.jpeg",
      "originalPath": "/Users/alex/Downloads/IMG_1190.jpeg",
      "sequenceNumber": 1,
      "addedAt": "2026-01-14T15:25:00Z"
    }
  ]
}

13. Out of MVP Scope (Future Extensions)

  • Support more than 2 root folders
  • Session nicknames
  • Custom image format / alt text
  • Batch rename existing images
  • Multi-version mirror history

To keep implementation aligned with the above design, the following Swift project structure is recommended:

Inserable/
├── App/
│   ├── InserableApp.swift       # entry
│   └── AppDelegate.swift        # lifecycle
├── Model/
│   ├── AppConfig.swift          # global settings model
│   ├── Session.swift            # Session metadata model (Codable)
│   ├── ImageFile.swift          # image file model (Codable)
│   └── IntegrityStatus.swift    # enum: Synced, Syncing, Error
├── ViewModel/
│   ├── RootViewModel.swift      # root management + Session list logic
│   ├── SessionViewModel.swift   # image operations per Session
│   └── SettingsViewModel.swift  # settings-page logic
├── View/
│   ├── MainLayout/
│   │   ├── SidebarView.swift    # Session list on left
│   │   └── ImageListView.swift  # image list on right
│   ├── Components/
│   │   ├── ImageRowView.swift   # single image row component
│   │   └── StatusBadge.swift    # In Sync/Error indicator
│   ├── Overlays/
│   │   ├── IntegrityErrorView.swift # error popup (incl. Re-sync)
│   │   └── NewSessionPopup.swift    # create/standardize popup
│   └── SettingsView.swift
├── Service/
│   ├── FileSystemManager.swift  # core copy/delete/atomic checks
│   ├── ImageProcessor.swift     # format conversion + rename
│   ├── PersistenceManager.swift # JSON read/write (immediate persistence)
│   ├── MirrorManager.swift      # 5-min scheduled mirror
│   └── IntegrityChecker.swift   # comparison logic + Re-sync scan
├── Utils/
│   ├── Extensions.swift         # String/URL/Date extensions
│   ├── Logger.swift             # simple debug logging
│   └── PathHelper.swift         # App Support paths
└── Resources/
    ├── Assets.xcassets
    └── Info.plist

LOG

Project Start

Jan 14, 1:06am

Prototype Completed

Jan 14, 1:28am

Existing Bugs

  1. Mirror restore is broken. It does not restore to target location and can produce ghost folders.

  2. Initial copy output works only in the first standardization/copy of the first Session, with format like:

![apple_vision_pro__001.png](/images/Apple_Vision_Pro_Article/apple_vision_pro__001.png)

Original Path:

(/Users/kircerta/Desktop/Inversable_TESTING/MYBLOG_static/images/Apple_Vision_Pro_Article/Body_1.png)

============================================================

![apple_vision_pro__002.png](/images/Apple_Vision_Pro_Article/apple_vision_pro__002.png)

Original Path:

(/Users/kircerta/Desktop/Inversable_TESTING/MYBLOG_static/images/Apple_Vision_Pro_Article/Body_2.png)

============================================================

![apple_vision_pro__003.png](/images/Apple_Vision_Pro_Article/apple_vision_pro__003.png)

Original Path:

(/Users/kircerta/Desktop/Inversable_TESTING/MYBLOG_static/images/Apple_Vision_Pro_Article/Body_3.png)

At other times, output degrades to:

![appleAppArticle_001.png](/images/appleAppArticle/appleAppArticle_001.png)
![appleAppArticle_002.png](/images/appleAppArticle/appleAppArticle_002.png)
![appleAppArticle_003.png](/images/appleAppArticle/appleAppArticle_003.png)
![appleAppArticle_004.png](/images/appleAppArticle/appleAppArticle_004.png)
  1. New Session creation has serious issues:
  • Unexpected rename occurs right after creation (rename should only happen on right-click).
  • Folder-drop Session creation has delay or flawed logic.
  • Additional issues pending discovery.
  1. Ghost folders appear in Session list even when folder does not exist on disk. No preview opens, but no integrity error is raised either.

  2. No warning on root-folder modification/deletion, even though this operation can rewrite all Session records and should require explicit confirmation.

inverable_deve_pic_005.png

  1. delete original image after import toggle is ineffective (root cause unknown).
  • delete original folder toggle not fully tested, likely also problematic.
  1. Root Folder switch button is broken; clicking it opens root-folder picker directly. If only one root exists, button should be disabled.
  • Root Folder 1 and 2 can currently point to the same path (should not be allowed).
  • Root Folder 2 is not actually loaded.

inverable_deve_pic_005.png

  1. A Session marked standardized can still be opened directly. After popup closes, right panel is not blurred and does not show expected blocking state with re-activate hint.

inverable_deve_pic_005.png

  1. Session folder rename seems delayed, but final mapping is correct.

Pending Improvements

  1. UI style should move closer to Texmorph design language. Current look feels closer to Flutter than SwiftUI.

  2. Sync button animation glitches whole screen (usable but not expected).

  • Investigation suggests sync operation is too fast for current animation pipeline.
  1. Popup content is partially clipped. It does not block information transfer yet, but needs refinement.

inverable_deve_pic_006.png

  1. After Session setup, initial settings cannot be modified. Expected behavior: editable + one-click apply + modification log.

  2. Standardize button rendering/display issue.

  3. If Session loses files, current logic requires full Session delete. It works, but there may be a better approach.

Jan 14 Development Summary

  1. Overall UI layout is acceptable; details need polish. Keeping layout while applying Texmorph design language seems promising.

  2. Many hidden bugs are still untested. The above list is only a subset. Still, the fact that the app runs is already encouraging.


[to be continued…]


Jan 16, 1:56am @ Robarts Commons

Inserable Alpha 0.0.2 Development Log & Roadmap Summary: One-Tap Mapping Module

Date: 2026-01-16
Module: One-Tap Mapping Utility
Status: Feature complete / core bugs fixed


1. Dev Log (Today)

Today’s main work was building One-Tap Mapping from scratch and resolving a set of difficult macOS Sandbox + file-system interaction issues.

Fix and Improvement List

A. Core Logic Construction

  • Implemented automated organization from “scattered Root Folder” to “Session Folder”.
  • Added article-level deduplication: repeated references to same image in one article reuse file instead of generating img_1.png, img_2.png duplicates.
  • Added smart format retention with whitelist:
    • keep jpg/gif unchanged (to avoid animation loss or size inflation),
    • standardize only heic/webp and similar formats to PNG.

B. Permissions & Sandbox Battles

This was today’s critical debugging area.

  • Issue: app had read permission only, could not delete source files, causing old-residue + new-redundancy double occupancy.
  • Fix 1 (Explicit Authorization): removed auto-prefill folder path in UtilityView; forced manual folder selection via NSOpenPanel to obtain valid security-scoped write permission.
  • Fix 2 (Permission Lock): introduced startAccessingSecurityScopedResource() in manager layer to hold explicit access lock during operation.
  • Fix 3 (Output Redirection): moved logs, backups, and unused images into Downloads to avoid stricter Desktop permission constraints.

C. Algorithm Robustness

  • Fixed URL decoding mismatch bug (image%202.png vs local image 2.png) by decoding before matching.
  • Switched physical delete (removeItem) to move-to-trash (trashItem) for Gatekeeper compatibility and safer recovery path.

2. Future Improvements

Feature path is stable, but the following directions are worth next iterations.

Technical Debt & Optimization

  • Performance: current traversal is single-threaded; very large roots may block UI. Consider Swift TaskGroup for parallel file handling.
  • Transaction rollback: currently relies on .bak files. Future improvement could use atomic operation transactions with full rollback behavior.

UX/UI Enhancements

  • Add “Show Log Folder” button after operation completion to open Finder directly at log location.
  • Add ignore list (.inignore) for files that should not be processed by One-Tap Mapping (e.g., static logo/background assets in root).

3. Documentation Plan

As discussed, we will not hardcode manual content in app. Instead use a lightweight static site + client entry model.

Execution Steps

  1. Content production

    • Source: reuse existing content_zh/posts/Developer/Inverable开发文档.md.
    • Add today’s One-Tap Mapping operational logic, especially: “manual folder selection is required to grant cleanup permission.”
  2. Deployment

    • Compile with Hugo as static site.
    • Deploy to GitHub Pages or personal server.
  3. App integration

    • Entry in app menu: Help -> Inserable Documentation.
    • Implementation:
CommandGroup(replacing: .help) {
    Button("文档") {
        NSWorkspace.shared.open(URL(string: "你的网址")!)
    }
}
  1. Fallback hint
    • Keep one-line note under folder picker in UtilityView: “Please manually click the select button to grant app permission to clean old files.”

4. Closing

Inserable’s One-Tap Mapping module now meets an engineering baseline of zero residue, zero false positives, and full traceability.

Today’s debugging strongly proved: in macOS development, working with Sandbox rules is more effective than fighting them.

Mission accomplished.


(Above summary section was generated by Gemini.)