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

155 lines
5.0 KiB
Markdown

# 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.<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:**
```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