From 395e445c99207ee8f9120dbd85b0aa4fbb46d0b9 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 8 Feb 2026 08:40:40 -0800 Subject: [PATCH 1/7] Add test for Bonanza Produce invoice 03882095 Validates existing template correctly parses multi-page invoice with: - Invoice number 03882095 - Customer identifier NICK THE GREEK - Account number 600 VISTA WAY - Total of $946.24 --- dev-resources/INVOICE - 03882095.pdf | Bin 0 -> 55419 bytes test/clj/auto_ap/parse/templates_test.clj | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100755 dev-resources/INVOICE - 03882095.pdf diff --git a/dev-resources/INVOICE - 03882095.pdf b/dev-resources/INVOICE - 03882095.pdf new file mode 100755 index 0000000000000000000000000000000000000000..3810d6670f577979e63ee074d478a9969c447eb4 GIT binary patch literal 55419 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%0A4g0`8g$ob|~n9#<^1- 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 literal 0 HcmV?d00001 diff --git a/test/clj/auto_ap/parse/templates_test.clj b/test/clj/auto_ap/parse/templates_test.clj index 3313bcfb..fcdfe54b 100644 --- a/test/clj/auto_ap/parse/templates_test.clj +++ b/test/clj/auto_ap/parse/templates_test.clj @@ -51,3 +51,22 @@ (is (= "720.33" (:total (nth results 1)))) (is (= "853.16" (:total (nth results 2)))) (is (= "1066.60" (:total (nth results 3))))))) + +(deftest parse-bonanza-produce-invoice-03882095 + (testing "Should parse Bonanza Produce invoice 03882095 with customer identifier including address" + (let [pdf-file (io/file "dev-resources/INVOICE - 03882095.pdf") + pdf-text (:out (clojure.java.shell/sh "pdftotext" "-layout" (str pdf-file) "-")) + results (sut/parse pdf-text) + result (first results)] + (is (some? results) "parse should return a result") + (is (some? result) "Template should match and return a result") + (when result + (is (= "Bonanza Produce" (:vendor-code result))) + (is (= "03882095" (:invoice-number result))) + (let [d (:date result)] + (is (= 2026 (time/year d))) + (is (= 1 (time/month d))) + (is (= 23 (time/day d)))) + (is (= "NICK THE GREEK" (:customer-identifier result))) + (is (= "600 VISTA WAY" (str/trim (:account-number result)))) + (is (= "946.24" (:total result))))))) From c196723913e5b2af20f0d86a15f026ec80c70b45 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 8 Feb 2026 08:43:53 -0800 Subject: [PATCH 2/7] ok. --- .beads/.gitignore | 46 ++++++++++++++++++++++ .beads/README.md | 81 +++++++++++++++++++++++++++++++++++++++ .beads/config.yaml | 67 ++++++++++++++++++++++++++++++++ .beads/interactions.jsonl | 0 .beads/issues.jsonl | 0 .beads/metadata.json | 4 ++ .gitattributes | 3 ++ AGENTS.md | 41 ++++++++++++++++++++ 8 files changed, 242 insertions(+) create mode 100644 .beads/.gitignore create mode 100644 .beads/README.md create mode 100644 .beads/config.yaml create mode 100644 .beads/interactions.jsonl create mode 100644 .beads/issues.jsonl create mode 100644 .beads/metadata.json create mode 100644 .gitattributes create mode 100644 AGENTS.md diff --git a/.beads/.gitignore b/.beads/.gitignore new file mode 100644 index 00000000..0acd8c61 --- /dev/null +++ b/.beads/.gitignore @@ -0,0 +1,46 @@ +# SQLite databases +*.db +*.db?* +*.db-journal +*.db-wal +*.db-shm + +# Daemon runtime files +daemon.lock +daemon.log +daemon.pid +bd.sock +sync-state.json +last-touched + +# Local version tracking (prevents upgrade notification spam after git ops) +.local_version + +# Legacy database files +db.sqlite +bd.db + +# Worktree redirect file (contains relative path to main repo's .beads/) +# Must not be committed as paths would be wrong in other clones +redirect + +# Merge artifacts (temporary files from 3-way merge) +beads.base.jsonl +beads.base.meta.json +beads.left.jsonl +beads.left.meta.json +beads.right.jsonl +beads.right.meta.json + +# Sync state (local-only, per-machine) +# These files are machine-specific and should not be shared across clones +.sync.lock +.jsonl.lock +sync_base.jsonl +export-state/ + +# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here. +# They would override fork protection in .git/info/exclude, allowing +# contributors to accidentally commit upstream issue databases. +# The JSONL files (issues.jsonl, interactions.jsonl) and config files +# are tracked by git by default since no pattern above ignores them. diff --git a/.beads/README.md b/.beads/README.md new file mode 100644 index 00000000..50f281f0 --- /dev/null +++ b/.beads/README.md @@ -0,0 +1,81 @@ +# Beads - AI-Native Issue Tracking + +Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code. + +## What is Beads? + +Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git. + +**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads) + +## Quick Start + +### Essential Commands + +```bash +# Create new issues +bd create "Add user authentication" + +# View all issues +bd list + +# View issue details +bd show + +# Update issue status +bd update --status in_progress +bd update --status done + +# Sync with git remote +bd sync +``` + +### Working with Issues + +Issues in Beads are: +- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code +- **AI-friendly**: CLI-first design works perfectly with AI coding agents +- **Branch-aware**: Issues can follow your branch workflow +- **Always in sync**: Auto-syncs with your commits + +## Why Beads? + +✨ **AI-Native Design** +- Built specifically for AI-assisted development workflows +- CLI-first interface works seamlessly with AI coding agents +- No context switching to web UIs + +🚀 **Developer Focused** +- Issues live in your repo, right next to your code +- Works offline, syncs when you push +- Fast, lightweight, and stays out of your way + +🔧 **Git Integration** +- Automatic sync with git commits +- Branch-aware issue tracking +- Intelligent JSONL merge resolution + +## Get Started with Beads + +Try Beads in your own projects: + +```bash +# Install Beads +curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash + +# Initialize in your repo +bd init + +# Create your first issue +bd create "Try out Beads" +``` + +## Learn More + +- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs) +- **Quick Start Guide**: Run `bd quickstart` +- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples) + +--- + +*Beads: Issue tracking that moves at the speed of thought* ⚡ diff --git a/.beads/config.yaml b/.beads/config.yaml new file mode 100644 index 00000000..ff8bc921 --- /dev/null +++ b/.beads/config.yaml @@ -0,0 +1,67 @@ +# Beads Configuration File +# This file configures default behavior for all bd commands in this repository +# All settings can also be set via environment variables (BD_* prefix) +# or overridden with command-line flags + +# Issue prefix for this repository (used by bd init) +# If not set, bd init will auto-detect from directory name +# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc. +# issue-prefix: "" + +# Use no-db mode: load from JSONL, no SQLite, write back after each command +# When true, bd will use .beads/issues.jsonl as the source of truth +# instead of SQLite database +# no-db: false + +# Disable daemon for RPC communication (forces direct database access) +# no-daemon: false + +# Disable auto-flush of database to JSONL after mutations +# no-auto-flush: false + +# Disable auto-import from JSONL when it's newer than database +# no-auto-import: false + +# Enable JSON output by default +# json: false + +# Default actor for audit trails (overridden by BD_ACTOR or --actor) +# actor: "" + +# Path to database (overridden by BEADS_DB or --db) +# db: "" + +# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON) +# auto-start-daemon: true + +# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE) +# flush-debounce: "5s" + +# Export events (audit trail) to .beads/events.jsonl on each flush/sync +# When enabled, new events are appended incrementally using a high-water mark. +# Use 'bd export --events' to trigger manually regardless of this setting. +# events-export: false + +# Git branch for beads commits (bd sync will commit to this branch) +# IMPORTANT: Set this for team projects so all clones use the same sync branch. +# This setting persists across clones (unlike database config which is gitignored). +# Can also use BEADS_SYNC_BRANCH env var for local override. +# If not set, bd sync will require you to run 'bd config set sync.branch '. +# sync-branch: "beads-sync" + +# Multi-repo configuration (experimental - bd-307) +# Allows hydrating from multiple repositories and routing writes to the correct JSONL +# repos: +# primary: "." # Primary repo (where this database lives) +# additional: # Additional repos to hydrate from (read-only) +# - ~/beads-planning # Personal planning repo +# - ~/work-planning # Work planning repo + +# Integration settings (access with 'bd config get/set') +# These are stored in the database, not in this file: +# - jira.url +# - jira.project +# - linear.url +# - linear.api-key +# - github.org +# - github.repo diff --git a/.beads/interactions.jsonl b/.beads/interactions.jsonl new file mode 100644 index 00000000..e69de29b diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl new file mode 100644 index 00000000..e69de29b diff --git a/.beads/metadata.json b/.beads/metadata.json new file mode 100644 index 00000000..c787975e --- /dev/null +++ b/.beads/metadata.json @@ -0,0 +1,4 @@ +{ + "database": "beads.db", + "jsonl_export": "issues.jsonl" +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..807d5983 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ + +# Use bd merge for beads JSONL files +.beads/issues.jsonl merge=beads diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..78c7c75e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,41 @@ +# Agent Instructions + +This project uses **bd** (beads) for issue tracking. Run `bd onboard` to get started. + +## Quick Reference + +```bash +bd ready # Find available work +bd show # View issue details +bd update --status in_progress # Claim work +bd close # Complete work +bd sync # Sync with git +``` + +## Landing the Plane (Session Completion) + +**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds. + +**MANDATORY WORKFLOW:** + +1. **File issues for remaining work** - Create issues for anything that needs follow-up +2. **Run quality gates** (if code changed) - Tests, linters, builds +3. **Update issue status** - Close finished work, update in-progress items +4. **PUSH TO REMOTE** - This is MANDATORY: + ```bash + git pull --rebase + bd sync + git push + git status # MUST show "up to date with origin" + ``` +5. **Clean up** - Clear stashes, prune remote branches +6. **Verify** - All changes committed AND pushed +7. **Hand off** - Provide context for next session + +**CRITICAL RULES:** +- Work is NOT complete until `git push` succeeds +- NEVER stop before pushing - that leaves work stranded locally +- NEVER say "ready to push when you are" - YOU must push +- If push fails, resolve and retry until it succeeds + +Use 'bd' for task tracking From 8899c643edbaa2f4bd43bc24052963e953c7a4e3 Mon Sep 17 00:00:00 2001 From: Bryce Date: Sun, 8 Feb 2026 09:31:26 -0800 Subject: [PATCH 3/7] Complete code review session - documented findings for auto_ap.permissions, iol-ion.query, and auto_ap.ss.admin.background-jobs --- .beads/issues.jsonl | 64 +++++++++ .claude/skills/clojure-eval/SKILL.md | 174 ++++++++++++++++++++++++ .claude/skills/clojure-eval/examples.md | 82 +++++++++++ AGENTS.md | 13 ++ 4 files changed, 333 insertions(+) create mode 100644 .claude/skills/clojure-eval/SKILL.md create mode 100644 .claude/skills/clojure-eval/examples.md diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index e69de29b..0f64cf33 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -0,0 +1,64 @@ +{"id":"integreat-00t","title":"Security: Input validation and sanitization in import functions","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.0129384-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:28.0129384-08:00"} +{"id":"integreat-01o","title":"Security: Remove hardcoded API keys in insight_outcome_recommendation","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:46.141653019-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:46.141653019-08:00"} +{"id":"integreat-08c","title":"Performance: Fix N+1 query problem in sales_summaries","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:47.102267818-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:47.102267818-08:00"} +{"id":"integreat-0ic","title":"Clientize sales summaries and add schema cleanup","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:43.768991121-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:43.768991121-08:00"} +{"id":"integreat-0tf","title":"Security: Remove hardcoded cookie secret","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:54.956951237-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:54.956951237-08:00"} +{"id":"integreat-0z7","title":"Complete test coverage for transactions and invoice functionality","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:54.738460045-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:54.738460045-08:00"} +{"id":"integreat-104","title":"Code Review: auto_ap.permissions","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:58.102943422-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:00.915797483-08:00","closed_at":"2026-02-08T09:30:00.915797483-08:00","close_reason":"Closed"} +{"id":"integreat-1b8","title":"Code Review: auto_ap.ledger","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:58.457434281-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:52.517437805-08:00","closed_at":"2026-02-08T09:30:52.517437805-08:00","close_reason":"Closed"} +{"id":"integreat-1ex","title":"Security: Implement rate limiting","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:55.32191677-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:55.32191677-08:00"} +{"id":"integreat-1ff","title":"Code Review: iol_ion","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:59.195722157-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:30.631572319-08:00","closed_at":"2026-02-08T09:30:30.631572319-08:00","close_reason":"Closed"} +{"id":"integreat-1ht","title":"Security: Add input validation and sanitization","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:55.707181622-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:55.707181622-08:00"} +{"id":"integreat-1m3","title":"Security: Remove hardcoded JWT secrets","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:54.57377807-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:54.57377807-08:00"} +{"id":"integreat-1qy","title":"Code Review: auto_ap.routes","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:55.26442193-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:55.26442193-08:00"} +{"id":"integreat-278","title":"Security: Remove hardcoded Google credentials in auth.clj","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:19.491341584-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:19.491341584-08:00"} +{"id":"integreat-35k","title":"Fix session handling and authentication route issues","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:50.662486708-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:50.662486708-08:00"} +{"id":"integreat-3a7","title":"Refactor clients module for better reusability, schemas, and bug fixes","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:44.681764032-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:44.681764032-08:00"} +{"id":"integreat-3cp","title":"Code Review: auto_ap.import","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.573843708-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:54.573843708-08:00"} +{"id":"integreat-3pr","title":"Code Review: auto_ap.ss_routes","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.020989213-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:57.020989213-08:00"} +{"id":"integreat-46f","title":"Security: Rate limiting for external API calls","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.429193916-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:28.429193916-08:00"} +{"id":"integreat-4ag","title":"Code Review: iol-ion.query - Security and Code Quality Issues","description":"Code review of /home/noti/dev/integreat/iol_ion/src/iol_ion/query.clj revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- **Regex Injection Vulnerability** (line 67-68): User input passed directly to regex compilation without sanitization, enabling ReDoS attacks\\n- **No input validation on date parameters** (lines 25-30, 46-54, 83-162): Invalid dates could cause Denial of Service attacks\\n- **No validation of client IDs** (lines 46-54, 83-162): Malicious client IDs could bypass access controls\\n- **Unsafe timezone handling** (line 70-75): Hardcoded timezone without validation or fallback could cause failures\\n- **Permission checking lacks validation** (lines 59-64): Assumes identity structure without validation\\n\\n## Code Quality Issues:\\n- **Extreme code duplication** (lines 83-162): 8 scan functions with identical structure except for index names and entity types\\n- **Obsolete function** (lines 7-9): marked as \"not working in Datomic Cloud\" but still used\\n- **Magic numbers** (lines 25-30, 86-89): Hardcoded years (2001-2030) and days (90) should be configuration\\n- **Inconsistent client handling**: Mixed use of vs direct client IDs\\n\\n## Performance Issues:\\n- **Inefficient database queries** (lines 83-162): Sequential scans in for-loops instead of bulk operations\\n- **Repeated timezone conversions**: Each call to local-now converts to same timezone unnecessarily\\n\\n## Recommendations:\\n1. Add input validation for all user-supplied parameters\\n2. Create a utility function to handle regex compilation safely\\n3. Extract common scan logic into a single reusable function\\n4. Replace deprecated entid function or remove its usage\\n5. Move magic numbers to configuration constants\\n6. Optimize database queries with bulk operations\\n7. Add proper error handling and validation for all functions","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:53.593616294-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:59.771987594-08:00"} +{"id":"integreat-4mc","title":"Clean up legacy code and remove commented out templates","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:48.479644441-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:48.479644441-08:00"} +{"id":"integreat-54l","title":"Code Review: auto_ap.background","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:58.809902284-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:31:14.526449134-08:00","closed_at":"2026-02-08T09:31:14.526449134-08:00","close_reason":"Closed"} +{"id":"integreat-59c","title":"Security: Fix SQL injection vulnerability in exports.clj","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:19.959391674-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:19.959391674-08:00"} +{"id":"integreat-5a1","title":"Concurrency: Fix thread safety issues in sysco.clj","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:48.485672868-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:48.485672868-08:00"} +{"id":"integreat-6cf","title":"Implement autopay and unpaid API unification","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:49.217286047-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:49.217286047-08:00"} +{"id":"integreat-74f","title":"Security: Transaction validation and data integrity","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:29.251711914-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:29.251711914-08:00"} +{"id":"integreat-7cx","title":"Code Review: auto_ap.shared_views","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.754073898-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:57.754073898-08:00"} +{"id":"integreat-7de","title":"Security: Database connection management in imports","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:27.574962301-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:27.574962301-08:00"} +{"id":"integreat-7en","title":"Code Review: auto_ap.ss.admin.background-jobs - Security and Code Quality Issues","description":"Code review of /home/noti/dev/integreat/src/clj/auto_ap/ssr/admin/background_jobs.clj revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- **No job name validation** (lines 53-58): Job names used to construct task ARNs without validation, enabling injection attacks\\n- **Hardcoded network configuration** (lines 150-52): Subnets and security groups hardcoded with direct IPs\\n- **Hardcoded security group IDs** (lines 151-52): Security credentials directly embedded in code\\n- **No rate limiting** (lines 56-61): Job execution lacks rate limiting, enabling DoS attacks\\n- **Fragile job name sanitization** (lines 161-62): Regex replacement approach is insecure\\n- **No URL validation** (lines 74, 84-86): S3 URLs not validated before use\\n\\n## Code Quality Issues:\\n- **Poor error handling** (lines 30-37): AWS API errors not handled, could crash page\\n- **Code duplication** (lines 46-52, 53-58): and have identical logic\\n- **Magic strings** (lines 33-42, 224-42): Job names hardcoded in select options and processing\\n- **Inconsistent error handling**: Mixed approach to form errors and API errors\\n\\n## Performance Issues:\\n- **Inefficient task querying** (lines 30-37): Two separate AWS API calls instead of one\\n- **Nested AWS calls** (lines 35-36): Multiple nested API calls increase complexity\\n- **No caching**: Repeated API calls to without memoization\\n\\n## Recommendations:\\n1. Add input validation for all user-supplied parameters\\n2. Extract hardcoded configuration to environment variables or config files\\n3. Implement rate limiting on job execution\\n4. Use secure sanitization for job names\\n5. Add proper error handling for AWS API calls\\n6. Remove code duplication by extracting common logic\\n7. Optimize AWS API calls and add caching where appropriate\\n8. Validate S3 URLs before use","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:31:15.621682311-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:31:22.196700831-08:00"} +{"id":"integreat-8jt","title":"Performance: Fix potential memory leak in client hydration","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:56.135939778-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:56.135939778-08:00"} +{"id":"integreat-8p7","title":"Code Review: auto_ap.client_routes","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.389725276-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:57.389725276-08:00"} +{"id":"integreat-9o2","title":"Code Review: auto_ap.ss","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:56.653394004-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:56.653394004-08:00"} +{"id":"integreat-adj","title":"Performance: Fix CSV writing efficiency in exports.clj","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:21.877285694-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:21.877285694-08:00"} +{"id":"integreat-ae3","title":"Investigate iol-ion module and security review requirements","description":"iol-ion appears to be an external or internal module that provides query functions used throughout the codebase:\\n\\nFunctions used:\\n- iol-ion.query/ident (line 98 in transaction_rules.clj)\\n- iol-ion.query/recent-date (line 317 in transaction_rules.clj)\\n- iol-ion.query/-\u003epattern (lines 323, 541 in transaction_rules.clj)\\n- iol-ion.query/dom (lines 361, 368 in transaction_rules.clj)\\n\\nNeeds investigation:\\n1. Is iol-ion a third-party library or internal module?\\n2. What security concerns exist in its usage?\\n3. Is there proper input validation in its functions?\\n4. Are there any potential injection vulnerabilities?\\n5. What are the dependencies and version requirements?\\n\\nSearch in:\\n- project.clj or deps.edn for dependencies\\n- src directory for module definition\\n- Documentation or README files","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:31.587996635-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:34.841745089-08:00"} +{"id":"integreat-aut","title":"Fix payment query parameter parsing and implement proper decoding","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:46.65410618-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:46.65410618-08:00"} +{"id":"integreat-bct","title":"Complete IOL integration with Datomic Cloud","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:51.056089489-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:51.056089489-08:00"} +{"id":"integreat-d8q","title":"Code Review: auto_ap.main","status":"in_progress","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.224210511-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:51.465831393-08:00"} +{"id":"integreat-dsb","title":"Performance: External API calls should be asynchronous","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:29.66389647-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:29.66389647-08:00"} +{"id":"integreat-edg","title":"Fix grid page helper issues and form bubbling problems","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:45.844140503-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:45.844140503-08:00"} +{"id":"integreat-g4b","title":"Complete wizard implementation and make it more modular","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:52.493115251-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:52.493115251-08:00"} +{"id":"integreat-gf0","title":"Performance: Fix memory leak in client cache","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.846092823-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:28.846092823-08:00"} +{"id":"integreat-ifw","title":"Add Plaid merchant integration and improve vendors module","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:45.076207245-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:45.076207245-08:00"} +{"id":"integreat-lov","title":"Security: Add input validation to all routes","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:21.423853589-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:21.423853589-08:00"} +{"id":"integreat-mt4","title":"Code Review: auto_ap.jobs","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.921445539-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:54.921445539-08:00"} +{"id":"integreat-mxf","title":"Security: Fix error information leakage","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:56.506580155-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:56.506580155-08:00"} +{"id":"integreat-opb","title":"Security: Fix SQL injection risk in close_auto_invoices","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:47.576841414-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:47.576841414-08:00"} +{"id":"integreat-oyo","title":"Componentize transaction rules and improve form handling","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:45.44170363-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:45.44170363-08:00"} +{"id":"integreat-pc1","title":"Complete real user testing for invoices and add credit from balance support","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:46.269009169-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:46.269009169-08:00"} +{"id":"integreat-qj2","title":"Improve component structure and implement better error handling","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:52.132393487-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:52.132393487-08:00"} +{"id":"integreat-rlj","title":"Complete wizard step structure and modularize page components","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:53.993488192-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:53.993488192-08:00"} +{"id":"integreat-s53","title":"Security: Remove hardcoded NTG API key in exports.clj","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:20.457790327-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:20.457790327-08:00"} +{"id":"integreat-s5h","title":"Resource: Fix resource leaks in import_uploaded_invoices","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:48.026329699-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:48.026329699-08:00"} +{"id":"integreat-syf","title":"Code Review: auto_ap.graphql","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:55.620533412-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:55.620533412-08:00"} +{"id":"integreat-uc3","title":"Security: Input sanitization and validation in job functions","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:46.60155898-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:46.60155898-08:00"} +{"id":"integreat-vk3","title":"Add feature flags system and signature support","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:51.419253869-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:51.419253869-08:00"} +{"id":"integreat-vkf","title":"Improve form handling and remove unused code","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:49.592681075-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:49.592681075-08:00"} +{"id":"integreat-vvk","title":"Performance: Fix N+1 query problems in exports.clj","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:20.96494325-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:20.96494325-08:00"} +{"id":"integreat-w1i","title":"Improve input components and data grid implementations","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:47.721945968-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:47.721945968-08:00"} +{"id":"integreat-y3e","title":"Improve typeahead component and implement proper query handling","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:53.602661377-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:53.602661377-08:00"} +{"id":"integreat-y72","title":"Enhance ledger reports and improve navigation/aside components","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:48.101954827-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:48.101954827-08:00"} +{"id":"integreat-yq9","title":"Remove deprecated code and clean up unused functions","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:54.367393577-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:54.367393577-08:00"} +{"id":"integreat-zly","title":"Code Review: auto_ap.permissions - Security and Maintainability Issues","description":"Code review of /home/noti/dev/integreat/src/cljc/auto_ap/permissions.cljc revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- Client access control bypass: Non-admins completely blocked if client-id is nil (lines 22-24)\\n- No input validation: Client IDs and user data not validated (lines 10-11, 17)\\n- Trust-based user object: No schema validation for user data\\n\\n## Maintainability Issues:\\n- Extreme code duplication: Permission logic repeated 4 times across different role checks (lines 26-141)\\n- Magic strings: Inconsistent role representation (mixing keywords and strings)\\n- Hardcoded permissions: No separation from business logic\\n- No unit tests: No test coverage for permission checks\\n\\n## Performance Issues:\\n- Redundant set creation on every call (lines 22-23)\\n- Repeated condition checks for each role\\n\\n## Recommendations:\\n1. Implement schema validation for user data using malli\\n2. Extract permissions to data structure following DRY principle\\n3. Add client-id validation with pos-int?\\n4. Add unit tests for all permission sets\\n5. Move set creation outside function or add short-circuit for admin role\\n\\nSee full review for detailed analysis and refactoring suggestions.","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:01.992071212-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:05.576405896-08:00"} +{"id":"integreat-zn0","title":"Implement cash drawer shift functionality","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:51.76190647-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:51.76190647-08:00"} +{"id":"integreat-zt8","title":"Complete invoice totals implementation to include expense accounts","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:48.848572114-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:48.848572114-08:00"} diff --git a/.claude/skills/clojure-eval/SKILL.md b/.claude/skills/clojure-eval/SKILL.md new file mode 100644 index 00000000..36d58650 --- /dev/null +++ b/.claude/skills/clojure-eval/SKILL.md @@ -0,0 +1,174 @@ +--- +name: clojure-eval +description: Evaluate Clojure code via nREPL using clj-nrepl-eval. Use this when you need to test code, check if edited files compile, verify function behavior, or interact with a running REPL session. +--- + +# Clojure REPL Evaluation + +## When to Use This Skill + +Use this skill when you need to: +- **Verify that edited Clojure files compile and load correctly** +- Test function behavior interactively +- Check the current state of the REPL +- Debug code by evaluating expressions +- Require or load namespaces for testing +- Validate that code changes work before committing + +## How It Works + +The `clj-nrepl-eval` command evaluates Clojure code against an nREPL server. **Session state persists between evaluations**, so you can require a namespace in one evaluation and use it in subsequent calls. Each host:port combination maintains its own session file. + +## Instructions + +### 0. Discover and select nREPL server + +First, discover what nREPL servers are running in the current directory: + +```bash +clj-nrepl-eval --discover-ports +``` + +This will show all nREPL servers (Clojure, Babashka, shadow-cljs, etc.) running in the current project directory. + +**Then use the AskUserQuestion tool:** + +- **If ports are discovered:** Prompt user to select which nREPL port to use: + - **question:** "Which nREPL port would you like to use?" + - **header:** "nREPL Port" + - **options:** Present each discovered port as an option with: + - **label:** The port number + - **description:** The server type and status (e.g., "Clojure nREPL server in current directory") + - Include up to 4 discovered ports as options + - The user can select "Other" to enter a custom port number + +- **If no ports are discovered:** Prompt user how to start an nREPL server: + - **question:** "No nREPL servers found. How would you like to start one?" + - **header:** "Start nREPL" + - **options:** + - **label:** "deps.edn alias", **description:** "Find and use an nREPL alias in deps.edn" + - **label:** "Leiningen", **description:** "Start nREPL using 'lein repl'" + - The user can select "Other" for alternative methods or if they already have a server running on a specific port + +IMPORTANT: IF you start a REPL do not supply a port let the nREPL start and return the port that it was started on. + +### 1. Evaluate Clojure Code + +> Evaluation automatically connects to the given port + +Use the `-p` flag to specify the port and pass your Clojure code. + +**Recommended: Pass code as a command-line argument:** +```bash +clj-nrepl-eval -p "(+ 1 2 3)" +``` + +**For multiple expressions (single line):** +```bash +clj-nrepl-eval -p "(def x 10) (+ x 20)" +``` + +**Alternative: Using heredoc (may require permission approval for multiline commands):** +```bash +clj-nrepl-eval -p <<'EOF' +(def x 10) +(+ x 20) +EOF +``` + +**Alternative: Via stdin pipe:** +```bash +echo "(+ 1 2 3)" | clj-nrepl-eval -p +``` + +### 2. Display nREPL Sessions + +**Discover all nREPL servers in current directory:** +```bash +clj-nrepl-eval --discover-ports +``` +Shows all running nREPL servers in the current project directory, including their type (clj/bb/basilisp) and whether they match the current working directory. + +**Check previously connected sessions:** +```bash +clj-nrepl-eval --connected-ports +``` +Shows only connections you have made before (appears after first evaluation on a port). + +### 3. Common Patterns + +**Require a namespace (always use :reload to pick up changes):** +```bash +clj-nrepl-eval -p "(require '[my.namespace :as ns] :reload)" +``` + +**Test a function after requiring:** +```bash +clj-nrepl-eval -p "(ns/my-function arg1 arg2)" +``` + +**Check if a file compiles:** +```bash +clj-nrepl-eval -p "(require 'my.namespace :reload)" +``` + +**Multiple expressions:** +```bash +clj-nrepl-eval -p "(def x 10) (* x 2) (+ x 5)" +``` + +**Complex multiline code (using heredoc):** +```bash +clj-nrepl-eval -p <<'EOF' +(def x 10) +(* x 2) +(+ x 5) +EOF +``` +*Note: Heredoc syntax may require permission approval.* + +**With custom timeout (in milliseconds):** +```bash +clj-nrepl-eval -p --timeout 5000 "(long-running-fn)" +``` + +**Reset the session (clears all state):** +```bash +clj-nrepl-eval -p --reset-session +clj-nrepl-eval -p --reset-session "(def x 1)" +``` + +## Available Options + +- `-p, --port PORT` - nREPL port (required) +- `-H, --host HOST` - nREPL host (default: 127.0.0.1) +- `-t, --timeout MILLISECONDS` - Timeout (default: 120000 = 2 minutes) +- `-r, --reset-session` - Reset the persistent nREPL session +- `-c, --connected-ports` - List previously connected nREPL sessions +- `-d, --discover-ports` - Discover nREPL servers in current directory +- `-h, --help` - Show help message + +## Important Notes + +- **Prefer command-line arguments:** Pass code as quoted strings: `clj-nrepl-eval -p "(+ 1 2 3)"` - works with existing permissions +- **Heredoc for complex code:** Use heredoc (`<<'EOF' ... EOF`) for truly multiline code, but note it may require permission approval +- **Sessions persist:** State (vars, namespaces, loaded libraries) persists across invocations until the nREPL server restarts or `--reset-session` is used +- **Automatic delimiter repair:** The tool automatically repairs missing or mismatched parentheses +- **Always use :reload:** When requiring namespaces, use `:reload` to pick up recent changes +- **Default timeout:** 2 minutes (120000ms) - increase for long-running operations +- **Input precedence:** Command-line arguments take precedence over stdin + +## Typical Workflow + +1. Discover nREPL servers: `clj-nrepl-eval --discover-ports` +2. Use **AskUserQuestion** tool to prompt user to select a port +3. Require namespace: + ```bash + clj-nrepl-eval -p "(require '[my.ns :as ns] :reload)" + ``` +4. Test function: + ```bash + clj-nrepl-eval -p "(ns/my-fn ...)" + ``` +5. Iterate: Make changes, re-require with `:reload`, test again + diff --git a/.claude/skills/clojure-eval/examples.md b/.claude/skills/clojure-eval/examples.md new file mode 100644 index 00000000..003b5aeb --- /dev/null +++ b/.claude/skills/clojure-eval/examples.md @@ -0,0 +1,82 @@ +# clj-nrepl-eval Examples + +## Discovery + +```bash +clj-nrepl-eval --connected-ports +``` + +## Heredoc for Multiline Code + +```bash +clj-nrepl-eval -p 7888 <<'EOF' +(defn greet [name] + (str "Hello, " name "!")) + +(greet "Claude") +EOF +``` + +### Heredoc Simplifies String Escaping + +Heredoc avoids shell escaping issues with quotes, backslashes, and special characters: + +```bash +# With heredoc - no escaping needed +clj-nrepl-eval -p 7888 <<'EOF' +(def regex #"\\d{3}-\\d{4}") +(def message "She said \"Hello!\" and waved") +(def path "C:\\Users\\name\\file.txt") +(println message) +EOF + +# Without heredoc - requires complex escaping +clj-nrepl-eval -p 7888 "(def message \"She said \\\"Hello!\\\" and waved\")" +``` + +## Working with Project Namespaces + +```bash +# Test a function after requiring +clj-nrepl-eval -p 7888 <<'EOF' +(require '[clojure-mcp-light.delimiter-repair :as dr] :reload) +(dr/delimiter-error? "(defn foo [x]") +EOF +``` + +## Verify Compilation After Edit + +```bash +# If this returns nil, the file compiled successfully +clj-nrepl-eval -p 7888 "(require 'clojure-mcp-light.hook :reload)" +``` + +## Session Management + +```bash +# Reset session if state becomes corrupted +clj-nrepl-eval -p 7888 --reset-session +``` + +## Common Workflow Patterns + +### Load, Test, Iterate + +```bash +# After editing a file, reload and test in one command +clj-nrepl-eval -p 7888 <<'EOF' +(require '[my.namespace :as ns] :reload) +(ns/my-function test-data) +EOF +``` + +### Run Tests After Changes + +```bash +clj-nrepl-eval -p 7888 <<'EOF' +(require '[my.project.core :as core] :reload) +(require '[my.project.core-test :as test] :reload) +(clojure.test/run-tests 'my.project.core-test) +EOF +``` + diff --git a/AGENTS.md b/AGENTS.md index 78c7c75e..3dec65dd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,6 +2,19 @@ This project uses **bd** (beads) for issue tracking. Run `bd onboard` to get started. +## Issue Tracking + +This project uses **bd (beads)** for issue tracking. +Run `bd prime` for workflow context, or install hooks (`bd hooks install`) for auto-injection. + +**Quick reference:** +- `bd ready` - Find unblocked work +- `bd create "Title" --type task --priority 2` - Create issue +- `bd close ` - Complete work +- `bd sync` - Sync with git (run at session end) + +For full workflow details: `bd prime` + ## Quick Reference ```bash From 53625e458314a7cd8ebc57317a2a8c364b78954a Mon Sep 17 00:00:00 2001 From: Bryce Date: Sat, 21 Feb 2026 22:53:05 -0800 Subject: [PATCH 4/7] Makes invoices use the closed_at date. --- .beads/issues.jsonl | 67 ++++++++++++++++++-------------- src/clj/auto_ap/square/core3.clj | 66 +++++++++++++++++-------------- 2 files changed, 75 insertions(+), 58 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 0f64cf33..68609603 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,64 +1,73 @@ -{"id":"integreat-00t","title":"Security: Input validation and sanitization in import functions","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.0129384-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:28.0129384-08:00"} -{"id":"integreat-01o","title":"Security: Remove hardcoded API keys in insight_outcome_recommendation","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:46.141653019-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:46.141653019-08:00"} -{"id":"integreat-08c","title":"Performance: Fix N+1 query problem in sales_summaries","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:47.102267818-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:47.102267818-08:00"} +{"id":"integreat-00t","title":"Security: Input validation and sanitization in import functions","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.0129384-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:33:06.050946022-08:00","closed_at":"2026-02-08T13:33:06.050946022-08:00","close_reason":"Code review completed - import_uploaded_invoices.clj reviewed"} +{"id":"integreat-01o","title":"Security: Remove hardcoded API keys in insight_outcome_recommendation","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:46.141653019-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:31:42.926029101-08:00","closed_at":"2026-02-08T13:31:42.926029101-08:00","close_reason":"Code review completed - Hardcoded Pinecone API key found at lines 31, 48"} +{"id":"integreat-08c","title":"Performance: Fix N+1 query problem in sales_summaries","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:47.102267818-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:31:42.899786826-08:00","closed_at":"2026-02-08T13:31:42.899786826-08:00","close_reason":"Code review completed - N+1 queries identified throughout sales_summaries.clj"} +{"id":"integreat-0df","title":"Code review: auto_ap.ssr.admin.transaction_rules","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:26:21.41732477-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:26:50.545369921-08:00","closed_at":"2026-02-08T13:26:50.545369921-08:00","close_reason":"Closed"} {"id":"integreat-0ic","title":"Clientize sales summaries and add schema cleanup","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:43.768991121-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:43.768991121-08:00"} -{"id":"integreat-0tf","title":"Security: Remove hardcoded cookie secret","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:54.956951237-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:54.956951237-08:00"} +{"id":"integreat-0kl","title":"Code review: auto_ap.ssr.admin.import_batch","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:25:10.532871346-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:25:29.784001757-08:00","closed_at":"2026-02-08T13:25:29.784001757-08:00","close_reason":"Closed"} +{"id":"integreat-0tf","title":"Security: Remove hardcoded cookie secret","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:54.956951237-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.535163011-08:00","closed_at":"2026-02-08T13:34:04.535163011-08:00","close_reason":"Code review completed - Hardcoded cookie store key found at lines 447-448"} {"id":"integreat-0z7","title":"Complete test coverage for transactions and invoice functionality","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:54.738460045-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:54.738460045-08:00"} {"id":"integreat-104","title":"Code Review: auto_ap.permissions","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:58.102943422-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:00.915797483-08:00","closed_at":"2026-02-08T09:30:00.915797483-08:00","close_reason":"Closed"} {"id":"integreat-1b8","title":"Code Review: auto_ap.ledger","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:58.457434281-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:52.517437805-08:00","closed_at":"2026-02-08T09:30:52.517437805-08:00","close_reason":"Closed"} -{"id":"integreat-1ex","title":"Security: Implement rate limiting","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:55.32191677-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:55.32191677-08:00"} +{"id":"integreat-1ex","title":"Security: Implement rate limiting","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:55.32191677-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.585536605-08:00","closed_at":"2026-02-08T13:34:04.585536605-08:00","close_reason":"Code review completed - Rate limiting not implemented, recommendation added"} {"id":"integreat-1ff","title":"Code Review: iol_ion","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:59.195722157-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:30.631572319-08:00","closed_at":"2026-02-08T09:30:30.631572319-08:00","close_reason":"Closed"} -{"id":"integreat-1ht","title":"Security: Add input validation and sanitization","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:55.707181622-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:55.707181622-08:00"} -{"id":"integreat-1m3","title":"Security: Remove hardcoded JWT secrets","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:54.57377807-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:54.57377807-08:00"} -{"id":"integreat-1qy","title":"Code Review: auto_ap.routes","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:55.26442193-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:55.26442193-08:00"} -{"id":"integreat-278","title":"Security: Remove hardcoded Google credentials in auth.clj","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:19.491341584-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:19.491341584-08:00"} +{"id":"integreat-1ht","title":"Security: Add input validation and sanitization","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:55.707181622-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.560514104-08:00","closed_at":"2026-02-08T13:34:04.560514104-08:00","close_reason":"Code review completed - handler.clj reviewed, input validation issues identified"} +{"id":"integreat-1jz","title":"Code review: auto_ap.ssr.admin.excel_invoice","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:18:26.802261171-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:18:51.297567931-08:00","closed_at":"2026-02-08T13:18:51.297567931-08:00","close_reason":"Closed"} +{"id":"integreat-1m3","title":"Security: Remove hardcoded JWT secrets","status":"in_progress","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:54.57377807-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:35:21.465147919-08:00"} +{"id":"integreat-1oo","title":"Code review: auto_ap.ssr.admin.vendors","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:26:57.577293865-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:27:29.429533887-08:00","closed_at":"2026-02-08T13:27:29.429533887-08:00","close_reason":"Closed"} +{"id":"integreat-1qy","title":"Code Review: auto_ap.routes","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:55.26442193-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:55.026115465-08:00","closed_at":"2026-02-08T13:29:55.026115465-08:00","close_reason":"No file found for this namespace"} +{"id":"integreat-278","title":"Security: Remove hardcoded Google credentials in auth.clj","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:19.491341584-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:30:37.240560315-08:00","closed_at":"2026-02-08T13:30:37.240560315-08:00","close_reason":"Code review completed - JWT secret management reviewed"} +{"id":"integreat-2cd","title":"Code review: auto_ap.ssr.admin.sales_summaries","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:25:56.325342803-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:26:17.717894907-08:00","closed_at":"2026-02-08T13:26:17.717894907-08:00","close_reason":"Closed"} +{"id":"integreat-2ti","title":"Code review: auto_ap.ssr.admin.accounts","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T12:53:44.646685216-08:00","created_by":"Bryce","updated_at":"2026-02-08T12:55:55.094416105-08:00","closed_at":"2026-02-08T12:55:55.094416105-08:00","close_reason":"Closed"} {"id":"integreat-35k","title":"Fix session handling and authentication route issues","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:50.662486708-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:50.662486708-08:00"} {"id":"integreat-3a7","title":"Refactor clients module for better reusability, schemas, and bug fixes","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:44.681764032-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:44.681764032-08:00"} -{"id":"integreat-3cp","title":"Code Review: auto_ap.import","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.573843708-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:54.573843708-08:00"} -{"id":"integreat-3pr","title":"Code Review: auto_ap.ss_routes","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.020989213-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:57.020989213-08:00"} -{"id":"integreat-46f","title":"Security: Rate limiting for external API calls","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.429193916-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:28.429193916-08:00"} -{"id":"integreat-4ag","title":"Code Review: iol-ion.query - Security and Code Quality Issues","description":"Code review of /home/noti/dev/integreat/iol_ion/src/iol_ion/query.clj revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- **Regex Injection Vulnerability** (line 67-68): User input passed directly to regex compilation without sanitization, enabling ReDoS attacks\\n- **No input validation on date parameters** (lines 25-30, 46-54, 83-162): Invalid dates could cause Denial of Service attacks\\n- **No validation of client IDs** (lines 46-54, 83-162): Malicious client IDs could bypass access controls\\n- **Unsafe timezone handling** (line 70-75): Hardcoded timezone without validation or fallback could cause failures\\n- **Permission checking lacks validation** (lines 59-64): Assumes identity structure without validation\\n\\n## Code Quality Issues:\\n- **Extreme code duplication** (lines 83-162): 8 scan functions with identical structure except for index names and entity types\\n- **Obsolete function** (lines 7-9): marked as \"not working in Datomic Cloud\" but still used\\n- **Magic numbers** (lines 25-30, 86-89): Hardcoded years (2001-2030) and days (90) should be configuration\\n- **Inconsistent client handling**: Mixed use of vs direct client IDs\\n\\n## Performance Issues:\\n- **Inefficient database queries** (lines 83-162): Sequential scans in for-loops instead of bulk operations\\n- **Repeated timezone conversions**: Each call to local-now converts to same timezone unnecessarily\\n\\n## Recommendations:\\n1. Add input validation for all user-supplied parameters\\n2. Create a utility function to handle regex compilation safely\\n3. Extract common scan logic into a single reusable function\\n4. Replace deprecated entid function or remove its usage\\n5. Move magic numbers to configuration constants\\n6. Optimize database queries with bulk operations\\n7. Add proper error handling and validation for all functions","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:53.593616294-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:59.771987594-08:00"} +{"id":"integreat-3cp","title":"Code Review: auto_ap.import","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.573843708-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:55.090966459-08:00","closed_at":"2026-02-08T13:29:55.090966459-08:00","close_reason":"No file found for this namespace"} +{"id":"integreat-3pr","title":"Code Review: auto_ap.ss_routes","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.020989213-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:54.961399111-08:00","closed_at":"2026-02-08T13:29:54.961399111-08:00","close_reason":"No file found for this namespace"} +{"id":"integreat-3y8","title":"Code review: auto_ap.ssr.admin.clients","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:42:10.903791187-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:47:29.495083383-08:00","closed_at":"2026-02-08T09:47:29.495083383-08:00","close_reason":"Closed"} +{"id":"integreat-46f","title":"Security: Rate limiting for external API calls","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.429193916-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.63601665-08:00","closed_at":"2026-02-08T13:34:04.63601665-08:00","close_reason":"Code review completed - Rate limiting recommendations added"} +{"id":"integreat-4ag","title":"Code Review: iol-ion.query - Security and Code Quality Issues","description":"Code review of /home/noti/dev/integreat/iol_ion/src/iol_ion/query.clj revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- **Regex Injection Vulnerability** (line 67-68): User input passed directly to regex compilation without sanitization, enabling ReDoS attacks\\n- **No input validation on date parameters** (lines 25-30, 46-54, 83-162): Invalid dates could cause Denial of Service attacks\\n- **No validation of client IDs** (lines 46-54, 83-162): Malicious client IDs could bypass access controls\\n- **Unsafe timezone handling** (line 70-75): Hardcoded timezone without validation or fallback could cause failures\\n- **Permission checking lacks validation** (lines 59-64): Assumes identity structure without validation\\n\\n## Code Quality Issues:\\n- **Extreme code duplication** (lines 83-162): 8 scan functions with identical structure except for index names and entity types\\n- **Obsolete function** (lines 7-9): marked as \"not working in Datomic Cloud\" but still used\\n- **Magic numbers** (lines 25-30, 86-89): Hardcoded years (2001-2030) and days (90) should be configuration\\n- **Inconsistent client handling**: Mixed use of vs direct client IDs\\n\\n## Performance Issues:\\n- **Inefficient database queries** (lines 83-162): Sequential scans in for-loops instead of bulk operations\\n- **Repeated timezone conversions**: Each call to local-now converts to same timezone unnecessarily\\n\\n## Recommendations:\\n1. Add input validation for all user-supplied parameters\\n2. Create a utility function to handle regex compilation safely\\n3. Extract common scan logic into a single reusable function\\n4. Replace deprecated entid function or remove its usage\\n5. Move magic numbers to configuration constants\\n6. Optimize database queries with bulk operations\\n7. Add proper error handling and validation for all functions","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:53.593616294-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:28:52.035161365-08:00","closed_at":"2026-02-08T13:28:52.035161365-08:00","close_reason":"Closed"} {"id":"integreat-4mc","title":"Clean up legacy code and remove commented out templates","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:48.479644441-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:48.479644441-08:00"} {"id":"integreat-54l","title":"Code Review: auto_ap.background","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:58.809902284-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:31:14.526449134-08:00","closed_at":"2026-02-08T09:31:14.526449134-08:00","close_reason":"Closed"} -{"id":"integreat-59c","title":"Security: Fix SQL injection vulnerability in exports.clj","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:19.959391674-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:19.959391674-08:00"} +{"id":"integreat-59c","title":"Security: Fix SQL injection vulnerability in exports.clj","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:19.959391674-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:30:37.208340718-08:00","closed_at":"2026-02-08T13:30:37.208340718-08:00","close_reason":"Code review completed - SQL injection vulnerability found in export-raw function"} {"id":"integreat-5a1","title":"Concurrency: Fix thread safety issues in sysco.clj","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:48.485672868-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:48.485672868-08:00"} {"id":"integreat-6cf","title":"Implement autopay and unpaid API unification","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:49.217286047-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:49.217286047-08:00"} -{"id":"integreat-74f","title":"Security: Transaction validation and data integrity","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:29.251711914-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:29.251711914-08:00"} -{"id":"integreat-7cx","title":"Code Review: auto_ap.shared_views","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.754073898-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:57.754073898-08:00"} -{"id":"integreat-7de","title":"Security: Database connection management in imports","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:27.574962301-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:27.574962301-08:00"} -{"id":"integreat-7en","title":"Code Review: auto_ap.ss.admin.background-jobs - Security and Code Quality Issues","description":"Code review of /home/noti/dev/integreat/src/clj/auto_ap/ssr/admin/background_jobs.clj revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- **No job name validation** (lines 53-58): Job names used to construct task ARNs without validation, enabling injection attacks\\n- **Hardcoded network configuration** (lines 150-52): Subnets and security groups hardcoded with direct IPs\\n- **Hardcoded security group IDs** (lines 151-52): Security credentials directly embedded in code\\n- **No rate limiting** (lines 56-61): Job execution lacks rate limiting, enabling DoS attacks\\n- **Fragile job name sanitization** (lines 161-62): Regex replacement approach is insecure\\n- **No URL validation** (lines 74, 84-86): S3 URLs not validated before use\\n\\n## Code Quality Issues:\\n- **Poor error handling** (lines 30-37): AWS API errors not handled, could crash page\\n- **Code duplication** (lines 46-52, 53-58): and have identical logic\\n- **Magic strings** (lines 33-42, 224-42): Job names hardcoded in select options and processing\\n- **Inconsistent error handling**: Mixed approach to form errors and API errors\\n\\n## Performance Issues:\\n- **Inefficient task querying** (lines 30-37): Two separate AWS API calls instead of one\\n- **Nested AWS calls** (lines 35-36): Multiple nested API calls increase complexity\\n- **No caching**: Repeated API calls to without memoization\\n\\n## Recommendations:\\n1. Add input validation for all user-supplied parameters\\n2. Extract hardcoded configuration to environment variables or config files\\n3. Implement rate limiting on job execution\\n4. Use secure sanitization for job names\\n5. Add proper error handling for AWS API calls\\n6. Remove code duplication by extracting common logic\\n7. Optimize AWS API calls and add caching where appropriate\\n8. Validate S3 URLs before use","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:31:15.621682311-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:31:22.196700831-08:00"} +{"id":"integreat-74f","title":"Security: Transaction validation and data integrity","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:29.251711914-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.611256589-08:00","closed_at":"2026-02-08T13:34:04.611256589-08:00","close_reason":"Code review completed - Transaction validation reviewed in multiple files"} +{"id":"integreat-7cx","title":"Code Review: auto_ap.shared_views","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.754073898-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:39.003484636-08:00","closed_at":"2026-02-08T13:29:39.003484636-08:00","close_reason":"Closed"} +{"id":"integreat-7de","title":"Security: Database connection management in imports","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:27.574962301-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:33:06.077037636-08:00","closed_at":"2026-02-08T13:33:06.077037636-08:00","close_reason":"Code review completed - No connection management issues found in import files"} +{"id":"integreat-7en","title":"Code Review: auto_ap.ss.admin.background-jobs - Security and Code Quality Issues","description":"Code review of /home/noti/dev/integreat/src/clj/auto_ap/ssr/admin/background_jobs.clj revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- **No job name validation** (lines 53-58): Job names used to construct task ARNs without validation, enabling injection attacks\\n- **Hardcoded network configuration** (lines 150-52): Subnets and security groups hardcoded with direct IPs\\n- **Hardcoded security group IDs** (lines 151-52): Security credentials directly embedded in code\\n- **No rate limiting** (lines 56-61): Job execution lacks rate limiting, enabling DoS attacks\\n- **Fragile job name sanitization** (lines 161-62): Regex replacement approach is insecure\\n- **No URL validation** (lines 74, 84-86): S3 URLs not validated before use\\n\\n## Code Quality Issues:\\n- **Poor error handling** (lines 30-37): AWS API errors not handled, could crash page\\n- **Code duplication** (lines 46-52, 53-58): and have identical logic\\n- **Magic strings** (lines 33-42, 224-42): Job names hardcoded in select options and processing\\n- **Inconsistent error handling**: Mixed approach to form errors and API errors\\n\\n## Performance Issues:\\n- **Inefficient task querying** (lines 30-37): Two separate AWS API calls instead of one\\n- **Nested AWS calls** (lines 35-36): Multiple nested API calls increase complexity\\n- **No caching**: Repeated API calls to without memoization\\n\\n## Recommendations:\\n1. Add input validation for all user-supplied parameters\\n2. Extract hardcoded configuration to environment variables or config files\\n3. Implement rate limiting on job execution\\n4. Use secure sanitization for job names\\n5. Add proper error handling for AWS API calls\\n6. Remove code duplication by extracting common logic\\n7. Optimize AWS API calls and add caching where appropriate\\n8. Validate S3 URLs before use","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:31:15.621682311-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:18:06.425132957-08:00","closed_at":"2026-02-08T13:18:06.425132957-08:00","close_reason":"Closed"} {"id":"integreat-8jt","title":"Performance: Fix potential memory leak in client hydration","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:56.135939778-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:56.135939778-08:00"} -{"id":"integreat-8p7","title":"Code Review: auto_ap.client_routes","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.389725276-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:57.389725276-08:00"} -{"id":"integreat-9o2","title":"Code Review: auto_ap.ss","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:56.653394004-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:56.653394004-08:00"} +{"id":"integreat-8p7","title":"Code Review: auto_ap.client_routes","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.389725276-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:13.440742845-08:00","closed_at":"2026-02-08T13:34:13.440742845-08:00","close_reason":"No file found for auto_ap.client_routes namespace"} +{"id":"integreat-9o2","title":"Code Review: auto_ap.ss","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:56.653394004-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:54.994180329-08:00","closed_at":"2026-02-08T13:29:54.994180329-08:00","close_reason":"No file found for this namespace"} {"id":"integreat-adj","title":"Performance: Fix CSV writing efficiency in exports.clj","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:21.877285694-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:21.877285694-08:00"} {"id":"integreat-ae3","title":"Investigate iol-ion module and security review requirements","description":"iol-ion appears to be an external or internal module that provides query functions used throughout the codebase:\\n\\nFunctions used:\\n- iol-ion.query/ident (line 98 in transaction_rules.clj)\\n- iol-ion.query/recent-date (line 317 in transaction_rules.clj)\\n- iol-ion.query/-\u003epattern (lines 323, 541 in transaction_rules.clj)\\n- iol-ion.query/dom (lines 361, 368 in transaction_rules.clj)\\n\\nNeeds investigation:\\n1. Is iol-ion a third-party library or internal module?\\n2. What security concerns exist in its usage?\\n3. Is there proper input validation in its functions?\\n4. Are there any potential injection vulnerabilities?\\n5. What are the dependencies and version requirements?\\n\\nSearch in:\\n- project.clj or deps.edn for dependencies\\n- src directory for module definition\\n- Documentation or README files","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:31.587996635-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:34.841745089-08:00"} {"id":"integreat-aut","title":"Fix payment query parameter parsing and implement proper decoding","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:46.65410618-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:46.65410618-08:00"} {"id":"integreat-bct","title":"Complete IOL integration with Datomic Cloud","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:51.056089489-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:51.056089489-08:00"} -{"id":"integreat-d8q","title":"Code Review: auto_ap.main","status":"in_progress","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.224210511-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:51.465831393-08:00"} +{"id":"integreat-d8q","title":"Code Review: auto_ap.main","notes":"Code review completed for auto_ap.views.main\n\n**Summary**: Found several issues ranging from performance to code quality.\n\n**High Priority**:\n- Inefficient key generation on line 90 using pr-str - causes unnecessary re-renders\n\n**Medium Priority**:\n- Permission check pattern duplication across 16 page methods\n- Insufficient nil handling for edge cases\n\n**Low Priority**:\n- Subscription frequency could be optimized\n- Growing page handler count suggests need for refactoring\n\n**Security**: All page routes properly check permissions - good security posture.\n\nFull detailed review saved to REVIEW_auto_ap.main.md","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.224210511-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:35:08.65588745-08:00","closed_at":"2026-02-08T09:35:08.65588745-08:00","close_reason":"Closed"} {"id":"integreat-dsb","title":"Performance: External API calls should be asynchronous","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:29.66389647-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:29.66389647-08:00"} {"id":"integreat-edg","title":"Fix grid page helper issues and form bubbling problems","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:45.844140503-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:45.844140503-08:00"} {"id":"integreat-g4b","title":"Complete wizard implementation and make it more modular","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:52.493115251-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:52.493115251-08:00"} {"id":"integreat-gf0","title":"Performance: Fix memory leak in client cache","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.846092823-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:28.846092823-08:00"} {"id":"integreat-ifw","title":"Add Plaid merchant integration and improve vendors module","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:45.076207245-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:45.076207245-08:00"} +{"id":"integreat-iut","title":"Code review: auto_ap.ssr.admin.history","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:22:16.782050468-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:22:40.135978155-08:00","closed_at":"2026-02-08T13:22:40.135978155-08:00","close_reason":"Closed"} {"id":"integreat-lov","title":"Security: Add input validation to all routes","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:21.423853589-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:21.423853589-08:00"} -{"id":"integreat-mt4","title":"Code Review: auto_ap.jobs","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.921445539-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:54.921445539-08:00"} +{"id":"integreat-mt4","title":"Code Review: auto_ap.jobs","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.921445539-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:55.058776633-08:00","closed_at":"2026-02-08T13:29:55.058776633-08:00","close_reason":"No file found for this namespace"} {"id":"integreat-mxf","title":"Security: Fix error information leakage","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:56.506580155-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:56.506580155-08:00"} -{"id":"integreat-opb","title":"Security: Fix SQL injection risk in close_auto_invoices","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:47.576841414-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:47.576841414-08:00"} +{"id":"integreat-opb","title":"Security: Fix SQL injection risk in close_auto_invoices","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:47.576841414-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:33:26.149329059-08:00","closed_at":"2026-02-08T13:33:26.149329059-08:00","close_reason":"Code review completed - No SQL injection risk found, queries properly parameterized"} {"id":"integreat-oyo","title":"Componentize transaction rules and improve form handling","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:45.44170363-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:45.44170363-08:00"} {"id":"integreat-pc1","title":"Complete real user testing for invoices and add credit from balance support","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:46.269009169-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:46.269009169-08:00"} {"id":"integreat-qj2","title":"Improve component structure and implement better error handling","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:52.132393487-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:52.132393487-08:00"} {"id":"integreat-rlj","title":"Complete wizard step structure and modularize page components","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:53.993488192-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:53.993488192-08:00"} -{"id":"integreat-s53","title":"Security: Remove hardcoded NTG API key in exports.clj","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:20.457790327-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:20.457790327-08:00"} -{"id":"integreat-s5h","title":"Resource: Fix resource leaks in import_uploaded_invoices","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:48.026329699-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:48.026329699-08:00"} -{"id":"integreat-syf","title":"Code Review: auto_ap.graphql","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:55.620533412-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:20:55.620533412-08:00"} -{"id":"integreat-uc3","title":"Security: Input sanitization and validation in job functions","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:46.60155898-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:46.60155898-08:00"} +{"id":"integreat-s53","title":"Security: Remove hardcoded NTG API key in exports.clj","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:20.457790327-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:30:37.176681233-08:00","closed_at":"2026-02-08T13:30:37.176681233-08:00","close_reason":"Code review completed - Hardcoded API key found at lines 659, 665"} +{"id":"integreat-s5h","title":"Resource: Fix resource leaks in import_uploaded_invoices","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:48.026329699-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:31:42.874323093-08:00","closed_at":"2026-02-08T13:31:42.874323093-08:00","close_reason":"Code review completed - Resource leaks identified in lines 43-76"} +{"id":"integreat-syf","title":"Code Review: auto_ap.graphql","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:55.620533412-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:39.033441719-08:00","closed_at":"2026-02-08T13:29:39.033441719-08:00","close_reason":"Closed"} +{"id":"integreat-uc3","title":"Security: Input sanitization and validation in job functions","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:46.60155898-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:31:42.951371743-08:00","closed_at":"2026-02-08T13:31:42.951371743-08:00","close_reason":"Code review completed - Job functions reviewed, input validation needed"} {"id":"integreat-vk3","title":"Add feature flags system and signature support","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:51.419253869-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:51.419253869-08:00"} {"id":"integreat-vkf","title":"Improve form handling and remove unused code","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:49.592681075-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:49.592681075-08:00"} -{"id":"integreat-vvk","title":"Performance: Fix N+1 query problems in exports.clj","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:20.96494325-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:20.96494325-08:00"} +{"id":"integreat-vvk","title":"Performance: Fix N+1 query problems in exports.clj","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:20.96494325-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:30:37.144024095-08:00","closed_at":"2026-02-08T13:30:37.144024095-08:00","close_reason":"Code review completed - N+1 queries identified in exports.clj"} {"id":"integreat-w1i","title":"Improve input components and data grid implementations","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:47.721945968-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:47.721945968-08:00"} {"id":"integreat-y3e","title":"Improve typeahead component and implement proper query handling","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:53.602661377-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:53.602661377-08:00"} {"id":"integreat-y72","title":"Enhance ledger reports and improve navigation/aside components","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:48.101954827-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:48.101954827-08:00"} {"id":"integreat-yq9","title":"Remove deprecated code and clean up unused functions","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:54.367393577-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:54.367393577-08:00"} -{"id":"integreat-zly","title":"Code Review: auto_ap.permissions - Security and Maintainability Issues","description":"Code review of /home/noti/dev/integreat/src/cljc/auto_ap/permissions.cljc revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- Client access control bypass: Non-admins completely blocked if client-id is nil (lines 22-24)\\n- No input validation: Client IDs and user data not validated (lines 10-11, 17)\\n- Trust-based user object: No schema validation for user data\\n\\n## Maintainability Issues:\\n- Extreme code duplication: Permission logic repeated 4 times across different role checks (lines 26-141)\\n- Magic strings: Inconsistent role representation (mixing keywords and strings)\\n- Hardcoded permissions: No separation from business logic\\n- No unit tests: No test coverage for permission checks\\n\\n## Performance Issues:\\n- Redundant set creation on every call (lines 22-23)\\n- Repeated condition checks for each role\\n\\n## Recommendations:\\n1. Implement schema validation for user data using malli\\n2. Extract permissions to data structure following DRY principle\\n3. Add client-id validation with pos-int?\\n4. Add unit tests for all permission sets\\n5. Move set creation outside function or add short-circuit for admin role\\n\\nSee full review for detailed analysis and refactoring suggestions.","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:01.992071212-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:05.576405896-08:00"} +{"id":"integreat-zly","title":"Code Review: auto_ap.permissions - Security and Maintainability Issues","description":"Code review of /home/noti/dev/integreat/src/cljc/auto_ap/permissions.cljc revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- Client access control bypass: Non-admins completely blocked if client-id is nil (lines 22-24)\\n- No input validation: Client IDs and user data not validated (lines 10-11, 17)\\n- Trust-based user object: No schema validation for user data\\n\\n## Maintainability Issues:\\n- Extreme code duplication: Permission logic repeated 4 times across different role checks (lines 26-141)\\n- Magic strings: Inconsistent role representation (mixing keywords and strings)\\n- Hardcoded permissions: No separation from business logic\\n- No unit tests: No test coverage for permission checks\\n\\n## Performance Issues:\\n- Redundant set creation on every call (lines 22-23)\\n- Repeated condition checks for each role\\n\\n## Recommendations:\\n1. Implement schema validation for user data using malli\\n2. Extract permissions to data structure following DRY principle\\n3. Add client-id validation with pos-int?\\n4. Add unit tests for all permission sets\\n5. Move set creation outside function or add short-circuit for admin role\\n\\nSee full review for detailed analysis and refactoring suggestions.","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:01.992071212-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:13.389737709-08:00","closed_at":"2026-02-08T13:34:13.389737709-08:00","close_reason":"No file found for auto_ap.permissions namespace"} {"id":"integreat-zn0","title":"Implement cash drawer shift functionality","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:51.76190647-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:51.76190647-08:00"} +{"id":"integreat-zp6","title":"Code review: auto_ap.ssr.admin.sales_powerqueries","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:25:33.754411978-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:25:52.806787427-08:00","closed_at":"2026-02-08T13:25:52.806787427-08:00","close_reason":"Closed"} {"id":"integreat-zt8","title":"Complete invoice totals implementation to include expense accounts","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:48.848572114-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:48.848572114-08:00"} diff --git a/src/clj/auto_ap/square/core3.clj b/src/clj/auto_ap/square/core3.clj index a0df0672..dee59bd0 100644 --- a/src/clj/auto_ap/square/core3.clj +++ b/src/clj/auto_ap/square/core3.clj @@ -349,7 +349,10 @@ (s/reduce conj []))] [(remove-nils #:sales-order - {:date (coerce/to-date (time/to-time-zone (coerce/to-date-time (:created_at order)) (time/time-zone-for-id "America/Los_Angeles"))) + {:date (if (= "Invoices" (:name (:source order))) + (when (:closed_at order) + (coerce/to-date (time/to-time-zone (coerce/to-date-time (:closed_at order)) (time/time-zone-for-id "America/Los_Angeles")))) + (coerce/to-date (time/to-time-zone (coerce/to-date-time (:created_at order)) (time/time-zone-for-id "America/Los_Angeles")))) :client (:db/id client) :location (:square-location/client-location location) :external-id (str "square/order/" (:client/code client) "-" (:square-location/client-location location) "-" (:id order)) @@ -379,6 +382,9 @@ ;; sometimes orders stay open in square. At least one payment ;; is needed to import, in order to avoid importing orders in-progress. (and + (if (= "Invoices" (:name (:source order))) + (boolean (:closed_at order)) + true) (or (> (count (:tenders order)) 0) (seq (:returns order))) (or (= #{} (set (map #(:status (:card_details %)) (:tenders order)))) @@ -972,13 +978,14 @@ :headers (client-base-headers client) :as :json}) :body))) -(->> - @(let [[c [l]] (get-square-client-and-location "NGGG")] + (->> + @(let [[c [l]] (get-square-client-and-location "NGGG")] - (search c l (time/plus (time/now)))) - (filter (fn [r] - (str/starts-with? (:created_at r) "2024-03-14")))) + (search c l (time/now) (time/plus (time/now) (time/days -1)))) + + (filter (fn [r] + (str/starts-with? (:created_at r) "2024-03-14")))) (def refs (->> @@ -995,35 +1002,35 @@ (map (fn [r] @(get-payment c (:payment_id r))) refs)) -(get-square-client-and-location "NGGB") + (get-square-client-and-location "NGGB") (def my-results (let [[c [l]] (get-square-client-and-location "NGFA")])) (clojure.data.csv/write-csv *out* - (for [c (get-square-clients) - l (:client/square-locations c) - :when (:square-location/client-location l) - bad-row (try (->> @(search c l (coerce/to-date-time #inst "2024-04-01T00:00:00-07:00") (coerce/to-date-time #inst "2024-04-15T23:59:00-07:00")) - (filter #(not (should-import-order? %))) - (map #(first (deref (order->sales-order c l %)))) - (filter (fn already-exists [o] - (when (:sales-order/external-id o) - (seq (dc/q '[:find ?i - :in $ ?ei - :where [?i :sales-order/external-id ?ei]] - (dc/db conn) - (:sales-order/external-id o))))))) - (catch Exception e - []))] - [(:client/code c) (atime/unparse-local (clj-time.coerce/to-date-time (:sales-order/date bad-row)) atime/normal-date) (:sales-order/total bad-row) (:sales-order/tax bad-row) (:sales-order/tip bad-row) (:db/id bad-row)]) - :separator \tab) + (for [c (get-square-clients) + l (:client/square-locations c) + :when (:square-location/client-location l) + bad-row (try (->> @(search c l (coerce/to-date-time #inst "2024-04-01T00:00:00-07:00") (coerce/to-date-time #inst "2024-04-15T23:59:00-07:00")) + (filter #(not (should-import-order? %))) + (map #(first (deref (order->sales-order c l %)))) + (filter (fn already-exists [o] + (when (:sales-order/external-id o) + (seq (dc/q '[:find ?i + :in $ ?ei + :where [?i :sales-order/external-id ?ei]] + (dc/db conn) + (:sales-order/external-id o))))))) + (catch Exception e + []))] + [(:client/code c) (atime/unparse-local (clj-time.coerce/to-date-time (:sales-order/date bad-row)) atime/normal-date) (:sales-order/total bad-row) (:sales-order/tax bad-row) (:sales-order/tip bad-row) (:db/id bad-row)]) + :separator \tab) ;; => - + (require 'auto-ap.time-reader) @@ -1035,7 +1042,7 @@ (def z @(search c l #clj-time/date-time "2025-02-23T00:00:00-08:00" - #clj-time/date-time "2025-02-28T00:00:00-08:00")) + #clj-time/date-time "2025-02-28T00:00:00-08:00")) (take 10 (map #(first (deref (order->sales-order c l %))) z))) @@ -1058,10 +1065,11 @@ #_(filter (comp #{"OTHER"} :type) (mapcat :tenders z)) - (let [[c [l]] (get-square-client-and-location "LFHH")] - (search c l (clj-time.coerce/from-date #inst "2025-02-28") (clj-time.coerce/from-date #inst "2025-03-01")) + @(let [[c [l]] (get-square-client-and-location "NGRY")] + #_(search c l (clj-time.coerce/from-date #inst "2025-02-28") (clj-time.coerce/from-date #inst "2025-03-01")) + + (order->sales-order c l (:order (get-order c l "KdvwntmfMNTKBu8NOocbxatOs18YY" ))) - (:order (get-order c l "CLjQqkzVfGa82o5hEFUrGtUGO6QZY" )) ) ) From 01347ff3f56a59ef2e22e92833704a7cfa6cc039 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 2 Mar 2026 22:53:53 -0800 Subject: [PATCH 5/7] fixes balance sheet --- src/clj/auto_ap/ssr/ledger/balance_sheet.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/auto_ap/ssr/ledger/balance_sheet.clj b/src/clj/auto_ap/ssr/ledger/balance_sheet.clj index 185faba3..adfc67e5 100644 --- a/src/clj/auto_ap/ssr/ledger/balance_sheet.clj +++ b/src/clj/auto_ap/ssr/ledger/balance_sheet.clj @@ -81,7 +81,7 @@ data (into [] (for [client-id client-ids d date - [client-id account-id location debits credits balance count] (iol-ion.query/detailed-account-snapshot (dc/db conn) client-id (coerce/to-date (time/plus d (time/days 1)))) + [client-id account-id location debits credits balance count] (iol-ion.query/detailed-account-snapshot (dc/db conn) client-id (coerce/to-date d)) :let [account ((or (lookup-account client-id) {}) account-id)]] {:client-id client-id :account-id account-id From 28a755e9a97f3d219409b23afcb1348468fa3732 Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 2 Mar 2026 23:20:14 -0800 Subject: [PATCH 6/7] fixes invoice date filtering --- src/clj/auto_ap/ssr/components/date_range.clj | 14 ++++++++++--- src/clj/auto_ap/ssr/invoices.clj | 20 +++++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/clj/auto_ap/ssr/components/date_range.clj b/src/clj/auto_ap/ssr/components/date_range.clj index ff1306f1..fe694c35 100644 --- a/src/clj/auto_ap/ssr/components/date_range.clj +++ b/src/clj/auto_ap/ssr/components/date_range.clj @@ -1,11 +1,13 @@ (ns auto-ap.ssr.components.date-range (:require [auto-ap.ssr.components :as com] + [auto-ap.ssr.components.buttons :as but] + [auto-ap.ssr.svg :as svg] [auto-ap.time :as atime] [clj-time.coerce :as c] [clj-time.core :as t] [clj-time.periodic :as per])) -(defn date-range-field [{:keys [value id]}] +(defn date-range-field [{:keys [value id apply-button?]}] [:div {:id id} (com/field {:label "Date Range"} [:div.space-y-4 @@ -21,11 +23,17 @@ (atime/unparse-local atime/normal-date)) :placeholder "Date" :size :small - :class "shrink"}) + :class "shrink date-filter-input"}) (com/date-input {:name "end-date" :value (some-> (:end value) (atime/unparse-local atime/normal-date)) :placeholder "Date" :size :small - :class "shrink"})]])]) + :class "shrink date-filter-input"}) + (when apply-button? + (but/button- {:color :secondary + :size :small + :type "button" + "x-on:click" "$dispatch('datesApplied')"} + "Apply"))]])]) diff --git a/src/clj/auto_ap/ssr/invoices.clj b/src/clj/auto_ap/ssr/invoices.clj index 92b95c15..4028ebe1 100644 --- a/src/clj/auto_ap/ssr/invoices.clj +++ b/src/clj/auto_ap/ssr/invoices.clj @@ -37,7 +37,7 @@ [auto-ap.ssr.invoice.common :refer [default-read]] [auto-ap.ssr.invoice.import :as invoice-import] [auto-ap.ssr.invoice.new-invoice-wizard :as new-invoice-wizard :refer [location-select*]] - [auto-ap.ssr.pos.common :refer [date-range-field*]] + [auto-ap.ssr.components.date-range :as dr] [auto-ap.ssr.svg :as svg] [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers assert-schema @@ -77,7 +77,7 @@ [:div {:id "exact-match-id-tag"}])) (defn filters [request] - [:form#invoice-filters {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms" + [:form#invoice-filters {"hx-trigger" "datesApplied, change delay:500ms from:.filter-trigger, keyup changed from:.hot-filter delay:1000ms" "hx-get" (bidi/path-for ssr-routes/only-routes ::route/table) "hx-target" "#entity-table" @@ -92,7 +92,8 @@ :url (bidi/path-for ssr-routes/only-routes :vendor-search) :value (:vendor (:query-params request)) :value-fn :db/id - :content-fn :vendor/name})) + :content-fn :vendor/name + :class "filter-trigger"})) (com/field {:label "Account"} (com/typeahead {:name "account" :id "account" @@ -100,8 +101,12 @@ :value (:account (:query-params request)) :value-fn :db/id :content-fn #(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read (:db/id %)) - (:db/id (:client request))))})) - (date-range-field* request) + (:db/id (:client request)))) + :class "filter-trigger"})) + (dr/date-range-field {:value {:start (:start-date (:query-params request)) + :end (:end-date (:query-params request))} + :id "date-range" + :apply-button? true}) (com/field {:label "Check #"} (com/text-input {:name "check-number" :id "check-number" @@ -486,7 +491,10 @@ :fetch-page fetch-page :oob-render (fn [request] - [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true) + [(assoc-in (dr/date-range-field {:value {:start (:start-date (:query-params request)) + :end (:end-date (:query-params request))} + :id "date-range" + :apply-button? true}) [1 :hx-swap-oob] true) (assoc-in (exact-match-id* request) [1 :hx-swap-oob] true)]) :query-schema query-schema :parse-query-params (fn [p] From 6e3a024f66ecec667681211e611f45319bdc9ffa Mon Sep 17 00:00:00 2001 From: Bryce Date: Mon, 30 Mar 2026 22:36:12 -0700 Subject: [PATCH 7/7] adds stuff for dough burger --- .beads/.gitignore | 46 ------------------ .beads/README.md | 81 -------------------------------- .beads/config.yaml | 67 -------------------------- .beads/interactions.jsonl | 0 .beads/issues.jsonl | 73 ---------------------------- .beads/metadata.json | 4 -- src/clj/auto_ap/square/core3.clj | 45 +++++++++++++++--- 7 files changed, 38 insertions(+), 278 deletions(-) delete mode 100644 .beads/.gitignore delete mode 100644 .beads/README.md delete mode 100644 .beads/config.yaml delete mode 100644 .beads/interactions.jsonl delete mode 100644 .beads/issues.jsonl delete mode 100644 .beads/metadata.json diff --git a/.beads/.gitignore b/.beads/.gitignore deleted file mode 100644 index 0acd8c61..00000000 --- a/.beads/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -# SQLite databases -*.db -*.db?* -*.db-journal -*.db-wal -*.db-shm - -# Daemon runtime files -daemon.lock -daemon.log -daemon.pid -bd.sock -sync-state.json -last-touched - -# Local version tracking (prevents upgrade notification spam after git ops) -.local_version - -# Legacy database files -db.sqlite -bd.db - -# Worktree redirect file (contains relative path to main repo's .beads/) -# Must not be committed as paths would be wrong in other clones -redirect - -# Merge artifacts (temporary files from 3-way merge) -beads.base.jsonl -beads.base.meta.json -beads.left.jsonl -beads.left.meta.json -beads.right.jsonl -beads.right.meta.json - -# Sync state (local-only, per-machine) -# These files are machine-specific and should not be shared across clones -.sync.lock -.jsonl.lock -sync_base.jsonl -export-state/ - -# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here. -# They would override fork protection in .git/info/exclude, allowing -# contributors to accidentally commit upstream issue databases. -# The JSONL files (issues.jsonl, interactions.jsonl) and config files -# are tracked by git by default since no pattern above ignores them. diff --git a/.beads/README.md b/.beads/README.md deleted file mode 100644 index 50f281f0..00000000 --- a/.beads/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Beads - AI-Native Issue Tracking - -Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code. - -## What is Beads? - -Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git. - -**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads) - -## Quick Start - -### Essential Commands - -```bash -# Create new issues -bd create "Add user authentication" - -# View all issues -bd list - -# View issue details -bd show - -# Update issue status -bd update --status in_progress -bd update --status done - -# Sync with git remote -bd sync -``` - -### Working with Issues - -Issues in Beads are: -- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code -- **AI-friendly**: CLI-first design works perfectly with AI coding agents -- **Branch-aware**: Issues can follow your branch workflow -- **Always in sync**: Auto-syncs with your commits - -## Why Beads? - -✨ **AI-Native Design** -- Built specifically for AI-assisted development workflows -- CLI-first interface works seamlessly with AI coding agents -- No context switching to web UIs - -🚀 **Developer Focused** -- Issues live in your repo, right next to your code -- Works offline, syncs when you push -- Fast, lightweight, and stays out of your way - -🔧 **Git Integration** -- Automatic sync with git commits -- Branch-aware issue tracking -- Intelligent JSONL merge resolution - -## Get Started with Beads - -Try Beads in your own projects: - -```bash -# Install Beads -curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash - -# Initialize in your repo -bd init - -# Create your first issue -bd create "Try out Beads" -``` - -## Learn More - -- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs) -- **Quick Start Guide**: Run `bd quickstart` -- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples) - ---- - -*Beads: Issue tracking that moves at the speed of thought* ⚡ diff --git a/.beads/config.yaml b/.beads/config.yaml deleted file mode 100644 index ff8bc921..00000000 --- a/.beads/config.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# Beads Configuration File -# This file configures default behavior for all bd commands in this repository -# All settings can also be set via environment variables (BD_* prefix) -# or overridden with command-line flags - -# Issue prefix for this repository (used by bd init) -# If not set, bd init will auto-detect from directory name -# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc. -# issue-prefix: "" - -# Use no-db mode: load from JSONL, no SQLite, write back after each command -# When true, bd will use .beads/issues.jsonl as the source of truth -# instead of SQLite database -# no-db: false - -# Disable daemon for RPC communication (forces direct database access) -# no-daemon: false - -# Disable auto-flush of database to JSONL after mutations -# no-auto-flush: false - -# Disable auto-import from JSONL when it's newer than database -# no-auto-import: false - -# Enable JSON output by default -# json: false - -# Default actor for audit trails (overridden by BD_ACTOR or --actor) -# actor: "" - -# Path to database (overridden by BEADS_DB or --db) -# db: "" - -# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON) -# auto-start-daemon: true - -# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE) -# flush-debounce: "5s" - -# Export events (audit trail) to .beads/events.jsonl on each flush/sync -# When enabled, new events are appended incrementally using a high-water mark. -# Use 'bd export --events' to trigger manually regardless of this setting. -# events-export: false - -# Git branch for beads commits (bd sync will commit to this branch) -# IMPORTANT: Set this for team projects so all clones use the same sync branch. -# This setting persists across clones (unlike database config which is gitignored). -# Can also use BEADS_SYNC_BRANCH env var for local override. -# If not set, bd sync will require you to run 'bd config set sync.branch '. -# sync-branch: "beads-sync" - -# Multi-repo configuration (experimental - bd-307) -# Allows hydrating from multiple repositories and routing writes to the correct JSONL -# repos: -# primary: "." # Primary repo (where this database lives) -# additional: # Additional repos to hydrate from (read-only) -# - ~/beads-planning # Personal planning repo -# - ~/work-planning # Work planning repo - -# Integration settings (access with 'bd config get/set') -# These are stored in the database, not in this file: -# - jira.url -# - jira.project -# - linear.url -# - linear.api-key -# - github.org -# - github.repo diff --git a/.beads/interactions.jsonl b/.beads/interactions.jsonl deleted file mode 100644 index e69de29b..00000000 diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl deleted file mode 100644 index 68609603..00000000 --- a/.beads/issues.jsonl +++ /dev/null @@ -1,73 +0,0 @@ -{"id":"integreat-00t","title":"Security: Input validation and sanitization in import functions","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.0129384-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:33:06.050946022-08:00","closed_at":"2026-02-08T13:33:06.050946022-08:00","close_reason":"Code review completed - import_uploaded_invoices.clj reviewed"} -{"id":"integreat-01o","title":"Security: Remove hardcoded API keys in insight_outcome_recommendation","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:46.141653019-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:31:42.926029101-08:00","closed_at":"2026-02-08T13:31:42.926029101-08:00","close_reason":"Code review completed - Hardcoded Pinecone API key found at lines 31, 48"} -{"id":"integreat-08c","title":"Performance: Fix N+1 query problem in sales_summaries","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:47.102267818-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:31:42.899786826-08:00","closed_at":"2026-02-08T13:31:42.899786826-08:00","close_reason":"Code review completed - N+1 queries identified throughout sales_summaries.clj"} -{"id":"integreat-0df","title":"Code review: auto_ap.ssr.admin.transaction_rules","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:26:21.41732477-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:26:50.545369921-08:00","closed_at":"2026-02-08T13:26:50.545369921-08:00","close_reason":"Closed"} -{"id":"integreat-0ic","title":"Clientize sales summaries and add schema cleanup","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:43.768991121-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:43.768991121-08:00"} -{"id":"integreat-0kl","title":"Code review: auto_ap.ssr.admin.import_batch","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:25:10.532871346-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:25:29.784001757-08:00","closed_at":"2026-02-08T13:25:29.784001757-08:00","close_reason":"Closed"} -{"id":"integreat-0tf","title":"Security: Remove hardcoded cookie secret","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:54.956951237-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.535163011-08:00","closed_at":"2026-02-08T13:34:04.535163011-08:00","close_reason":"Code review completed - Hardcoded cookie store key found at lines 447-448"} -{"id":"integreat-0z7","title":"Complete test coverage for transactions and invoice functionality","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:54.738460045-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:54.738460045-08:00"} -{"id":"integreat-104","title":"Code Review: auto_ap.permissions","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:58.102943422-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:00.915797483-08:00","closed_at":"2026-02-08T09:30:00.915797483-08:00","close_reason":"Closed"} -{"id":"integreat-1b8","title":"Code Review: auto_ap.ledger","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:58.457434281-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:52.517437805-08:00","closed_at":"2026-02-08T09:30:52.517437805-08:00","close_reason":"Closed"} -{"id":"integreat-1ex","title":"Security: Implement rate limiting","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:55.32191677-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.585536605-08:00","closed_at":"2026-02-08T13:34:04.585536605-08:00","close_reason":"Code review completed - Rate limiting not implemented, recommendation added"} -{"id":"integreat-1ff","title":"Code Review: iol_ion","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:59.195722157-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:30.631572319-08:00","closed_at":"2026-02-08T09:30:30.631572319-08:00","close_reason":"Closed"} -{"id":"integreat-1ht","title":"Security: Add input validation and sanitization","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:55.707181622-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.560514104-08:00","closed_at":"2026-02-08T13:34:04.560514104-08:00","close_reason":"Code review completed - handler.clj reviewed, input validation issues identified"} -{"id":"integreat-1jz","title":"Code review: auto_ap.ssr.admin.excel_invoice","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:18:26.802261171-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:18:51.297567931-08:00","closed_at":"2026-02-08T13:18:51.297567931-08:00","close_reason":"Closed"} -{"id":"integreat-1m3","title":"Security: Remove hardcoded JWT secrets","status":"in_progress","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:54.57377807-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:35:21.465147919-08:00"} -{"id":"integreat-1oo","title":"Code review: auto_ap.ssr.admin.vendors","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:26:57.577293865-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:27:29.429533887-08:00","closed_at":"2026-02-08T13:27:29.429533887-08:00","close_reason":"Closed"} -{"id":"integreat-1qy","title":"Code Review: auto_ap.routes","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:55.26442193-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:55.026115465-08:00","closed_at":"2026-02-08T13:29:55.026115465-08:00","close_reason":"No file found for this namespace"} -{"id":"integreat-278","title":"Security: Remove hardcoded Google credentials in auth.clj","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:19.491341584-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:30:37.240560315-08:00","closed_at":"2026-02-08T13:30:37.240560315-08:00","close_reason":"Code review completed - JWT secret management reviewed"} -{"id":"integreat-2cd","title":"Code review: auto_ap.ssr.admin.sales_summaries","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:25:56.325342803-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:26:17.717894907-08:00","closed_at":"2026-02-08T13:26:17.717894907-08:00","close_reason":"Closed"} -{"id":"integreat-2ti","title":"Code review: auto_ap.ssr.admin.accounts","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T12:53:44.646685216-08:00","created_by":"Bryce","updated_at":"2026-02-08T12:55:55.094416105-08:00","closed_at":"2026-02-08T12:55:55.094416105-08:00","close_reason":"Closed"} -{"id":"integreat-35k","title":"Fix session handling and authentication route issues","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:50.662486708-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:50.662486708-08:00"} -{"id":"integreat-3a7","title":"Refactor clients module for better reusability, schemas, and bug fixes","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:44.681764032-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:44.681764032-08:00"} -{"id":"integreat-3cp","title":"Code Review: auto_ap.import","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.573843708-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:55.090966459-08:00","closed_at":"2026-02-08T13:29:55.090966459-08:00","close_reason":"No file found for this namespace"} -{"id":"integreat-3pr","title":"Code Review: auto_ap.ss_routes","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.020989213-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:54.961399111-08:00","closed_at":"2026-02-08T13:29:54.961399111-08:00","close_reason":"No file found for this namespace"} -{"id":"integreat-3y8","title":"Code review: auto_ap.ssr.admin.clients","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:42:10.903791187-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:47:29.495083383-08:00","closed_at":"2026-02-08T09:47:29.495083383-08:00","close_reason":"Closed"} -{"id":"integreat-46f","title":"Security: Rate limiting for external API calls","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.429193916-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.63601665-08:00","closed_at":"2026-02-08T13:34:04.63601665-08:00","close_reason":"Code review completed - Rate limiting recommendations added"} -{"id":"integreat-4ag","title":"Code Review: iol-ion.query - Security and Code Quality Issues","description":"Code review of /home/noti/dev/integreat/iol_ion/src/iol_ion/query.clj revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- **Regex Injection Vulnerability** (line 67-68): User input passed directly to regex compilation without sanitization, enabling ReDoS attacks\\n- **No input validation on date parameters** (lines 25-30, 46-54, 83-162): Invalid dates could cause Denial of Service attacks\\n- **No validation of client IDs** (lines 46-54, 83-162): Malicious client IDs could bypass access controls\\n- **Unsafe timezone handling** (line 70-75): Hardcoded timezone without validation or fallback could cause failures\\n- **Permission checking lacks validation** (lines 59-64): Assumes identity structure without validation\\n\\n## Code Quality Issues:\\n- **Extreme code duplication** (lines 83-162): 8 scan functions with identical structure except for index names and entity types\\n- **Obsolete function** (lines 7-9): marked as \"not working in Datomic Cloud\" but still used\\n- **Magic numbers** (lines 25-30, 86-89): Hardcoded years (2001-2030) and days (90) should be configuration\\n- **Inconsistent client handling**: Mixed use of vs direct client IDs\\n\\n## Performance Issues:\\n- **Inefficient database queries** (lines 83-162): Sequential scans in for-loops instead of bulk operations\\n- **Repeated timezone conversions**: Each call to local-now converts to same timezone unnecessarily\\n\\n## Recommendations:\\n1. Add input validation for all user-supplied parameters\\n2. Create a utility function to handle regex compilation safely\\n3. Extract common scan logic into a single reusable function\\n4. Replace deprecated entid function or remove its usage\\n5. Move magic numbers to configuration constants\\n6. Optimize database queries with bulk operations\\n7. Add proper error handling and validation for all functions","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:53.593616294-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:28:52.035161365-08:00","closed_at":"2026-02-08T13:28:52.035161365-08:00","close_reason":"Closed"} -{"id":"integreat-4mc","title":"Clean up legacy code and remove commented out templates","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:48.479644441-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:48.479644441-08:00"} -{"id":"integreat-54l","title":"Code Review: auto_ap.background","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:58.809902284-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:31:14.526449134-08:00","closed_at":"2026-02-08T09:31:14.526449134-08:00","close_reason":"Closed"} -{"id":"integreat-59c","title":"Security: Fix SQL injection vulnerability in exports.clj","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:19.959391674-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:30:37.208340718-08:00","closed_at":"2026-02-08T13:30:37.208340718-08:00","close_reason":"Code review completed - SQL injection vulnerability found in export-raw function"} -{"id":"integreat-5a1","title":"Concurrency: Fix thread safety issues in sysco.clj","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:48.485672868-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:24:48.485672868-08:00"} -{"id":"integreat-6cf","title":"Implement autopay and unpaid API unification","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:49.217286047-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:49.217286047-08:00"} -{"id":"integreat-74f","title":"Security: Transaction validation and data integrity","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:29.251711914-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:04.611256589-08:00","closed_at":"2026-02-08T13:34:04.611256589-08:00","close_reason":"Code review completed - Transaction validation reviewed in multiple files"} -{"id":"integreat-7cx","title":"Code Review: auto_ap.shared_views","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.754073898-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:39.003484636-08:00","closed_at":"2026-02-08T13:29:39.003484636-08:00","close_reason":"Closed"} -{"id":"integreat-7de","title":"Security: Database connection management in imports","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:27.574962301-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:33:06.077037636-08:00","closed_at":"2026-02-08T13:33:06.077037636-08:00","close_reason":"Code review completed - No connection management issues found in import files"} -{"id":"integreat-7en","title":"Code Review: auto_ap.ss.admin.background-jobs - Security and Code Quality Issues","description":"Code review of /home/noti/dev/integreat/src/clj/auto_ap/ssr/admin/background_jobs.clj revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- **No job name validation** (lines 53-58): Job names used to construct task ARNs without validation, enabling injection attacks\\n- **Hardcoded network configuration** (lines 150-52): Subnets and security groups hardcoded with direct IPs\\n- **Hardcoded security group IDs** (lines 151-52): Security credentials directly embedded in code\\n- **No rate limiting** (lines 56-61): Job execution lacks rate limiting, enabling DoS attacks\\n- **Fragile job name sanitization** (lines 161-62): Regex replacement approach is insecure\\n- **No URL validation** (lines 74, 84-86): S3 URLs not validated before use\\n\\n## Code Quality Issues:\\n- **Poor error handling** (lines 30-37): AWS API errors not handled, could crash page\\n- **Code duplication** (lines 46-52, 53-58): and have identical logic\\n- **Magic strings** (lines 33-42, 224-42): Job names hardcoded in select options and processing\\n- **Inconsistent error handling**: Mixed approach to form errors and API errors\\n\\n## Performance Issues:\\n- **Inefficient task querying** (lines 30-37): Two separate AWS API calls instead of one\\n- **Nested AWS calls** (lines 35-36): Multiple nested API calls increase complexity\\n- **No caching**: Repeated API calls to without memoization\\n\\n## Recommendations:\\n1. Add input validation for all user-supplied parameters\\n2. Extract hardcoded configuration to environment variables or config files\\n3. Implement rate limiting on job execution\\n4. Use secure sanitization for job names\\n5. Add proper error handling for AWS API calls\\n6. Remove code duplication by extracting common logic\\n7. Optimize AWS API calls and add caching where appropriate\\n8. Validate S3 URLs before use","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:31:15.621682311-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:18:06.425132957-08:00","closed_at":"2026-02-08T13:18:06.425132957-08:00","close_reason":"Closed"} -{"id":"integreat-8jt","title":"Performance: Fix potential memory leak in client hydration","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:56.135939778-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:56.135939778-08:00"} -{"id":"integreat-8p7","title":"Code Review: auto_ap.client_routes","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:57.389725276-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:13.440742845-08:00","closed_at":"2026-02-08T13:34:13.440742845-08:00","close_reason":"No file found for auto_ap.client_routes namespace"} -{"id":"integreat-9o2","title":"Code Review: auto_ap.ss","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:56.653394004-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:54.994180329-08:00","closed_at":"2026-02-08T13:29:54.994180329-08:00","close_reason":"No file found for this namespace"} -{"id":"integreat-adj","title":"Performance: Fix CSV writing efficiency in exports.clj","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:21.877285694-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:21.877285694-08:00"} -{"id":"integreat-ae3","title":"Investigate iol-ion module and security review requirements","description":"iol-ion appears to be an external or internal module that provides query functions used throughout the codebase:\\n\\nFunctions used:\\n- iol-ion.query/ident (line 98 in transaction_rules.clj)\\n- iol-ion.query/recent-date (line 317 in transaction_rules.clj)\\n- iol-ion.query/-\u003epattern (lines 323, 541 in transaction_rules.clj)\\n- iol-ion.query/dom (lines 361, 368 in transaction_rules.clj)\\n\\nNeeds investigation:\\n1. Is iol-ion a third-party library or internal module?\\n2. What security concerns exist in its usage?\\n3. Is there proper input validation in its functions?\\n4. Are there any potential injection vulnerabilities?\\n5. What are the dependencies and version requirements?\\n\\nSearch in:\\n- project.clj or deps.edn for dependencies\\n- src directory for module definition\\n- Documentation or README files","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:31.587996635-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:30:34.841745089-08:00"} -{"id":"integreat-aut","title":"Fix payment query parameter parsing and implement proper decoding","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:46.65410618-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:46.65410618-08:00"} -{"id":"integreat-bct","title":"Complete IOL integration with Datomic Cloud","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:51.056089489-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:51.056089489-08:00"} -{"id":"integreat-d8q","title":"Code Review: auto_ap.main","notes":"Code review completed for auto_ap.views.main\n\n**Summary**: Found several issues ranging from performance to code quality.\n\n**High Priority**:\n- Inefficient key generation on line 90 using pr-str - causes unnecessary re-renders\n\n**Medium Priority**:\n- Permission check pattern duplication across 16 page methods\n- Insufficient nil handling for edge cases\n\n**Low Priority**:\n- Subscription frequency could be optimized\n- Growing page handler count suggests need for refactoring\n\n**Security**: All page routes properly check permissions - good security posture.\n\nFull detailed review saved to REVIEW_auto_ap.main.md","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.224210511-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:35:08.65588745-08:00","closed_at":"2026-02-08T09:35:08.65588745-08:00","close_reason":"Closed"} -{"id":"integreat-dsb","title":"Performance: External API calls should be asynchronous","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:29.66389647-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:29.66389647-08:00"} -{"id":"integreat-edg","title":"Fix grid page helper issues and form bubbling problems","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:45.844140503-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:45.844140503-08:00"} -{"id":"integreat-g4b","title":"Complete wizard implementation and make it more modular","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:52.493115251-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:52.493115251-08:00"} -{"id":"integreat-gf0","title":"Performance: Fix memory leak in client cache","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:23:28.846092823-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:23:28.846092823-08:00"} -{"id":"integreat-ifw","title":"Add Plaid merchant integration and improve vendors module","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:45.076207245-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:45.076207245-08:00"} -{"id":"integreat-iut","title":"Code review: auto_ap.ssr.admin.history","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:22:16.782050468-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:22:40.135978155-08:00","closed_at":"2026-02-08T13:22:40.135978155-08:00","close_reason":"Closed"} -{"id":"integreat-lov","title":"Security: Add input validation to all routes","status":"open","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:21.423853589-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:26:21.423853589-08:00"} -{"id":"integreat-mt4","title":"Code Review: auto_ap.jobs","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:54.921445539-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:55.058776633-08:00","closed_at":"2026-02-08T13:29:55.058776633-08:00","close_reason":"No file found for this namespace"} -{"id":"integreat-mxf","title":"Security: Fix error information leakage","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:21:56.506580155-08:00","created_by":"Bryce","updated_at":"2026-02-08T09:21:56.506580155-08:00"} -{"id":"integreat-opb","title":"Security: Fix SQL injection risk in close_auto_invoices","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:47.576841414-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:33:26.149329059-08:00","closed_at":"2026-02-08T13:33:26.149329059-08:00","close_reason":"Code review completed - No SQL injection risk found, queries properly parameterized"} -{"id":"integreat-oyo","title":"Componentize transaction rules and improve form handling","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:45.44170363-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:45.44170363-08:00"} -{"id":"integreat-pc1","title":"Complete real user testing for invoices and add credit from balance support","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:46.269009169-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:46.269009169-08:00"} -{"id":"integreat-qj2","title":"Improve component structure and implement better error handling","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:52.132393487-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:52.132393487-08:00"} -{"id":"integreat-rlj","title":"Complete wizard step structure and modularize page components","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:53.993488192-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:53.993488192-08:00"} -{"id":"integreat-s53","title":"Security: Remove hardcoded NTG API key in exports.clj","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:20.457790327-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:30:37.176681233-08:00","closed_at":"2026-02-08T13:30:37.176681233-08:00","close_reason":"Code review completed - Hardcoded API key found at lines 659, 665"} -{"id":"integreat-s5h","title":"Resource: Fix resource leaks in import_uploaded_invoices","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:48.026329699-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:31:42.874323093-08:00","closed_at":"2026-02-08T13:31:42.874323093-08:00","close_reason":"Code review completed - Resource leaks identified in lines 43-76"} -{"id":"integreat-syf","title":"Code Review: auto_ap.graphql","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:20:55.620533412-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:29:39.033441719-08:00","closed_at":"2026-02-08T13:29:39.033441719-08:00","close_reason":"Closed"} -{"id":"integreat-uc3","title":"Security: Input sanitization and validation in job functions","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:24:46.60155898-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:31:42.951371743-08:00","closed_at":"2026-02-08T13:31:42.951371743-08:00","close_reason":"Code review completed - Job functions reviewed, input validation needed"} -{"id":"integreat-vk3","title":"Add feature flags system and signature support","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:51.419253869-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:51.419253869-08:00"} -{"id":"integreat-vkf","title":"Improve form handling and remove unused code","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:49.592681075-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:49.592681075-08:00"} -{"id":"integreat-vvk","title":"Performance: Fix N+1 query problems in exports.clj","status":"closed","priority":1,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:26:20.96494325-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:30:37.144024095-08:00","closed_at":"2026-02-08T13:30:37.144024095-08:00","close_reason":"Code review completed - N+1 queries identified in exports.clj"} -{"id":"integreat-w1i","title":"Improve input components and data grid implementations","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:47.721945968-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:47.721945968-08:00"} -{"id":"integreat-y3e","title":"Improve typeahead component and implement proper query handling","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:53.602661377-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:53.602661377-08:00"} -{"id":"integreat-y72","title":"Enhance ledger reports and improve navigation/aside components","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:48.101954827-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:48.101954827-08:00"} -{"id":"integreat-yq9","title":"Remove deprecated code and clean up unused functions","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:54.367393577-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:54.367393577-08:00"} -{"id":"integreat-zly","title":"Code Review: auto_ap.permissions - Security and Maintainability Issues","description":"Code review of /home/noti/dev/integreat/src/cljc/auto_ap/permissions.cljc revealed critical security and maintainability issues:\\n\\n## Security Issues:\\n- Client access control bypass: Non-admins completely blocked if client-id is nil (lines 22-24)\\n- No input validation: Client IDs and user data not validated (lines 10-11, 17)\\n- Trust-based user object: No schema validation for user data\\n\\n## Maintainability Issues:\\n- Extreme code duplication: Permission logic repeated 4 times across different role checks (lines 26-141)\\n- Magic strings: Inconsistent role representation (mixing keywords and strings)\\n- Hardcoded permissions: No separation from business logic\\n- No unit tests: No test coverage for permission checks\\n\\n## Performance Issues:\\n- Redundant set creation on every call (lines 22-23)\\n- Repeated condition checks for each role\\n\\n## Recommendations:\\n1. Implement schema validation for user data using malli\\n2. Extract permissions to data structure following DRY principle\\n3. Add client-id validation with pos-int?\\n4. Add unit tests for all permission sets\\n5. Move set creation outside function or add short-circuit for admin role\\n\\nSee full review for detailed analysis and refactoring suggestions.","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T09:30:01.992071212-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:34:13.389737709-08:00","closed_at":"2026-02-08T13:34:13.389737709-08:00","close_reason":"No file found for auto_ap.permissions namespace"} -{"id":"integreat-zn0","title":"Implement cash drawer shift functionality","status":"open","priority":3,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:51.76190647-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:51.76190647-08:00"} -{"id":"integreat-zp6","title":"Code review: auto_ap.ssr.admin.sales_powerqueries","status":"closed","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T13:25:33.754411978-08:00","created_by":"Bryce","updated_at":"2026-02-08T13:25:52.806787427-08:00","closed_at":"2026-02-08T13:25:52.806787427-08:00","close_reason":"Closed"} -{"id":"integreat-zt8","title":"Complete invoice totals implementation to include expense accounts","status":"open","priority":2,"issue_type":"task","owner":"bryce@brycecovertoperations.com","created_at":"2026-02-08T08:56:48.848572114-08:00","created_by":"Bryce","updated_at":"2026-02-08T08:56:48.848572114-08:00"} diff --git a/.beads/metadata.json b/.beads/metadata.json deleted file mode 100644 index c787975e..00000000 --- a/.beads/metadata.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "database": "beads.db", - "jsonl_export": "issues.jsonl" -} \ No newline at end of file diff --git a/src/clj/auto_ap/square/core3.clj b/src/clj/auto_ap/square/core3.clj index dee59bd0..2f192cd2 100644 --- a/src/clj/auto_ap/square/core3.clj +++ b/src/clj/auto_ap/square/core3.clj @@ -293,7 +293,9 @@ (condp = (:name (:source order)) "GRUBHUB" :ccp-processor/grubhub "UBEREATS" :ccp-processor/uber-eats + "Uber Eats" :ccp-processor/uber-eats "DOORDASH" :ccp-processor/doordash + "DoorDash" :ccp-processor/doordash "Koala" :ccp-processor/koala "koala-production" :ccp-processor/koala :ccp-processor/na)) @@ -868,7 +870,11 @@ #_(comment (require 'auto-ap.time-reader) - + @(let [[c [l]] (get-square-client-and-location "DBFS") ] + (log/peek :x [ c l]) + (search c l #clj-time/date-time "2026-03-28" #clj-time/date-time "2026-03-29") + + ) @(let [[c [l]] (get-square-client-and-location "NGAK") ] (log/peek :x [ c l]) @@ -1058,18 +1064,43 @@ (count) ) - (doseq [c (get-square-clients)] - (println "Upserting" (:client/name c)) - @(upsert c)) + + + + (doseq [[code] (seq (dc/q '[:find ?code + :in $ + :where [?o :sales-order/date ?d] + [(>= ?d #inst "2026-01-01")] + [?o :sales-order/source "Invoices"] + [?o :sales-order/client ?c] + [?c :client/code ?code]] + (dc/db conn))) + :let [[c [l]] (get-square-client-and-location code) + ] + order @(search c l #clj-time/date-time "2026-01-01T00:00:00-08:00" (time/now)) + :when (= "Invoices" (:name (:source order) )) + :let [[sales-order] @(order->sales-order c l order)]] + + (when (should-import-order? order) + (println "DATE IS" (:sales-order/date sales-order)) + (when (some-> (:sales-order/date sales-order) coerce/to-date-time (time/after? #clj-time/date-time "2026-2-16T00:00:00-08:00")) + (println "WOULD UPDATE" sales-order) + @(dc/transact auto-ap.datomic/conn [sales-order]) + ) + #_@(dc/transact ) + (println "DONE")) + + + ) #_(filter (comp #{"OTHER"} :type) (mapcat :tenders z)) @(let [[c [l]] (get-square-client-and-location "NGRY")] - #_(search c l (clj-time.coerce/from-date #inst "2025-02-28") (clj-time.coerce/from-date #inst "2025-03-01")) + #_(search c l (clj-time.coerce/from-date #inst "2025-02-28") (clj-time.coerce/from-date #inst "2025-03-01")) - (order->sales-order c l (:order (get-order c l "KdvwntmfMNTKBu8NOocbxatOs18YY" ))) + (order->sales-order c l (:order (get-order c l "KdvwntmfMNTKBu8NOocbxatOs18YY" ))) - ) + ) )