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/tick dependency — replaced with a lightweight saas.utils.time namespace backed by pure java.time interop. This eliminates the time-literals vs java-time-literals data-reader conflict that prevented adding Datomic/Powerpack to the project. All t/now, t/instant, t/>>, t/new-duration calls across auth, payments, and DB layers have been migrated to time/now, time/->instant, time/add-seconds, etc.
  • quickblog dependency — replaced by the new Powerpack-based blog system. Removed quickblog/config integrant key, bb quickblog and bb release-blog tasks.

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/markdownhiccup2.core/html with 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, and content.js for 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/app creates an in-memory Datomic DB, ingests all content, and serves pages dynamically via wrap-serve-powerpack-pages middleware
    • Prod environment: pages pre-exported as static HTML via bb build:contentbb copy:content, served from the classpath via wrap-index-html-serving middleware
    • Export pipeline: bb build:content runs Powerpack export (requires frontend assets built first), bb copy:content copies HTML/XML to resources/public/, bb release-content orchestrates both (depends on release-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) via format-date helper instead of raw Date.toString()
    • Theme toggle IDs: added id="dropdown-theme-button-{light,dark,system}" to ssr-theme-toggle-dropdown so content.js can wire click handlers on SSR blog pages
  • Tailwind Typography plugin — added @plugin "@tailwindcss/typography" to tailwind.css for proper prose class support (heading sizes, list styles, link colors, code blocks)
  • saas.utils.time/->instant — polymorphic coercion function (Instant passthrough, epoch millis, java.util.Date) replacing tick/t/instant

Changed

  • Ring middleware orderwrap-asset-optimization now runs before wrap-serve-powerpack-pages so :optimus-assets is populated when content pages render
  • CSS font loading — removed @import url(...) for Google Fonts from typography.css (render-blocking, rejected by Optimus); fonts already loaded via <link> tags in HTML layouts
  • CSS asset path — fixed landing.css to reference /assets/images/landing/footer-grainy.png (was /images/landing/ without assets/ 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 into deps.local.edn
    • bb prepare-instance:worktree --branch <name> — creates a git worktree and configures it in one step
    • bb list-instances — lists all active worktrees and their port allocations
    • bin/launchpad port injection — reads :dev/options from deps.local.edn at startup and injects DEV_PG_PORT, POSTGRES_PORT, DEV_SHADOW_*, and PORT env vars so every child process (docker-compose, shadow-cljs, http-kit) uses the correct ports
    • docker-compose.yml postgres port parameterised via ${DEV_PG_PORT:-5432} for per-instance isolation
    • shadow-cljs.edn nREPL and dev-http ports now driven by DEV_SHADOW_* env vars (with fallback defaults) so two instances can run shadow-cljs simultaneously without conflicts
    • src/bb/port_injection.clj — shared bb utility that reads :postgres-port from deps.local.edn and provides effective-env for any task that invokes clj directly
    • bb test injects POSTGRES_PORT automatically so tests connect to the correct database in any worktree
    • docker-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-name written into deps.local.edn for non-isolated mode so all worktrees share the same docker compose project and postgres_data volume
    • Colorized dev startup summary on bb dev showing 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-details accordion
    • Full-bleed CTA section with background image overlay
    • Footer with links, legal, and copyright

Changed

  • Reorganized .dockerignore by category and explicitly exclude .secrets.edn files from Docker images
  • Replace realistic-looking default secrets in secrets.example.edn with obvious REPLACE_WITH / CHANGE_ME placeholders to prevent accidental production use
  • Fix secrets.example.edn placeholder 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 removes data-theme attribute for :system theme (instead of setting it), allowing the browser's prefers-color-scheme media 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 :system keyword identically to nil — removes the "theme" key from localStorage rather 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 removes data-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 :system keyword (instead of nil) 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): Added saas.db.events, saas.db.subs, and saas.local-storage.re-frame requires so theme toggle and re-frame subscriptions function correctly after client-side hydration
  • Bump @chrisoakman/standard-clojure-style 0.25 → 0.27 (npm security audit)

Fixed

  • Return 409 Conflict instead of 500 when 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.exception and saas.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 Authorization header to avoid leaking into logs, browser history, and Referer headers
  • Hide exception class names from 500 error responses to avoid leaking internal implementation details
  • Require explicit allowed-origin patterns in wrap-cors instead 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.exception as a proper ring wrapper
    • Simplified route-level middleware - routes now only define route-specific middleware
  • API Documentation: Switched from Swagger 2.0 to OpenAPI 3.0
    • Changed endpoint from /swagger.json to /openapi/openapi.json
    • Updated Swagger UI path from /api to /openapi
  • Server Configuration: Added profile-based server config with nil for test environment to skip HTTP server startup
  • Sente: Updated to use sente-transit/get-packer (renamed from deprecated get-transit-packer)
  • Logging Upgrade: Upgraded Telemere from 1.0.0-RC5 to 1.2.0
    • Add log context for each API request
    • Added telemere-slf4j as the SLF4J backend, routing all SLF4J logs through Telemere
    • Removed logback-classic dependency in favor of unified Telemere logging
    • Excluded logback-classic from 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!, and configure-test-log-levels! functions
    • Removed all logback.xml files (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_icons script to use clojure.data.xml instead of bootleg pod
  • Removed required linux/amd64 platform 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-clj alias 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.