Files
integreat/AGENTS.md
2026-01-31 20:58:33 -08:00

5.0 KiB

Integreat Development Guide

Build & Run Commands

Build

lein build              # Create uberjar
lein uberjar            # Standalone JAR
npm install             # Install Node.js dependencies (for frontend build)

Development

docker-compose up -d    # Start Datomic, Solr services
lein repl               # Start Clojure REPL (nREPL on port 9000), typically one will be running for you already
lein cljfmt check       # Check code formatting
lein cljfmt fix         # Auto-format code
clj-paren-repair [FILE ...] # fix parentheses in files
clj-nrepl-eval -p PORT "(+ 1 2 3)" #  evaluate clojure code

Often times, if a file won't compile, first clj-paren-repair on the file, then try again. If it doesn't wor still, try cljfmt check.

Running the Application

INTEGREAT_JOB="" lein run  # Default: port 3000
# Or with custom port:
PORT=3449 lein run

Test Execution

prefer using clojure-eval skill

Run All Tests

lein test                   # WORST CASE

Run Specific Test Selectors

lein test :integration # WORST CASE
lein test :functional #WORST CASE

Run Specific Test File

clj-nrepl-eval -p PORT "(clojure.test/run-tests 'auto-ap.import.plaid-test)" # preferred method
lein test auto-ap.import.plaid-test #WORST CASE

Run Specific Test Function

lein test auto-ap.import.plaid-test/plaid->transaction #WORST CASE

Code Style Guidelines

File Organization

  • Namespaces follow auto-ap.* format
  • Source files in src/clj/auto_ap/
  • Test files in test/clj/auto_ap/
  • Backend: Clojure 1.10.1
  • Frontend: alpinejs + TailwindCSS + HTMX

Import Formatting

  • Imports must be sorted alphabetically within each group
  • Standard library imports first (clojure.core, clojure.string, etc.)
  • Third-party libraries second
  • Internal library imports last
  • Group related imports together

Example:

(ns auto-ap.example
  (:require
   [auto-ap.datomic :refer [conn pull-many]]
   [auto-ap.graphql.utils :refer [limited-clients]]
   [clojure.data.json :as json]
   [clojure.string :as str]
   [com.brunobonacci.mulog :as mu]
   [datomic.api :as dc]))

Naming Conventions

  • Namespace names: auto-ap.<feature>.<sub-feature>
  • File names: kebab-case (e.g., ledger_common.clj)
  • Functions: lowercase with underscores, descriptive (e.g., fetch-ids, process-invoice)
  • Database identifiers: use :db/id keyword, not string IDs
  • Entity attributes: follow schema convention (e.g., :invoice/status)

Data Types & Schema

  • Use keywords for schema accessors (e.g., :invoice/date instead of strings)
  • Datomic pull queries use [:db/id ...] syntax
  • Use :db/ident for schema keyword resolution
  • Dates and times: use inst types (handled by clj-time.coerce)
  • Numbers: use double for monetary values (stored as strings in DB, converted to double)

Error Handling

  • Use slingshot.slingshot library for error handling
  • Pattern: (exception->notification #(throw ...)) to wrap errors with logging
  • Pattern: (notify-if-locked client-id invoice-date) for business logic checks
  • Throw ex-info with metadata for structured exceptions
  • Use throw+ for throwing exceptions that can be caught by slingshot

Example:

(exception->notification
 (when-not (= :invoice-status/unpaid (:invoice/status invoice))
   (throw (ex-info "Cannot void an invoice if it is paid."
                   {:type :notification}))))

Function Definitions

  • Use defn for public functions
  • Use defn- for private functions (indicated by underscore prefix)
  • Use letfn for locally recursive functions
  • Use cond and condp for conditional logic
  • Use case for exhaustive keyword matching

Testing Patterns

  • Use clojure.test with deftest and testing
  • Group related tests in testing blocks
  • Use is for assertions with descriptive messages
  • Use are for parameterized assertions
  • Fixtures with use-fixtures for setup/teardown

Example:

(deftest import-invoices
  (testing "Should import valid invoice"
    (is (= 1 (invoice-count-for-client [:client/code "ABC"]))))
  (testing "Should not import duplicate invoice"
    (is (thrown? Exception (sut/import-uploaded-invoice user invoices)))))

look at the testing-conventions skill for more detail

Code Formatting & Documentation

  • Use lein cljfmt check before committing, auto-fix with lein cljfmt fix
  • Use #_ for commenting out entire forms (not single lines)
  • Use comment special form for evaluation examples
  • Use #_ to comment out library dependencies in project.clj

Logging

  • Uses com.brunobonacci.mulog for structured logging
  • Import with (require [auto-ap.logging :as alog])
  • Use alog/info, alog/warn, alog/error for different log levels
  • Use alog/with-context-as to add context to log messages

Linting Configuration

  • Uses clj-kondo for static analysis
  • Custom linters configured in .clj-kondo/config.edn
  • Hooks for mount.core/defstate and auto-ap.logging in .clj-kondo/hooks/
  • Run clj-kondo --lint src/clj auto_ap/ for linting