Changelog
All notable changes to ShipClojure-Datom will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
Added
- RSS feed at
/blog/feed.xml: Blog posts are now published as a valid RSS 2.0 feed, enabling submission to feed aggregators like Planet Clojure- Full RSS 2.0 with
atom:linkself-reference for feed validator compliance - Each item includes title, link, guid, description, publication date, author, and category tags
- Feed is excluded from the sitemap
- RSS auto-discovery
<link>tag added to the HTML<head>for browser and feed reader detection
- Full RSS 2.0 with
- Multi-instance development: Run multiple dev instances in parallel via git worktrees with unique port blocks
bb prepare-instance [seed]— computes a contiguous block of 9 ports from a numeric seed and writes overrides todeps.local.ednbb list-instances— shows all git worktrees with their configured ports--docker-overrideflag generatesdocker-compose.override.ymlfor fully isolated Docker containers (unique names, volumes, network)- Seed can be a number, ticket ID (
SC-1234), branch name, or auto-detected from current git branch - Conflict detection: scans worktree configs + TCP-probes before assigning ports
- See
docs/multi-instance.mdfor full documentation
- Automatic port conflict detection:
bb devnow checks if default ports are already in use (e.g. by another project) and automatically finds free alternatives at startup — no configuration required - Dev configuration summary:
bb devprints a clear startup banner showing services, browsable URLs, and all port assignments :dev/optionsindeps.edn: project-specific dev configuration (:docker-compose, port overrides) merged fromdeps.edn(defaults) anddeps.local.edn(local overrides, takes priority)- Docker Compose auto-detection:
:docker-composeoption in:dev/optionswith three modes —:auto(default, probes PostgreSQL + Transactor ports),true(always start),false(never start) - Service identity verification: Zero-dependency protocol-aware probes for PostgreSQL (SSLRequest wire protocol) and Datomic transactor (HTTP
/healthendpoint) — detects when ports are occupied by wrong services. Post-startup verification confirms services started correctly with retries and clear error messages. - Datomic transactor health port: Container health endpoint (internal 9999) mapped to host port 4335 via
DEV_TRANSACTOR_HEALTH_PORTfor protocol-level health checking
Changed
bin/launchpadrefactored: reads:dev/optionsfrom bothdeps.ednanddeps.local.edn(usinglaunchpad/maybe-read-edn), injectsDEV_*env vars for child processes, resolves ports and docker-compose status before printing a configuration summaryshadow-cljs.edn: ports now configurable via#shadow/envreader tags (DEV_SHADOW_NREPL_PORT,DEV_SHADOW_HTTP_APP_PORT,DEV_SHADOW_HTTP_PORTFOLIO_PORT)docker-compose.yml: service ports now use${DEV_*:-default}env var substitution for PostgreSQL, Memcached, and Datomic Transactor
Security
- npm audit fixes: Resolved 4 audit vulnerabilities by upgrading direct dependencies
katex0.12.0→0.16.28— fixes URL protocol bypass, unescaped filenames, unvalidated attributes, maxExpand bypass (4 moderate)markdown-it14.1.0→14.1.1— fixes ReDoS vulnerability (moderate)@isaacs/brace-expansion— transitive fix vianpm audit fix(high)tar— transitive fix via@tailwindcss/cliupgrade (high)- Remaining 5 high-severity warnings are unfixable transitive deps from
@chrisoakman/standard-clojure-style(dev-only)
Changed
- Dependency Updates (npm):
apexcharts5.3.4→5.6.0punycode2.1.1→2.3.1@tailwindcss/cli4.1.14→4.2.0@tailwindcss/postcss4.0.12→4.2.0tailwindcss4.1.14→4.2.0daisyui5.1.29→5.5.19prettier3.2.5→3.8.1prettier-plugin-tailwindcss0.6.11→0.6.14shadow-cljs3.1.8→3.3.6snabbdom3.5.1→3.6.3
Fixed
- Fixed custom field schema for payment checkout
- Theme system: Fixed "System" theme not correctly respecting
prefers-color-schemeset-dom-theme-attribute!now removesdata-themefor:system/nil(instead of settingdata-theme="system") so the OS media query applies naturally; also correctly removes thedarkclass when switching away from dark themes- FOUC prevention inline scripts in
saas.ui.layout.coreandsaas.ui.layoutsnow removedata-themefor system/absent theme instead of defaulting to"light" content.jsfixed: uses correct localStorage key ("theme"instead of"saas.theme/theme") and properly removesdata-themefor system modedaisyui.css: customlighttheme markeddefault: trueand customdarktheme markedprefersdark: trueso system mode uses the app's own branded themes rather than daisyUI's built-in defaults- App state now hydrated from localStorage on boot (
saas.core/init!andsaas.landing/init!) so the theme dropdown reflects the saved preference immediately on load - Extracted duplicated FOUC prevention script into
saas.ui.layout.core/theme-init-scriptdef, shared across both layout namespaces - Make
cljc/saas/ui/components/render-theme-dropdownfully support server rendering through CSS selective rendering of the correct theme
[1.0.0] - 2026-02-08
Security
- Token Tampering Detection: Enhanced authentication validation to detect and prevent token tampering
- Implemented
invalidate-token-family!function that clears all refresh tokens for a user when tampering is detected - Token signature mismatch now triggers immediate family invalidation and logs security warning
- Both commands and queries now validate refresh token pairing when present in session
- Updated authentication documentation to explain token tampering detection and family invalidation
- Implemented
Changed
- Environment Lifecycle: Consistent use of
env/defaults:init,:start, and:stopfunctionssaas.core/-mainnow calls:initbefore startup for proper logging configurationsaas.devruns:initon namespace load and calls:start/:stopin reset/halt functionsuser.cljnow reuses integrant functions fromsaas.devinstead of duplicating them- Moved
virgil/watch-and-recompileand*warn-on-reflection*setup into dev env:init
- Logging Upgrade: Upgraded Telemere from 1.0.0-RC5 to 1.2.0
- Added
telemere-slf4jas the SLF4J backend, routing all SLF4J logs through Telemere - Removed
logback-classicdependency in favor of unified Telemere logging - Excluded
slf4j-nopfrom Powerpack to resolve SLF4J provider conflicts - Migrated all logback.xml configurations to Telemere
set-min-level!calls in env.clj files - Added
configure-dev-log-levels!,configure-prod-log-levels!, andconfigure-test-log-levels!functions - Removed all
logback.xmlfiles (dev, prod, test) - logging now fully managed by Telemere
- Added
- Changed
/auth/log-inhandler schema to be aligned with rest of the handlers.:password, :email->:user/password,:user/email - Changed transit serialization between client and server to use
jsonin production andjson-verbosein development for easier debugging locally - Muuntaja instance is now created per-environment via
create-instancefunction, injected through Integrant instead of a static def - Upgraded Datomic peer from 1.0.7364 to 1.0.7387
- Upgraded replicant to v2025.12.1
Added
Organisation Support
Multi-tenant organisation system with role-based membership and optimised query performance.
- New
organisationschema withid,name,slug, andmembershipsattributes - New
membershipschema linking users to organisations with roles (owner,admin,member) - Automatic personal organisation creation on user registration (name: "My Organisation", slug: username)
- Users become
ownerof their personal organisation - New
saas.datomic.organisationnamespace with implicit partition utilitiesorg/tempid- creates tempids in the org's partition for index localityorg/org-partition- returns the implicit partition for an org ID
- New
u/->slugfunction for URL-friendly string conversion - Member invitation system:
invite-member,accept-invitation,reissue-invitationcommands with invitation schema attributes (:org.invitation/token,:org.invitation/email,:org.invitation/role, etc.) - Member management:
remove-memberandupdate-member-rolecommands for managing organisation members get-organisationquery: returns organisation details with members and their rolesregister-membercommand: allows invited users to register without email verification- Organisation invitation email template: new email template for inviting users to join an organisation
- Organisation settings page: full UI for managing org details, inviting members, and updating roles
- Accept invite page: UI for accepting organisation invitations via token link
:query/get-accountreturns:user-account/role: the user's membership role within their organisation is now included in the account response- [DOCS] Added documentation for organisations:
docs/backend/organisations.md
Breaking Changes:
- Removed
db.part/accountpartition - use implicit partitions viaorg/tempidinstead
Route-Level Role-Based Access Control
Defence-in-depth authorisation enforced on both frontend and backend.
- Declarative
:auth/rolesmetadata on routes restricts access by membership role routes/required-roleshelper to look up role requirements for any route- Forbidden page: access denied screen shown when a user lacks the required role
- CQRS role enforcement: commands/queries support
:command/required-roles/:query/required-roles— middleware checks the user's role and returns 403 if insufficient - Sidebar role filtering: dashboard sidebar items are automatically hidden when the user's role doesn't match the route's
:auth/roles - New
subs/user-rolesubscription reads the user's membership role from DataScript
Other Additions
- Support for ruby & kamal through mise for consistent version
docker-compose.ymlfor easy local development. See Getting Started for more details. It contains:- PostgreSQL storage for Datomic
- Datomic transactor service
- Datomic console
- Memcache for caching consistent with production setup
- Better logging context. Each request adds in the logging context the following:
request-method,uri,request params- with obfuscation of sensitive data, userclaimsinfo. - launchpad support for streamlined development experience across all editors!
- [DOCS] Better getting started documentation for new users.
- [DOCS] Better docs for Repl Workflow and local customization options
- [DOCS] Added docs on logging and log configuration
- stripe-cli to be installed through mise
- Reitit request coercion support for route definitions
- Nexus
:event/target.checkedplaceholder to gettrue|falsevalue from a checkbox dom event - Tests for onboarding page
- Show correct initials in avatar when user is registering through normal onboarding
- Added support for
data-type "uuid"for forms. This will automatically send the input's content asuuid select-fieldandselectform components: new form components insaas.formsfor dropdown selects with automatic keyword value serializationprepare-form-input-argshelper insaas.forms: auto-clears field validation errors on user input for better UX- Test-only session handler:
test-set-sessionhandler to simulate session-setting flows (OAuth2, etc.) in integration tests - [DOCS] Added UI pages documentation:
docs/frontend/ui-pages.md— guide for creating pages with the standard page pattern
Removed
- Removed emacs specific configuration. It's now handled by launchpad
- ShadowCLJS & CSS Watch integrant component logic - It's now handled by launchpad
:nreplalias from deps.edn - replaced by usage of launchpad
Fixed
- Fixed 404 page requests not returning correct not found screen
- Fixed crash on
:actions/clear-refresh-tokenwhen user was not found - Show "Username taken" server error on
/complete-registerroute - Fixed bug where
command/refresh-tokenwould go in a loop when accessing authenticated routes without a session - Fixed arrow icon not expanding in dashboard sidebar when element was selected
- Fixed queries & commands not merging under the same log if different token or options were used
[0.1.0]
Added
- CRM Dashboard Page: New Customer Relationship Management dashboard with sample data and charts
- DaisyUI Progress Component: Added progress bar component with comprehensive Portfolio scenes
- Structured JSON Logging: Production-ready structured logging with request ID tracking
- Automatic daily rotation with gzip compression
- 30-day retention policy
- One JSON object per line for easy parsing with
jq - Request tracing across all operations
- Kamal Log Utilities: Added Kamal aliases for easy log parsing and error tracking
kamal json-logs-errors- View all error logskamal json-logs-latest- View latest 100 logskamal json-logs-today- View today's logs
- Sitemap Generation: Automatic sitemap.xml generation for static pages and blog posts
- Enhanced Security: Query response filtering to exclude sensitive data
- Password hashes no longer returned in
:query/get-account - Refresh tokens excluded from account queries
- Password hashes no longer returned in
- Test Coverage: Added comprehensive tests for
:query/get-accountendpoint
Changed
- Icon System Migration: Complete migration from Lucide icons to Phosphor icons
- Removed 108+ individual SVG files (resources/icons/*)
- Eliminated custom icon build system (src/bb/build_icons.clj)
- Reduced bundle size and improved performance
- Simplified icon usage via
no.cjohansen/phosphor-cljlibrary - Updated all UI components, Portfolio scenes, and tests
- Dependency Updates:
- Upgraded Clojure from 1.12.1 to 1.12.3
- Updated standard-clojure formatter to 0.25.0
- Updated Virgil from 0.4.0 to 0.5.0
- Current stack: Replicant 2025.06.21, Nexus 2025.07.1, Powerpack 2025.06.16
- Docker Configuration:
- Added
jqto runtime for JSON log parsing - Optimized persistent data locations
- Fixed production build process
- Added
- Static Asset Handling: Enhanced Powerpack middleware to serve generated resources (sitemap.xml)
- Page Routing: Separated static pages from SPA routes for better SEO and performance
Fixed
- Frontend Build: Resolved build issues related to icon system migration
- Unit Tests: Fixed all tests affected by new icon system
- Sidebar Tests: Updated component tests for Phosphor icon integration
- Kamal Logging: Fixed log alias commands for production monitoring
- Dockerfile: Resolved build issues with content copying and optimization
- Integrant: Removed deprecated integrant calls in production logging setup
- Settings Pages: Fixed styling and icon display issues
Removed
- Lucide Icons: Completely removed legacy Lucide icon system
- Deleted 108+ SVG icon files
- Removed
src/bb/build_icons.cljicon build script - Removed
src/cljc/saas/ui/icons.cljcicon namespace - Cleaned up icon-related build tasks from
bb.edn
- Legacy Code: Removed code supporting old icon system
Documentation
- Updated icon usage guide in
docs/frontend/icons.md - Updated PROJECT_SUMMARY.md with latest architecture details
- Enhanced deployment documentation with structured logging information
Performance
- Reduced Package Dependencies: Significant reduction in npm package-lock.json size (2872 fewer lines)
- Smaller Bundle Size: Icon migration reduced frontend asset size
- Optimized Asset Delivery: Improved static content serving for production
Security Enhancement
If your code relies on receiving password hashes or refresh tokens from :query/get-account, note that these are now filtered out for security. Use dedicated endpoints for authentication operations.
Version History
This is the initial CHANGELOG for ShipClojure-Datom. Previous changes were tracked via git commits.
For detailed commit history, run:
git log --oneline --decorate