# Memo and Description Filters Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add a new memo filter and enhance the existing description filter to use case-insensitive regex matching on the transaction page.

**Architecture:** Modify the existing query schema, filter UI, and query logic in `src/clj/auto_ap/ssr/transaction/common.clj`. Both filters convert user input to regex patterns with `(?i)` flag and use Datomic's `re-find`.

**Tech Stack:** Clojure, Datomic, Hiccup, Malli schema validation

---

## File Structure

- **Modify:** `src/clj/auto_ap/ssr/transaction/common.clj` — add memo to query schema, add memo filter UI, update description filter to use regex, add memo filter to query logic
- **Test:** `test/clj/auto_ap/ssr/transaction/common_test.clj` — create new test file for filter logic (or add to existing transaction tests)

---

### Task 1: Update Query Schema

**Files:**
- Modify: `src/clj/auto_ap/ssr/transaction/common.clj:42`

- [ ] **Step 1: Add `:memo` to query-schema**

Add after the `:description` field in the query-schema map:

```clojure
[:memo {:optional true} [:maybe [:string {:decode/string strip}]]]
```

It should be placed after `:description` (line 42) and before `:vendor` (line 43).

---

### Task 2: Update Description Filter Query Logic

**Files:**
- Modify: `src/clj/auto_ap/ssr/transaction/common.clj:140-145`

- [ ] **Step 1: Change description filter from `.contains` to `re-find`**

Replace the description filter block (lines 140-145):

```clojure
(seq (:description args))
(merge-query {:query {:in    ['?description]
                      :where ['[?e :transaction/description-original ?do]
                              '[(clojure.string/lower-case ?do) ?do2]
                              '[(.contains ?do2 ?description)]]}
              :args  [(str/lower-case (:description args))]})
```

With:

```clojure
(seq (:description args))
(merge-query {:query {:in    ['?description-regex]
                      :where ['[?e :transaction/description-original ?do]
                              '[(re-find ?description-regex ?do)]]}
              :args  [(re-pattern (str "(?i).*" (str/lower-case (:description args)) ".*"))]})
```

---

### Task 3: Add Memo Filter Query Logic

**Files:**
- Modify: `src/clj/auto_ap/ssr/transaction/common.clj` (after description filter block)

- [ ] **Step 1: Add memo filter condition in fetch-ids cond-> chain**

Add after the description filter block (around line 145) and before the amount-gte filter:

```clojure
(seq (:memo args))
(merge-query {:query {:in    ['?memo-regex]
                      :where ['[?e :transaction/memo ?memo]
                              '[(re-find ?memo-regex ?memo)]]}
              :args  [(re-pattern (str "(?i).*" (str/lower-case (:memo args)) ".*"))]})
```

---

### Task 4: Add Memo Filter UI

**Files:**
- Modify: `src/clj/auto_ap/ssr/transaction/common.clj:340-355` (around the description filter UI)

- [ ] **Step 1: Add memo filter input in the filters function**

Add after the description filter input (lines 340-346) and before the location filter (lines 348-354):

```clojure
(com/field {:label "Memo"}
           (com/text-input {:name        "memo"
                            :id          "memo"
                            :class       "hot-filter"
                            :value       (:memo (:query-params request))
                            :placeholder "e.g., Rent"
                            :size        :small}))
```

---

### Task 5: Write Tests

**Files:**
- Create: `test/clj/auto_ap/ssr/transaction/common_test.clj`

- [ ] **Step 1: Create test file for filter logic**

```clojure
(ns auto-ap.ssr.transaction.common-test
  (:require
   [auto-ap.ssr.transaction.common :as sut]
   [clojure.test :as t :refer [deftest is testing use-fixtures]]))

(deftest description-filter-regex-pattern
  (testing "Description filter creates correct regex pattern"
    (let [pattern (re-pattern (str "(?i).*" "Groceries" ".*"))]
      (is (re-find pattern "My Groceries Store"))
      (is (re-find pattern "GROCERIES"))
      (is (re-find pattern "groceries shop"))
      (is (not (re-find pattern "Restaurant"))))))

(deftest memo-filter-regex-pattern
  (testing "Memo filter creates correct regex pattern"
    (let [pattern (re-pattern (str "(?i).*" "Rent" ".*"))]
      (is (re-find pattern "Monthly Rent"))
      (is (re-find pattern "RENT"))
      (is (re-find pattern "rent payment"))
      (is (not (re-find pattern "Utilities"))))))
```

- [ ] **Step 2: Run tests to verify they pass**

Run: `clj-nrepl-eval -p PORT "(clojure.test/run-tests 'auto-ap.ssr.transaction.common-test)"`

Expected: All tests pass

---

### Task 6: Verify Changes

**Files:**
- Modify: `src/clj/auto_ap/ssr/transaction/common.clj`

- [ ] **Step 1: Check that both filters work correctly**

1. Start the application: `INTEGREAT_JOB="" lein run`
2. Navigate to the transaction page
3. Test description filter:
   - Enter "gro" in description filter
   - Should show transactions with descriptions containing "gro" (case-insensitive)
4. Test memo filter:
   - Enter "rent" in memo filter  
   - Should show transactions with memos containing "rent" (case-insensitive)
5. Test combined filters:
   - Use both description and memo filters together
   - Should show only transactions matching both criteria

- [ ] **Step 2: Commit changes**

```bash
git add src/clj/auto_ap/ssr/transaction/common.clj
git add test/clj/auto_ap/ssr/transaction/common_test.clj
git commit -m "feat: add memo filter and enhance description filter with regex matching"
```

---

## Self-Review

**Spec coverage check:**
- ✅ New memo filter added to query schema (Task 1)
- ✅ Memo filter uses `re-find` with `(?i)` flag (Task 3)
- ✅ Description filter enhanced to use `re-find` (Task 2)
- ✅ Both filters wrap input with `.*` on both ends
- ✅ Memo filter placed after description filter in query logic (Task 3)
- ✅ Memo filter UI added to filter sidebar (Task 4)
- ✅ Tests written for regex patterns (Task 5)

**Placeholder scan:**
- No TBDs, TODOs, or placeholder text found
- All code blocks contain actual implementation code

**Type consistency:**
- `:memo` field uses same schema structure as `:description`
- Both filters use `re-pattern` with `(?i)` flag consistently

## Execution Handoff

Plan complete and saved to `docs/superpowers/plans/2026-05-26-memo-description-filter-plan.md`. 

**Two execution options:**

**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration

**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints

Which approach?
