Changelog
All notable changes to ShipClojure will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
Removed
tick/tickdependency — replaced with a lightweightsaas.utils.timenamespace backed by purejava.timeinterop. This eliminates thetime-literalsvsjava-time-literalsdata-reader conflict that prevented adding Datomic/Powerpack to the project. Allt/now,t/instant,t/>>,t/new-durationcalls across auth, payments, and DB layers have been migrated totime/now,time/->instant,time/add-seconds, etc.quickblogdependency — replaced by the new Powerpack-based blog system. Removedquickblog/configintegrant key,bb quickblogandbb release-blogtasks.
Added
- Powerpack-based blog & content system — full static-site blog with server-side rendered UIX components, replacing quickblog:
- Content ingestion via Powerpack + in-memory Datomic: blog posts in mapdown format (
content/blog-posts/), authors (content/authors/), and static pages (content/static-pages.edn) - Auto-generated pages: tag pages, author pages, sitemap.xml, and RSS feed created automatically from ingested content
- UIX blog components (
src/cljc/saas/content/ui/): blog listing with featured post hero, blog article with sticky TOC sidebar, tag cloud, author profile, generic article (ToS, Privacy), responsive navbar, newsletter signup card — all DaisyUI-styled - Markdown rendering via
nextjournal/markdown→hiccup2.core/htmlwith Prism.js syntax highlighting and custom code block captions - Content layout system (
layout.cljc): base and content layouts with full Open Graph / Twitter Card meta tags, RSS auto-discovery, theme init script, Safari mask-icon, andcontent.jsfor theme switching + TOC scroll highlighting + smooth scrolling - Optimus asset optimization (
assets.clj): cache-busted static assets (images, CSS, JS) with fingerprinted URLs, integrated into Ring middleware chain - Dev environment:
ig/init-key :powerpack/appcreates an in-memory Datomic DB, ingests all content, and serves pages dynamically viawrap-serve-powerpack-pagesmiddleware - Prod environment: pages pre-exported as static HTML via
bb build:content→bb copy:content, served from the classpath viawrap-index-html-servingmiddleware - Export pipeline:
bb build:contentruns Powerpack export (requires frontend assets built first),bb copy:contentcopies HTML/XML toresources/public/,bb release-contentorchestrates both (depends onrelease-frontend) - Static pages: Privacy Policy and Terms of Service with AI prompt comments for easy customization
- Portfolio scenes: blog card, featured post, blog listing, blog article, author page — all with sample data for visual development
- Date formatting: human-readable dates (
June 15, 2024) viaformat-datehelper instead of rawDate.toString() - Theme toggle IDs: added
id="dropdown-theme-button-{light,dark,system}"tossr-theme-toggle-dropdownsocontent.jscan wire click handlers on SSR blog pages
- Content ingestion via Powerpack + in-memory Datomic: blog posts in mapdown format (
- Tailwind Typography plugin — added
@plugin "@tailwindcss/typography"totailwind.cssfor properproseclass support (heading sizes, list styles, link colors, code blocks) saas.utils.time/->instant— polymorphic coercion function (Instant passthrough, epoch millis, java.util.Date) replacingtick/t/instant
Changed
- Ring middleware order —
wrap-asset-optimizationnow runs beforewrap-serve-powerpack-pagesso:optimus-assetsis populated when content pages render - CSS font loading — removed
@import url(...)for Google Fonts fromtypography.css(render-blocking, rejected by Optimus); fonts already loaded via<link>tags in HTML layouts - CSS asset path — fixed
landing.cssto reference/assets/images/landing/footer-grainy.png(was/images/landing/withoutassets/prefix)
Added
- Multi-Instance Dev Support — run multiple dev instances in parallel (git worktrees, parallel coding agents):
bb prepare-instance [seed]— allocates a stable 6-port block from a numeric seed (ticket ID, branch name hash, or explicit integer) and writes port overrides intodeps.local.ednbb prepare-instance:worktree --branch <name>— creates a git worktree and configures it in one stepbb list-instances— lists all active worktrees and their port allocationsbin/launchpadport injection — reads:dev/optionsfromdeps.local.ednat startup and injectsDEV_PG_PORT,POSTGRES_PORT,DEV_SHADOW_*, andPORTenv vars so every child process (docker-compose, shadow-cljs, http-kit) uses the correct portsdocker-compose.ymlpostgres port parameterised via${DEV_PG_PORT:-5432}for per-instance isolationshadow-cljs.ednnREPL and dev-http ports now driven byDEV_SHADOW_*env vars (with fallback defaults) so two instances can run shadow-cljs simultaneously without conflictssrc/bb/port_injection.clj— shared bb utility that reads:postgres-portfromdeps.local.ednand provideseffective-envfor any task that invokescljdirectlybb testinjectsPOSTGRES_PORTautomatically so tests connect to the correct database in any worktreedocker-compose.override.yml(generated with--docker-override) gives an instance a dedicated postgres container, volume, and network; port binding omitted from the override to avoid Docker double-binding errors:docker-project-namewritten intodeps.local.ednfor non-isolated mode so all worktrees share the same docker compose project andpostgres_datavolume- Colorized dev startup summary on
bb devshowing services checklist, open-in-browser URLs, and full port table; highlights ⚡ Multi-Instance Mode when port overrides are active docs/development/multi-instance.md— full documentation covering quick start, data flow, port allocation, configuration details, and test/worktree usage
- Improved Landing Page (
src/cljc/saas/common/ui/pages/landing.cljc)- Scroll-aware sticky topbar with mobile drawer, desktop navigation, theme toggle dropdown, and CTA button
- Hero section with headline, subheadline, CTA button, social proof avatars, and responsive light/dark hero screenshots
- Problem section with 3-step visualization and connecting arrow SVGs
- Features section with interactive accordion selector and feature media panel
- Testimonial section with photo, pull quote, and attribution
- 3-tier pricing section (Starter / Professional / Enterprise) with animated popular badge and feature lists
- FAQ section using collapsible daisyUI
collapse-detailsaccordion - Full-bleed CTA section with background image overlay
- Footer with links, legal, and copyright
Changed
- Reorganized
.dockerignoreby category and explicitly exclude.secrets.ednfiles from Docker images - Replace realistic-looking default secrets in
secrets.example.ednwith obviousREPLACE_WITH/CHANGE_MEplaceholders to prevent accidental production use - Fix
secrets.example.ednplaceholder values to conform to required length and format constraints (cookie secret was 47 bytes instead of 16; JWT/TOTP placeholders had invalid formats) so test startup no longer fails on a fresh checkout - Theme system — system/OS preference support (
src/cljs/saas/db/events.cljs)::dom/set-theme!effect now removesdata-themeattribute for:systemtheme (instead of setting it), allowing the browser'sprefers-color-schememedia query to control the theme naturally:dom/set-theme!now removes the"dark"CSS class when switching away from dark themes, not just adds it:theme/set!event treats:systemkeyword identically tonil— removes the"theme"key fromlocalStoragerather than persisting"system"as a string
- FOUC prevention script (
src/clj/saas/web/pages/layout.clj): Inline<script>in<head>now checks for absent or"system"value and removesdata-theme(so OS preference applies) instead of always defaulting to"light" - Theme dropdown system option (
src/cljc/saas/common/ui/theme.cljc): System option now dispatches:systemkeyword (instead ofnil) for consistency with the updated event handler; highlight condition updated to(#{:system nil} theme) - Landing page hydration entry point (
src/cljs/saas/ui/ssr_pages/landing.cljs): Addedsaas.db.events,saas.db.subs, andsaas.local-storage.re-framerequires so theme toggle and re-frame subscriptions function correctly after client-side hydration - Bump
@chrisoakman/standard-clojure-style0.25 → 0.27 (npm security audit)
Fixed
- Return
409 Conflictinstead of500when a user attempts OAuth2 onboarding with an email that already exists; adds a pre-flight existence check and a PSQLException safety-net catch for race conditions; the frontend onboarding form now displays the server error message in a red alert banner - Fix indentation in
saas.web.middleware.exceptionandsaas.web.middleware.formats
Security
- Run Docker runtime stage as a dedicated non-root user (
appuser, UID 1001) - Add payload validation to WebSocket example handler — reject non-string payloads and enforce a 16 KiB maximum message size
- Remove access token extraction from query parameters — tokens must be passed via the
Authorizationheader to avoid leaking into logs, browser history, andRefererheaders - Hide exception class names from 500 error responses to avoid leaking internal implementation details
- Require explicit allowed-origin patterns in
wrap-corsinstead of allowing all origins
[1.0.0] - 2025-12-14
Added
- Docker Compose setup for local PostgreSQL development (image is for Postgres 18.1)
- Database initialization script with user segregation (DDL, DML, and read-only users)
- Separate databases for testing & development
- CI/CD database setup in GitHub Actions workflow
- launchpad support for streamlined development experience across all editors!
- [DOCS] Better docs for REPL Workflow and local customization options
- [DOCS] Better docs on getting started with the project
- [DOCS] Better docs on secret management
- [DOCS] New docs for logging support in shipclojure
- [DOCS] New Ring API documentation explaining middleware chain and request lifecycle
Removed
- Removed emacs specific configuration (.dir-locals.el). It's now handled by launchpad
- ShadowCLJS & CSS Watch integrant component logic - It's now handled by launchpad
Changed
- Middleware Architecture Refactoring: Aligned with shipclojure-datom stack by moving middleware from reitit router level to ring handler level
- Split handler into
:handler/reitit(routing) and:handler/ring(middleware chain) - Moved request/response formatting, logging, and exception handling to ring handler level
- Created custom exception middleware in
saas.web.middleware.exceptionas a proper ring wrapper - Simplified route-level middleware - routes now only define route-specific middleware
- Split handler into
- API Documentation: Switched from Swagger 2.0 to OpenAPI 3.0
- Changed endpoint from
/swagger.jsonto/openapi/openapi.json - Updated Swagger UI path from
/apito/openapi
- Changed endpoint from
- Server Configuration: Added profile-based server config with
nilfor test environment to skip HTTP server startup - Sente: Updated to use
sente-transit/get-packer(renamed from deprecatedget-transit-packer) - Logging Upgrade: Upgraded Telemere from 1.0.0-RC5 to 1.2.0
- Add log context for each API request
- Added
telemere-slf4jas the SLF4J backend, routing all SLF4J logs through Telemere - Removed
logback-classicdependency in favor of unified Telemere logging - Excluded
logback-classicfrom kit-core to avoid conflicts with telemere - 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 JSON file logging support for production with
add-json-file-handler!
- Move dev only files to dev/
- Changed
build_iconsscript to use clojure.data.xml instead of bootleg pod - Removed required
linux/amd64platform in docker required by bootleg. MacOS docker builds should be faster - Renames saas-secrets.example.edn -> resources/secrets.example.edn and equivalent
.{dev|prod}-secrets.edn->resources/.secrets.edn. For production, secrets should come from environment variables - Add support for environment var based secrets in
secrets.examples.edn - Upgrade deps:
- uix sha from past -> 1.4.8
- react 19.0.0 -> 19.2.0
- clojure 1.12.0 -> 1.12.1
- clojurescript 1.12.35 -> 1.12.134
- shadow-cljs 3.0.4 -> 3.3.4
- portfolio 2024.09.25 -> 2025.11.2
- integrant: 0.12.0 -> 1.0.1 (MAJOR version bump - required change addressed)
- honeysql 2.4.969 -> 2.7.1350
- postgresql 42.5.1 -> 42.7.7
- hikari-cp 3.0.1 -> 3.3.0
- migratus 1.4.3 -> 1.6.4
- reitit 0.7.2 -> 0.9.2
- http-kit 2.8.0 -> 2.8.1
- ring 1.13.0 -> 1.15.3
- ring-defaults 0.6.0 -> 0.7.0
- sente 1.20.0 -> 1.21.0
- stripe-clojure 0.2.2 -> 1.0.0 (no BREAKING changes in shipclojure usage. See stripe-clojure CHANGELOG for more details)
- integrant-repl 0.4.0 -> 0.5.0
- tailwindcss 4.0.12 -> 4.1.14
- @tailwindcss/typography 0.5.15 -> 0.5.19
- @tailwindcss/cli (new)
- daisyui 5.0.16 -> 5.1.29
- @chrisoakman/standard-clojure-style 0.18.0 -> 0.25.0
- Removed
:cider-cljalias from deps.edn (CIDER setup now handled by launchpad) - Upgrade mise tools (.mise.toml):
- java temurin-21.0.2+13.0.LTS -> temurin-25.0.1+8.0.LTS
- clojure 1.12.0.1530 -> 1.12.3
- babashka 1.12.197 -> 1.12.209
- clj-kondo 2025.02.20 -> 2025.10.23
- node 22 -> 24.11.1
- standard-clojure-style (new)
- stripe CLI (new)
- [DOCS] Updated llm uix docs
Fixed
- Build watching logic for portfolio development
- CSS error not adding classes to dropdown components
[0.1.0] - 2025-05-07
Added
- Frontend development task and documentation
- Open Graph and social preview metadata for SEO
- YouTube demo video
- AI development documentation
- Countdown UI component with portfolio scenes
- Development REPL babashka task
Changed
- Bumped Clojure, ClojureScript, and Shadow-CLJS versions
- Updated tools.build to use Maven version
- Improved build process and dependency management
Fixed
- CSS compilation on initial launch
- Build issues after JavaScript dependency changes
- Getting started documentation
[0.1.0-alpha] - 2025-04-29
Added
- Role-Based Access Control (RBAC)
- User roles and permissions system
- Database seeding for initial roles and permissions
- Middleware for role-based route protection
- Admin routes for user management
- User management UI with role assignment
- Stripe Payment Integration
- Product and price management
- Checkout session creation
- Webhook handlers for Stripe events
- One-time and subscription payment support
- Payment tables and migrations
- OAuth2 Authentication
- Google OAuth2 provider integration
- PKCE (Proof Key for Code Exchange) support
- OAuth2 redirect handling with HTTPS support
- Frontend Enhancements
- Dashboard with authentication requirements
- Settings pages with breadcrumb navigation
- Lazy loading for images on landing pages
- Theme persistence across page reloads
- Logo component improvements
- Link to documentation and blog
Changed
- Refactored payment database schema
- Migrated from plans to Stripe products and prices
- Improved frontend routing with redirect functionality
- Enhanced secret management system
- Reitit-style middleware implementation throughout
- Improved test suite performance (single system setup)
Fixed
- Refresh token functionality
- OAuth redirect to use HTTPS correctly outside localhost
- Checkbox toggling on registration form
- Logo and navigation overlap issues
- Logout button on dashboard
- User fetching on Google login
- Security middleware wrapping order
- CSRF protection for authenticated requests
Security
- Added SSL mode support for database connections
- Implemented proper secret management for production
- Fixed role-permission foreign key constraints
[0.0.1] - 2023-05-17
Added
- Initial Release
- Integrant-based system management
- Reitit routing
- PostgreSQL database with HikariCP connection pooling
- Database migrations with Migratus
- Cookie-based session authentication
- User account creation and management
- Basic frontend with Shadow-CLJS
- Dark mode support
- UI component library
- CircleCI configuration
- Docker deployment setup
- Basic authentication routes
Infrastructure
- Initial CircleCI CI/CD pipeline
- Dockerfile for containerized deployment
- Database migration runner in Integrant lifecycle
Version History Summary
- 0.0.1 (May 2023) - Initial release with basic authentication and infrastructure
- 0.1.0-alpha (April 2025) - Major feature additions: RBAC, Stripe payments, OAuth2
- 0.1.0 (May 2025) - Stability improvements, documentation, dependency updates
- 1.0.0 (Dec 2025) - Docker dev environment, middleware refactoring, major dependency upgrades, OpenAPI 3.0
- Unreleased (Feb 2026) - Theme system OS-preference support, improved landing page
Versioning Strategy
This project follows Semantic Versioning:
- MAJOR version for incompatible API changes
- MINOR version for new functionality in a backwards compatible manner
- PATCH version for backwards compatible bug fixes
Pre-release versions use suffixes like -alpha, -beta, -rc1 for unstable releases.