5.5 KiB
5.5 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
Pull Requests on Gitea
This project uses gitea.story-basking.ts net as the primary remote for PRs. Use tea (the Gitea CLI) to create and manage pull requests. The gitea remote is the one you push to, NOT origin and NOT deploy.
When opening a PR, load and follow the gitea-tea skill. In short:
- Target branch is always
master - Use
tea pulls create -r notid/integreat -b master --title "..." --description "..."
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/idkeyword, not string IDs - Entity attributes: follow schema convention (e.g.,
:invoice/status)
Data Types & Schema
- Use keywords for schema accessors (e.g.,
:invoice/dateinstead of strings) - Datomic pull queries use
[:db/id ...]syntax - Use
:db/identfor schema keyword resolution - Dates and times: use
insttypes (handled byclj-time.coerce) - Numbers: use
doublefor monetary values (stored as strings in DB, converted to double)
Error Handling
- Use
slingshot.slingshotlibrary 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-infowith metadata for structured exceptions - Use
throw+for throwing exceptions that can be caught byslingshot
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
defnfor public functions - Use
defn-for private functions (indicated by underscore prefix) - Use
letfnfor locally recursive functions - Use
condandcondpfor conditional logic - Use
casefor exhaustive keyword matching
Testing Patterns
- Use
clojure.testwithdeftestandtesting - Group related tests in
testingblocks - Use
isfor assertions with descriptive messages - Use
arefor parameterized assertions - Fixtures with
use-fixturesfor 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 checkbefore committing, auto-fix withlein cljfmt fix - Use
#_for commenting out entire forms (not single lines) - Use
commentspecial form for evaluation examples - Use
#_to comment out library dependencies in project.clj
Logging
- Uses
com.brunobonacci.mulogfor structured logging - Import with
(require [auto-ap.logging :as alog]) - Use
alog/info,alog/warn,alog/errorfor different log levels - Use
alog/with-context-asto add context to log messages
Linting Configuration
- Uses
clj-kondofor static analysis - Custom linters configured in
.clj-kondo/config.edn - Hooks for
mount.core/defstateandauto-ap.loggingin.clj-kondo/hooks/ - Run
clj-kondo --lint src/clj auto_ap/for linting