Version: 1.1
Date: 2026-01-19
Status: ✅ Complete (v0.1.0 released)
Owner: Boundary Core Team
This document outlines the detailed implementation plan for splitting the Boundary monolithic framework into 8 modular, independently publishable Clojars libraries. This transformation will enable developers to use Boundary as a foundation for their projects with flexible dependency management while maintaining the cohesive framework experience.
8 independently publishable libraries in a monorepo:
boundary/core - Foundation utilities and validationboundary/observability - Logging, metrics, error reportingboundary/platform - Database, HTTP, pagination, searchboundary/user - Authentication, MFA, sessionsboundary/admin - Auto-generated CRUD admin interfaceboundary/storage - File storage (local, S3)boundary/external - External service adapters (email, payments) (placeholder)boundary/scaffolder - Code generation toolingReleased: 2026-01-18
Tag: v0.1.0
| Phase | Status | Notes |
|---|---|---|
| Phase 0: Preparation | ✅ Complete | Monorepo structure, root deps.edn, build scripts |
| Phase 1: Core | ✅ Complete | 8,000+ LOC migrated, all tests passing |
| Phase 2: Observability | ✅ Complete | Logging, metrics, error reporting extracted |
| Phase 3: Platform | ✅ Complete | Database, HTTP, system wiring migrated |
| Phase 4: User | ✅ Complete | Auth, MFA, sessions migrated |
| Phase 5: Admin | ✅ Complete | Admin UI and shared components migrated |
| Phase 6: Storage | ✅ Complete | Local and S3 adapters migrated |
| Phase 7: External | ⏳ Deferred | Placeholder created, no adapters exist yet |
| Phase 8: Scaffolder | ✅ Complete | Code generator migrated |
| Phase 9: Examples | 🔶 Partial | Inventory migrated; starter-app/full-app pending |
| Phase 10: Publishing | ⏳ Deferred | Git tag created; Clojars publishing pending |
| Phase 11: Release | ✅ Complete | v0.1.0 tagged for internal use |
src/boundary/
├── admin/ # Auto-CRUD admin interface
├── config.clj # Aero-based configuration
├── error_reporting/ # Error tracking (Sentry)
├── inventory/ # Example domain module → moving to examples/
├── jobs/ # Background jobs → future enhancement
├── logging/ # Structured logging
├── main.clj # Entry point
├── metrics/ # Metrics collection
├── platform/ # Core infrastructure
├── scaffolder/ # Code generator
├── shared/ # Shared utilities → becoming core
├── storage/ # File storage
└── user/ # User management & auth
Current Coupling Issues:
platform/shell/system/wiring.clj hard-codes module requiresboundary.shared namespace will need renaming to boundary.coreshared/ui → moving to adminDependency Flow (Current):
admin, user, inventory → platform → logging, metrics, error_reporting → shared
Purpose: Foundation library providing validation, utilities, and interceptor framework.
Contents:
Namespace Mapping:
boundary.shared.core.validation.* → boundary.core.validation.*
boundary.shared.core.utils.* → boundary.core.utils.*
boundary.shared.core.interceptor → boundary.core.interceptor
boundary.shared.core.config.feature_flags → boundary.core.config.feature_flags
Dependencies:
{:deps {org.clojure/clojure {:mvn/version "1.12.4"}
metosin/malli {:mvn/version "0.20.0"}}}
Size: ~8,000 LOC
Purpose: Unified observability stack with pluggable adapters.
Contents:
Namespace Mapping:
boundary.logging.* → boundary.observability.logging.*
boundary.metrics.* → boundary.observability.metrics.*
boundary.error_reporting.* → boundary.observability.errors.*
Dependencies:
{:deps {boundary/core {:mvn/version "0.1.0"}
org.clojure/tools.logging {:mvn/version "1.3.1"}
ch.qos.logback/logback-classic {:mvn/version "1.5.23"}
io.sentry/sentry-clj {:mvn/version "8.29.238"}}}
Size: ~3,500 LOC
Purpose: Core infrastructure for web applications.
Contents:
Namespace Structure:
boundary.platform.database/
core/ # Query building, validation
ports.clj # Database protocols
adapters/ # Multi-DB implementations
boundary.platform.http/
core/ # Problem details
ports.clj # HTTP protocols
interceptors.clj # HTTP middleware
versioning.clj # API versioning
adapters/reitit.clj
boundary.platform.pagination/
boundary.platform.search/
boundary.platform.system/
wiring.clj # Integrant lifecycle
modules.clj # Module discovery
boundary.platform.interceptors/
service.clj # Service layer observability
persistence.clj # DB operation observability
Dependencies:
{:deps {boundary/observability {:mvn/version "0.1.0"}
com.github.seancorfield/next.jdbc {:mvn/version "1.3.1086"}
com.github.seancorfield/honeysql {:mvn/version "2.7.1364"}
com.zaxxer/HikariCP {:mvn/version "7.0.2"}
migratus/migratus {:mvn/version "1.6.4"}
ring/ring-core {:mvn/version "1.15.3"}
ring/ring-jetty-adapter {:mvn/version "1.15.3"}
metosin/reitit-ring {:mvn/version "0.9.2"}
metosin/reitit-malli {:mvn/version "0.9.2"}
integrant/integrant {:mvn/version "1.0.1"}
integrant/repl {:mvn/version "0.5.0"}
aero/aero {:mvn/version "1.1.6"}}}
;; Database drivers are OPTIONAL - users include what they need:
;; org.xerial/sqlite-jdbc
;; org.postgresql/postgresql
;; com.mysql/mysql-connector-j
;; com.h2database/h2
Size: ~15,000 LOC
Purpose: Complete user management and authentication system.
Contents:
Dependencies:
{:deps {boundary/platform {:mvn/version "0.1.0"}
buddy/buddy-hashers {:mvn/version "2.0.167"}
buddy/buddy-sign {:mvn/version "3.6.1-359"}
one-time/one-time {:mvn/version "0.8.0"}
hiccup/hiccup {:mvn/version "2.0.0"}}}
Size: ~12,000 LOC
Purpose: Auto-generated CRUD admin interface with shared UI components.
Contents:
boundary.shared.ui):
Namespace Structure:
boundary.admin/
core/
permissions.clj
schema_introspection.clj
ui.clj
shell/
service.clj
http.clj
schema_repository.clj
module_wiring.clj
boundary.ui/ # Shared UI components
core/
layout.clj
components.clj
icons.clj
table.clj
validation.clj
Dependencies:
{:deps {boundary/platform {:mvn/version "0.1.0"}
boundary/user {:mvn/version "0.1.0"} ; For admin authentication
hiccup/hiccup {:mvn/version "2.0.0"}}}
Size: ~8,000 LOC
Purpose: File storage abstraction with multiple backends.
Contents:
Dependencies:
{:deps {boundary/platform {:mvn/version "0.1.0"}
software.amazon.awssdk/s3 {:mvn/version "2.39.5"}
software.amazon.awssdk/s3-transfer-manager {:mvn/version "2.39.5"}}}
Size: ~2,000 LOC
Purpose: Adapters for external services.
Contents:
Dependencies:
{:deps {boundary/platform {:mvn/version "0.1.0"}}}
Size: ~1,500 LOC
Purpose: Code generation tool for creating new modules.
Contents:
Dependencies:
{:deps {boundary/core {:mvn/version "0.1.0"}
org.clojure/tools.cli {:mvn/version "1.3.250"}}}
Size: ~3,000 LOC
┌─────────────────────────────────────────────────────────────────┐
│ APPLICATION LAYER │
│ (User's project using Boundary) │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┴────────────────┐
│ │
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ boundary/admin │ │ boundary/scaffolder │
│ + shared UI │ │ (dev tool only) │
└──────────┬───────────┘ └──────────┬───────────┘
│ │
▼ │
┌──────────────────────┐ │
│ boundary/user │ │
└──────────┬───────────┘ │
│ │
├────────────┬────────────┐ │
▼ ▼ ▼ │
┌─────────────┐ ┌──────────┐ ┌─────────┐ │
│boundary/ │ │boundary/ │ │boundary/│ │
│storage │ │external │ │admin │ │
└──────┬──────┘ └────┬─────┘ └────┬────┘ │
│ │ │ │
└──────────────┴─────────────┘ │
│ │
▼ │
┌────────────────────┐ │
│ boundary/platform │ │
└─────────┬──────────┘ │
│ │
▼ │
┌────────────────────────┐ │
│ boundary/observability │ │
└─────────┬──────────────┘ │
│ │
▼ ▼
┌──────────────────────────────┐
│ boundary/core │
└──────────────────────────────┘
boundary/ # Root repository
├── .github/
│ └── workflows/
│ ├── ci.yml # CI for all libs
│ ├── release.yml # Coordinated release
│ └── docs.yml # Documentation generation
│
├── libs/ # All libraries
│ ├── core/
│ │ ├── deps.edn
│ │ ├── build.clj
│ │ ├── README.md
│ │ ├── CHANGELOG.md
│ │ ├── src/boundary/core/
│ │ └── test/boundary/core/
│ │
│ ├── observability/
│ │ ├── deps.edn
│ │ ├── build.clj
│ │ ├── README.md
│ │ ├── src/boundary/observability/
│ │ └── test/boundary/observability/
│ │
│ ├── platform/
│ │ ├── deps.edn
│ │ ├── build.clj
│ │ ├── README.md
│ │ ├── src/boundary/platform/
│ │ ├── test/boundary/platform/
│ │ └── resources/
│ │ └── migrations/
│ │
│ ├── user/
│ │ ├── deps.edn
│ │ ├── build.clj
│ │ ├── README.md
│ │ ├── src/boundary/user/
│ │ ├── test/boundary/user/
│ │ └── resources/
│ │ └── migrations/
│ │
│ ├── admin/
│ │ ├── deps.edn
│ │ ├── build.clj
│ │ ├── README.md
│ │ ├── src/
│ │ │ ├── boundary/admin/
│ │ │ └── boundary/ui/ # Shared UI components
│ │ ├── test/
│ │ └── resources/
│ │ ├── public/css/
│ │ └── public/js/
│ │
│ ├── storage/
│ │ ├── deps.edn
│ │ ├── build.clj
│ │ ├── README.md
│ │ ├── src/boundary/storage/
│ │ └── test/boundary/storage/
│ │
│ ├── external/
│ │ ├── deps.edn
│ │ ├── build.clj
│ │ ├── README.md
│ │ ├── src/boundary/external/
│ │ └── test/boundary/external/
│ │
│ └── scaffolder/
│ ├── deps.edn
│ ├── build.clj
│ ├── README.md
│ ├── src/boundary/scaffolder/
│ └── test/boundary/scaffolder/
│
├── examples/ # Example applications
│ ├── inventory/ # Domain module example
│ │ ├── README.md
│ │ ├── deps.edn
│ │ ├── src/boundary/inventory/
│ │ └── test/boundary/inventory/
│ │
│ ├── starter-app/ # Minimal working app
│ │ ├── README.md
│ │ ├── deps.edn
│ │ ├── src/myapp/
│ │ └── resources/conf/
│ │
│ └── full-app/ # All features enabled
│ ├── README.md
│ ├── deps.edn
│ ├── src/myapp/
│ └── resources/conf/
│
├── docs/ # Documentation
│ ├── guides/
│ │ ├── getting-started.md
│ │ ├── migration-guide.md
│ │ ├── module-development.md
│ │ └── database-setup.md
│ ├── adr/ # Architecture Decision Records
│ │ └── ADR-001-library-split.md
│ ├── api/ # API documentation
│ └── LIBRARY_SPLIT_IMPLEMENTATION_PLAN.md
│
├── tools/ # Build and development tools
│ ├── build.clj # Coordinated build script
│ └── release.clj # Release automation
│
├── deps.edn # Root deps for development
├── README.md # Main project README
├── LICENSE # Project license
└── CHANGELOG.md # Changelog for all libs
Each library follows this pattern:
libs/{library-name}/
├── deps.edn # Library dependencies
├── build.clj # Build configuration
├── README.md # Library-specific README
├── CHANGELOG.md # Library changelog
├── src/
│ └── boundary/
│ └── {library-name}/
│ ├── core/ # Pure business logic
│ ├── shell/ # I/O, adapters
│ ├── ports.clj # Protocol definitions
│ └── schema.clj# Malli schemas
├── test/
│ └── boundary/
│ └── {library-name}/
│ ├── core/ # Unit tests
│ └── shell/ # Integration tests
└── resources/ # Library-specific resources
Objective: Set up monorepo infrastructure without changing code.
Tasks:
Create monorepo directory structure
mkdir -p libs/{core,observability,platform,user,admin,storage,external,scaffolder}
mkdir -p examples/{inventory,starter-app,full-app}
mkdir -p tools
Create root deps.edn with development aliases
{:paths []
:deps {}
:aliases
{:dev {:extra-paths ["libs/core/src" "libs/observability/src" ...]
:extra-deps {...}}
:test {:extra-paths ["libs/core/test" "libs/observability/test" ...]}
:build:all {:exec-fn build/release-all}
:build:core {:exec-fn build/release-core}
...}}
Set up CI/CD pipeline
Create build tooling
tools/build.clj - Coordinated build/releasetools/release.clj - Clojars publishingInitialize each library with skeleton structure
Deliverables:
deps.edn configuredSuccess Criteria:
clojure -A:dev -M:repl-clj from rootObjective: Create the foundation library with zero internal dependencies.
Tasks:
Namespace Migration
# Move files
mkdir -p libs/core/src/boundary/core
mv src/boundary/shared/core/validation libs/core/src/boundary/core/
mv src/boundary/shared/core/utils libs/core/src/boundary/core/
mv src/boundary/shared/core/interceptor.clj libs/core/src/boundary/core/
mv src/boundary/shared/core/interceptor_context.clj libs/core/src/boundary/core/
mv src/boundary/shared/core/config libs/core/src/boundary/core/
Update Namespace Declarations
boundary.shared.core → boundary.core(:require ...) statementsCreate libs/core/deps.edn
{:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.12.4"}
metosin/malli {:mvn/version "0.20.0"}}
:aliases
{:test {:extra-paths ["test"]
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}}}}
Migrate Tests
mv test/boundary/shared/core libs/core/test/boundary/core
# Update test namespaces
Create Library README
Verify Independence
cd libs/core
clojure -M:test
Deliverables:
deps.edn created and testedSuccess Criteria:
clojure -M:test passes in libs/core/ directoryboundary.shared, boundary.platform, etc. in requiresclojure -M:clj-kondo --lint libs/core/srcObjective: Separate observability stack (logging, metrics, errors).
Tasks:
Namespace Migration
mkdir -p libs/observability/src/boundary/observability
mv src/boundary/logging libs/observability/src/boundary/observability/
mv src/boundary/metrics libs/observability/src/boundary/observability/
mv src/boundary/error_reporting libs/observability/src/boundary/observability/errors
Update Namespace Declarations
boundary.logging → boundary.observability.loggingboundary.metrics → boundary.observability.metricsboundary.error_reporting → boundary.observability.errorsUpdate Dependencies
boundary.shared requires to boundary.coreboundary/core as dependencyCreate libs/observability/deps.edn
{:paths ["src" "resources"]
:deps {boundary/core {:local/root "../core"} ; For dev, mvn/version for release
org.clojure/tools.logging {:mvn/version "1.3.1"}
ch.qos.logback/logback-classic {:mvn/version "1.5.23"}
io.sentry/sentry-clj {:mvn/version "8.29.238"}}
:aliases {:test {...}}}
Migrate Tests
Update All References in Codebase
(:require [boundary.logging and updateplatform/shell/system/wiring.cljDeliverables:
boundary/core workingSuccess Criteria:
cd libs/observability && clojure -M:testboundary.logging references in codebaseObjective: Core platform infrastructure with dynamic module system.
Tasks:
Implement Dynamic Module Registration (Critical!)
Create src/boundary/platform/system/modules.clj:
(ns boundary.platform.system.modules
"Dynamic module registration system.")
(defonce ^:private registered-modules (atom {}))
(defn register-module!
"Register a module's wiring namespace.
Called by each module on namespace load."
[module-key wiring-ns-sym]
(swap! registered-modules assoc module-key wiring-ns-sym))
(defn load-registered-modules!
"Load all registered module wirings."
[]
(doseq [[module-key ns-sym] @registered-modules]
(try
(require ns-sym)
(catch Exception e
(log/warn "Failed to load module" {:module module-key :error e})))))
Update system/wiring.clj
load-registered-modules! at initMove Platform Files
mkdir -p libs/platform/src/boundary/platform
mv src/boundary/platform/* libs/platform/src/boundary/platform/
Update Dependencies
boundary.shared → boundary.coreboundary.logging → boundary.observability.loggingboundary.metrics → boundary.observability.metricsboundary.error_reporting → boundary.observability.errorsCreate libs/platform/deps.edn
{:paths ["src" "resources"]
:deps {boundary/observability {:local/root "../observability"}
com.github.seancorfield/next.jdbc {:mvn/version "1.3.1086"}
com.github.seancorfield/honeysql {:mvn/version "2.7.1364"}
com.zaxxer/HikariCP {:mvn/version "7.0.2"}
migratus/migratus {:mvn/version "1.6.4"}
ring/ring-core {:mvn/version "1.15.3"}
ring/ring-jetty-adapter {:mvn/version "1.15.3"}
metosin/reitit-ring {:mvn/version "0.9.2"}
metosin/reitit-malli {:mvn/version "0.9.2"}
integrant/integrant {:mvn/version "1.0.1"}
integrant/repl {:mvn/version "0.5.0"}
aero/aero {:mvn/version "1.1.6"}}
:aliases {:test {:extra-deps {com.h2database/h2 {:mvn/version "2.4.240"}}}}}
Extract Database Migrations
resources/migrations/Migrate Tests
Deliverables:
Success Criteria:
Objective: User management module with self-registration.
Tasks:
Add Module Self-Registration
Update src/boundary/user/shell/module_wiring.clj:
(ns boundary.user.shell.module-wiring
(:require [boundary.platform.system.modules :as modules]
[boundary.user.shell.persistence :as persistence]
[boundary.user.shell.service :as service]
...))
;; Self-registration on namespace load
(modules/register-module! :user 'boundary.user.shell.module-wiring)
;; ... existing defmethod forms ...
Move User Files
mkdir -p libs/user/src/boundary/user
mv src/boundary/user/* libs/user/src/boundary/user/
Update Dependencies
boundary/platform dependencyCreate libs/user/deps.edn
{:paths ["src" "resources"]
:deps {boundary/platform {:local/root "../platform"}
buddy/buddy-hashers {:mvn/version "2.0.167"}
buddy/buddy-sign {:mvn/version "3.6.1-359"}
one-time/one-time {:mvn/version "0.8.0"}
hiccup/hiccup {:mvn/version "2.0.0"}}
:aliases {:test {:extra-deps {com.h2database/h2 {:mvn/version "2.4.240"}}}}}
Move Migrations
mv resources/migrations/*_create_users.sql libs/user/resources/migrations/
mv resources/migrations/*_create_sessions.sql libs/user/resources/migrations/
Migrate Tests
Update Configuration Loading
Deliverables:
Success Criteria:
cd libs/user && clojure -M:testObjective: Admin interface with shared UI components.
Tasks:
Move Admin Files
mkdir -p libs/admin/src/boundary/admin
mkdir -p libs/admin/src/boundary/ui
mv src/boundary/admin/* libs/admin/src/boundary/admin/
mv src/boundary/shared/ui/* libs/admin/src/boundary/ui/
Update UI Namespace
boundary.shared.ui.core → boundary.ui.coreAdd Module Self-Registration
(modules/register-module! :admin 'boundary.admin.shell.module-wiring)
Move Static Assets
mkdir -p libs/admin/resources/public
mv resources/public/css libs/admin/resources/public/
mv resources/public/js libs/admin/resources/public/
Create libs/admin/deps.edn
{:paths ["src" "resources"]
:deps {boundary/platform {:local/root "../platform"}
boundary/user {:local/root "../user"} ; For admin auth
hiccup/hiccup {:mvn/version "2.0.0"}}
:aliases {:test {...}}}
Update All UI Component References
boundary.shared.ui across entire codebaseboundary.uiMigrate Tests
Deliverables:
Success Criteria:
Objective: File storage library.
Tasks:
Move Storage Files
mkdir -p libs/storage/src/boundary/storage
mv src/boundary/storage/* libs/storage/src/boundary/storage/
Create libs/storage/deps.edn
{:paths ["src" "resources"]
:deps {boundary/platform {:local/root "../platform"}
software.amazon.awssdk/s3 {:mvn/version "2.39.5"}
software.amazon.awssdk/s3-transfer-manager {:mvn/version "2.39.5"}}
:aliases {:test {...}}}
Migrate Tests
Deliverables:
Objective: External service adapters library.
Tasks:
Move External Service Files
mkdir -p libs/external/src/boundary/external
mv src/boundary/platform/shell/adapters/external/* libs/external/src/boundary/external/
Create libs/external/deps.edn
{:paths ["src" "resources"]
:deps {boundary/platform {:local/root "../platform"}}
:aliases {:test {...}}}
Migrate Tests
Deliverables:
Note: Phase 7 was deferred. The
libs/external/structure was created as a placeholder for future external service adapters (SMTP, Stripe, etc.) but no source code was migrated as none exists yet.
Objective: Code generation tool.
Tasks:
Move Scaffolder Files
mkdir -p libs/scaffolder/src/boundary/scaffolder
mv src/boundary/scaffolder/* libs/scaffolder/src/boundary/scaffolder/
Create Standalone CLI
Create libs/scaffolder/deps.edn
{:paths ["src" "resources"]
:deps {boundary/core {:local/root "../core"}
org.clojure/tools.cli {:mvn/version "1.3.250"}}
:aliases {:test {...}}}
Update Templates
boundary.platform.system.modules/register-module!Deliverables:
Objective: Example applications and documentation.
Tasks:
Move Inventory to Examples
mkdir -p examples/inventory
mv src/boundary/inventory examples/inventory/src/boundary/
Create Starter App
Create Full App
Write Migration Guide
Update Documentation
Deliverables:
Note: Phase 9 partially complete. The
examples/directory structure exists with inventory example, but starter-app and full-app are placeholders for future development.
Objective: Prepare for Clojars release.
Tasks:
Register Clojars Group
boundary group on Clojarsio.github.boundary as fallbackConfigure Build Scripts
;; tools/build.clj
(defn release-all [_]
(doseq [lib ["core" "observability" "platform"
"user" "admin" "storage" "external" "scaffolder"]]
(release-lib lib)))
Create Release Checklist
Set Up GitHub Actions Release Workflow
Test Publishing Process
Deliverables:
Note: Phase 10 deferred. v0.1.0 was released as a git tag for internal use. Clojars publishing will be done when ready for public release.
Objective: Public release to Clojars.
Tasks:
Final Testing
Version All Libraries to 0.1.0
Update All deps.edn Files
:local/root to :mvn/version referencesCreate Release Notes
Tag Release
git tag -a v0.1.0 -m "Initial library release"
git push origin v0.1.0
Publish to Clojars
Announce Release
Deliverables:
Note: v0.1.0 released as internal milestone. Clojars publishing and public announcement deferred until ready for external consumption.
Problem: Current implementation hard-codes module requires in wiring.clj.
Solution: Module self-registration pattern.
Implementation:
;; In boundary.platform.system.modules
(ns boundary.platform.system.modules
"Dynamic module registration for Integrant components.")
(defonce ^:private registered-modules (atom {}))
(defn register-module!
"Register a module's Integrant wiring namespace.
Args:
module-key: Keyword identifier for the module (e.g., :user)
wiring-ns-sym: Quoted symbol of the wiring namespace
Example:
(register-module! :user 'boundary.user.shell.module-wiring)"
[module-key wiring-ns-sym]
(swap! registered-modules assoc module-key wiring-ns-sym)
(log/debug "Registered module" {:module module-key :wiring-ns wiring-ns-sym}))
(defn unregister-module!
"Unregister a module (primarily for testing)."
[module-key]
(swap! registered-modules dissoc module-key))
(defn registered-modules
"Return map of all registered modules."
[]
@registered-modules)
(defn load-registered-modules!
"Load all registered module wiring namespaces.
Called by system/wiring.clj during Integrant initialization."
[]
(doseq [[module-key ns-sym] @registered-modules]
(try
(require ns-sym)
(log/info "Loaded module" {:module module-key})
(catch Exception e
(log/error e "Failed to load module" {:module module-key})
(throw (ex-info "Module loading failed"
{:module module-key :wiring-ns ns-sym}
e))))))
Module Usage:
;; In boundary.user.shell.module-wiring
(ns boundary.user.shell.module-wiring
(:require [boundary.platform.system.modules :as modules]
[integrant.core :as ig]
...))
;; Self-registration on namespace load
(modules/register-module! :user 'boundary.user.shell.module-wiring)
;; Existing Integrant methods
(defmethod ig/init-key :boundary/user-repository [_ config] ...)
(defmethod ig/halt-key! :boundary/user-repository [_ repo] ...)
System Wiring:
;; In boundary.platform.system.wiring
(ns boundary.platform.system.wiring
(:require [boundary.platform.system.modules :as modules]
...))
;; Load registered modules BEFORE Integrant init
(modules/load-registered-modules!)
;; ... rest of wiring code ...
Migration Table:
| Old Namespace | New Namespace | Breaking Change? |
|---|---|---|
boundary.shared.core.* | boundary.core.* | Yes |
boundary.shared.ui.* | boundary.ui.* | Yes |
boundary.logging.* | boundary.observability.logging.* | Yes |
boundary.metrics.* | boundary.observability.metrics.* | Yes |
boundary.error_reporting.* | boundary.observability.errors.* | Yes |
boundary.platform.* | boundary.platform.* | No |
boundary.user.* | boundary.user.* | No |
boundary.admin.* | boundary.admin.* | No |
Automated Migration Script:
#!/bin/bash
# migrate-namespaces.sh
# Core namespace renames
find . -name "*.clj" -type f -exec sed -i '' 's/boundary\.shared\.core/boundary.core/g' {} +
find . -name "*.clj" -type f -exec sed -i '' 's/boundary\.shared\.ui/boundary.ui/g' {} +
# Observability namespace renames
find . -name "*.clj" -type f -exec sed -i '' 's/boundary\.logging/boundary.observability.logging/g' {} +
find . -name "*.clj" -type f -exec sed -i '' 's/boundary\.metrics/boundary.observability.metrics/g' {} +
find . -name "*.clj" -type f -exec sed -i '' 's/boundary\.error-reporting/boundary.observability.errors/g' {} +
echo "Namespace migration complete. Please review changes and run tests."
Before (Monolith):
;; All internal requires work directly
(ns myapp.core
(:require [boundary.shared.core.validation :as validation]
[boundary.platform.database.core :as db]))
After (Libraries):
;; deps.edn
{:deps {boundary/platform {:mvn/version "0.1.0"}}}
;; Namespace updates
(ns myapp.core
(:require [boundary.core.validation :as validation]
[boundary.platform.database.core :as db]))
Module Registration in Application Code:
;; In your app's main.clj or config.clj
(ns myapp.main
(:require
;; Explicitly require modules you want to use
;; This triggers their self-registration
[boundary.user.shell.module-wiring]
[boundary.admin.shell.module-wiring]
[myapp.modules.orders.shell.module-wiring]
;; Then require system wiring
[boundary.platform.system.wiring :as wiring]
[boundary.config :as config]
[integrant.core :as ig]))
(defn -main [& args]
(let [config (config/load-config)
ig-config (config/ig-config config)
system (ig/init ig-config)]
;; System running with all registered modules
system))
Step 1: Update deps.edn
;; BEFORE (Git dependency)
{:deps {boundary/boundary {:git/url "https://github.com/boundary/boundary"
:git/sha "abc123"}}}
;; AFTER (Choose your approach)
;; Option A: Full framework (all features)
{:deps {boundary/admin {:mvn/version "0.1.0"}
;; Plus your database driver
org.postgresql/postgresql {:mvn/version "42.7.8"}}}
;; Option B: Platform + select modules
{:deps {boundary/platform {:mvn/version "0.1.0"}
boundary/user {:mvn/version "0.1.0"}
org.postgresql/postgresql {:mvn/version "42.7.8"}}}
;; Option C: Core utilities only
{:deps {boundary/core {:mvn/version "0.1.0"}}}
Step 2: Update Namespace Requires
Run the migration script or manually update:
;; BEFORE
(ns myapp.core
(:require [boundary.shared.core.validation :as validation]
[boundary.shared.core.utils.case-conversion :as case]
[boundary.logging.core :as log]
[boundary.metrics.core :as metrics]))
;; AFTER
(ns myapp.core
(:require [boundary.core.validation :as validation]
[boundary.core.utils.case-conversion :as case]
[boundary.observability.logging.core :as log]
[boundary.observability.metrics.core :as metrics]))
Step 3: Update Module Registration
;; BEFORE
;; Module wiring was automatically loaded
;; AFTER
;; Explicitly require module wirings in your app entry point
(ns myapp.main
(:require [boundary.user.shell.module-wiring]
[boundary.admin.shell.module-wiring]
;; Your custom modules
[myapp.orders.shell.module-wiring]
[boundary.config :as config]
[integrant.core :as ig]))
Step 4: Update Database Drivers
;; Database drivers are now optional - add what you need
{:deps {boundary/platform {:mvn/version "0.1.0"}
;; Choose your database driver(s)
org.postgresql/postgresql {:mvn/version "42.7.8"}
;; org.xerial/sqlite-jdbc {:mvn/version "3.51.0.0"}
;; com.mysql/mysql-connector-j {:mvn/version "9.5.0"}
}}
Step 5: Update UI Component Requires (if using admin/UI)
;; BEFORE
(ns myapp.views
(:require [boundary.shared.ui.core.components :as ui]
[boundary.shared.ui.core.icons :as icons]))
;; AFTER
(ns myapp.views
(:require [boundary.ui.core.components :as ui]
[boundary.ui.core.icons :as icons]))
Step 6: Test Your Application
# Run tests
clojure -M:test
# Verify no old namespace references
grep -r "boundary.shared" src/
grep -r "boundary.logging" src/ # Should be boundary.observability.logging
Quick Start:
;; deps.edn
{:paths ["src" "resources"]
:deps {boundary/admin {:mvn/version "0.1.0"}
org.postgresql/postgresql {:mvn/version "42.7.8"}}
:aliases {:dev {:extra-paths ["dev"]}}}
;; src/myapp/main.clj
(ns myapp.main
(:require [boundary.user.shell.module-wiring]
[boundary.admin.shell.module-wiring]
[boundary.config :as config]
[integrant.core :as ig]))
(defn -main [& args]
(let [config (config/load-config)
ig-config (config/ig-config config)]
(ig/init ig-config)))
See examples/starter-app for complete working example.
Issue 1: "Namespace not found" errors
CompilerException: java.io.FileNotFoundException:
Could not locate boundary/shared/core/validation.clj
Solution: Update namespace requires to new names.
Issue 2: Module not loading
WARNING: No implementation of method: :init-key
for class: clojure.lang.Keyword
Solution: Explicitly require module wiring namespace:
(require '[boundary.user.shell.module-wiring])
Issue 3: Circular dependency
Solution: Libraries are designed to avoid circular deps. If you encounter this, check your custom code dependencies.
Unit Tests: Pure functions, no I/O
libs/{lib}/test/boundary/{lib}/core/
Integration Tests: With mocked dependencies
libs/{lib}/test/boundary/{lib}/shell/
Contract Tests: With real dependencies (H2 database)
libs/{lib}/test/boundary/{lib}/contract/
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
lib: [core, observability, platform, user, admin, storage, external, scaffolder]
steps:
- uses: actions/checkout@v3
- name: Setup Clojure
uses: DeLaGuardo/setup-clojure@master
with:
cli: 1.11.1.1347
- name: Test ${{ matrix.lib }}
run: |
cd libs/${{ matrix.lib }}
clojure -M:test
- name: Lint ${{ matrix.lib }}
run: |
cd libs/${{ matrix.lib }}
clojure -M:clj-kondo --lint src test
Cross-Library Integration Test:
;; test/integration/full_stack_test.clj
(ns integration.full-stack-test
"Test that all libraries work together"
(:require [clojure.test :refer :all]
[boundary.user.shell.module-wiring]
[boundary.admin.shell.module-wiring]
[boundary.config :as config]
[integrant.core :as ig]))
(deftest full-stack-integration
(testing "Can initialize complete system with all modules"
(let [config (config/load-config {:profile :test})
ig-config (config/ig-config config)
system (ig/init ig-config)]
(is (some? system))
(is (contains? system :boundary/user-service))
(is (contains? system :boundary/admin-service))
(ig/halt! system))))
Synchronized Versioning: All libraries share the same version number.
0.1.0deps.edn filesv0.1.0Manual Process (Initial):
# For each library
cd libs/core
clojure -T:build jar
clojure -T:build deploy
cd ../observability
clojure -T:build jar
clojure -T:build deploy
# ... repeat for all libraries
Automated Process (GitHub Actions):
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Clojure
uses: DeLaGuardo/setup-clojure@master
- name: Publish All Libraries
env:
CLOJARS_USERNAME: ${{ secrets.CLOJARS_USERNAME }}
CLOJARS_PASSWORD: ${{ secrets.CLOJARS_PASSWORD }}
run: |
clojure -T:build release-all
| Phase | Duration | Start | End |
|---|---|---|---|
| 0. Preparation | 2 days | Day 1 | Day 2 |
| 1. Core | 3 days | Day 3 | Day 5 |
| 2. Observability | 3 days | Day 6 | Day 8 |
| 3. Platform | 5 days | Day 9 | Day 13 |
| 4. User | 3 days | Day 14 | Day 16 |
| 5. Admin | 3 days | Day 17 | Day 19 |
| 6. Storage | 2 days | Day 20 | Day 21 |
| 7. External | 2 days | Day 22 | Day 23 |
| 8. Scaffolder | 2 days | Day 24 | Day 25 |
| 9. Examples | 3 days | Day 26 | Day 28 |
| 10. Publishing | 1 day | Day 29 | Day 29 |
| 11. Release | 1 day | Day 30 | Day 30 |
| Total | 30 days | 6 weeks |
Personnel:
Infrastructure:
boundary group ownershipCritical Path:
Potential Blockers:
boundary group name unavailability → Use io.github.boundary| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| Circular dependencies discovered | Medium | High | Careful dependency analysis completed; strict layering enforced |
| Test coverage gaps | Low | Medium | Maintain >80% coverage throughout; run full suite after each phase |
| Breaking changes missed | Medium | High | Comprehensive migration testing; maintain backwards compatibility checklist |
| Performance regression | Low | Medium | Benchmark before/after; optimize if needed |
| Module registration bugs | Medium | High | Extensive testing of dynamic loading; fallback to explicit requires |
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| Timeline overrun | Medium | Medium | Build in 20% buffer; prioritize phases |
| Clojars group unavailable | Low | Low | Fallback to io.github.boundary |
| Breaking existing users | High | High | Comprehensive migration guide; deprecation warnings; support channel |
| Documentation incomplete | Medium | Medium | Parallel doc work; review at each phase |
| Adoption resistance | Low | Medium | Clear value proposition; easy migration path |
For Breaking Changes:
For Test Coverage:
For Documentation:
Track file movements across phases:
## Phase 1: Core
- [ ] src/boundary/shared/core/validation/* → libs/core/src/boundary/core/validation/
- [ ] src/boundary/shared/core/utils/* → libs/core/src/boundary/core/utils/
- [ ] src/boundary/shared/core/interceptor.clj → libs/core/src/boundary/core/
- [ ] src/boundary/shared/core/interceptor_context.clj → libs/core/src/boundary/core/
- [ ] src/boundary/shared/core/config/* → libs/core/src/boundary/core/config/
- [ ] test/boundary/shared/core/* → libs/core/test/boundary/core/
## Phase 2: Observability
- [ ] src/boundary/logging/* → libs/observability/src/boundary/observability/logging/
- [ ] src/boundary/metrics/* → libs/observability/src/boundary/observability/metrics/
- [ ] src/boundary/error_reporting/* → libs/observability/src/boundary/observability/errors/
- [ ] test/boundary/logging/* → libs/observability/test/boundary/observability/logging/
- [ ] test/boundary/metrics/* → libs/observability/test/boundary/observability/metrics/
- [ ] test/boundary/error_reporting/* → libs/observability/test/boundary/observability/errors/
...
Complete mapping for automated migration:
{;; Core
"boundary.shared.core.validation" "boundary.core.validation"
"boundary.shared.core.utils.case-conversion" "boundary.core.utils.case-conversion"
"boundary.shared.core.utils.type-conversion" "boundary.core.utils.type-conversion"
"boundary.shared.core.utils.pii-redaction" "boundary.core.utils.pii-redaction"
"boundary.shared.core.interceptor" "boundary.core.interceptor"
"boundary.shared.core.interceptor-context" "boundary.core.interceptor-context"
"boundary.shared.core.config.feature-flags" "boundary.core.config.feature-flags"
;; UI
"boundary.shared.ui.core" "boundary.ui.core"
;; Observability
"boundary.logging" "boundary.observability.logging"
"boundary.metrics" "boundary.observability.metrics"
"boundary.error-reporting" "boundary.observability.errors"}
Project Lead: [Name]
Email: [Email]
Slack: #boundary-dev
GitHub: https://github.com/boundary/boundary
For Questions:
Document Version: 1.0
Last Updated: 2026-01-18
Next Review: After Phase 3 completion
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |