# Integreat Development Guide ## Build & Run Commands ### Build ```bash lein build # Create uberjar lein uberjar # Standalone JAR npm install # Install Node.js dependencies (for frontend build) ``` ### Development ```bash 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 ```bash 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 ```bash lein test # WORST CASE ``` ### Run Specific Test Selectors ```bash lein test :integration # WORST CASE lein test :functional #WORST CASE ``` ### Run Specific Test File ```bash 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 ```bash 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:** ```clojure (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..` - 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:** ```clojure (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:** ```clojure (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