Outerstellar Platform
A full-stack Kotlin platform template — multi-module architecture with observability, security, type-safe configuration, a JTE web layer, and a Swing desktop client.
Outerstellar Platform
A multi-module Kotlin project template with HTTP4k web and Swing desktop frontends, jOOQ/JDBI persistence, OpenTelemetry tracing, Micrometer metrics, and RBAC security. Intended as a starting point for new applications rather than a framework to depend on.
How is the platform structured?
Seven modules with explicit dependency boundaries:
| Module | Responsibility | Dependencies |
|---|---|---|
platform-core | Domain models, service interfaces, business logic | Kotlin stdlib |
platform-persistence-jooq | Type-safe SQL, Flyway migrations, Caffeine caching | jOOQ, Flyway, Caffeine |
platform-persistence-jdbi | JDBI alternative to the jOOQ module | JDBI 3, Flyway |
platform-sync-client | Shared DTOs and HTTP client for component sync | HTTP4k client |
platform-security | Auth models, RBAC, permissions, multi-realm auth | — |
platform-web | HTTP4k server, JTE templates, HTMX | HTTP4k, JTE |
platform-desktop | Swing MVVM desktop client | FlatLaf, MigLayout |
Module Dependencies
platform-core ←── platform-security
↑ ↑
│ │
platform-persistence-* │
↑ │
│ │
platform-web ─────────────┘
platform-desktop ──────────┘
platform-core has no framework dependencies. Domain logic is testable without a server or database.
What patterns does the platform use?
Transactional Outbox
Background tasks and sync events are written to an outbox table in the same transaction as the domain change, then processed asynchronously. Avoids distributed transactions.
Contract-First API
Routes defined via http4k-contract produce an OpenAPI spec that stays in sync with the code:
"/api/v1/projects" meta {
summary = "List all projects"
returning(Status.OK, projectListLens to listOf(sampleProject))
} bindContract GET to { _ -> Response(Status.OK).with(projectListLens of projects) }
Configuration
Hoplite maps YAML, environment variables, and system properties to data classes. Environment-specific overrides use APP_PROFILE:
data class DatabaseConfig(
val url: String,
val username: String,
val password: String,
val maxPoolSize: Int = 10
)
# application.yaml
database:
url: jdbc:h2:file:./data/dev
username: sa
password: ""
# application-production.yaml
database:
url: ${DB_URL}
username: ${DB_USER}
password: ${DB_PASSWORD}
maxPoolSize: 25
Observability
- OpenTelemetry distributed tracing with trace ID propagation
- Micrometer metrics for HTTP requests, cache hit rates, query timing
- Caffeine cache stats exported to Micrometer
- SLF4J + Logback with MDC context
Security
RBAC with resource-level permissions:
SecurityRules.hasPermission(
Permission("report", "export"),
permissionResolver,
next
)
Authentication is pluggable via AuthRealm implementations. The template includes session-based auth; LDAP, OAuth, or API key realms can be added by implementing the interface and registering in Koin.
Getting Started
Requirements: JDK 21+, Maven 3.9+, PostgreSQL (production) or H2 (development, default).
# Build
mvn clean install
# Run web app (dev profile, H2)
mvn -pl platform-web -Pruntime-dev compile exec:java
# Or:
./start-web.ps1
# Run desktop app
./start-swing.ps1
Adding a Route
- Define a ViewModel:
data class DashboardViewModel(
val stats: DashboardStats,
val navigationMenu: List<NavigationLink>
) : ViewModel {
override fun template() = "dashboard"
}
- Create a
.ktetemplate:
@param model: DashboardViewModel
@template.layout.base(content = @`
<h1>${model.stats.title}</h1>
`)
- Register in
App.kt:
"/dashboard" bind GET to { req ->
val stats = dashboardService.getStats()
Response(Status.OK).body(renderer(DashboardViewModel(stats, nav)))
}
How is the platform tested?
| Level | Tool | Scope |
|---|---|---|
| Unit | MockK | Business logic in platform-core |
| Integration | JUnit 5 + real DB | Persistence and service layer |
| Architecture | ArchUnit | Module boundary and dependency enforcement |
| End-to-end | HTTP4k in-memory | Full request/response through the web layer |
| Desktop | Xvfb container | Swing UI via -Ptest-desktop profile |
ArchUnit tests enforce that platform-core never imports from platform-web and that persistence types don't leak into the domain.
Tech Stack
| Language | Kotlin 2.x, JDK 21 |
| Web | HTTP4k, JTE, HTMX |
| Persistence | jOOQ or JDBI 3, Flyway |
| DI | Koin |
| Config | Hoplite |
| Observability | OpenTelemetry, Micrometer |
| Caching | Caffeine |
| Desktop | Swing, FlatLaf, MigLayout |
| Build | Maven, GraalVM Native Image |
FAQ
What is the Outerstellar Platform?
The Outerstellar Platform is a multi-module Kotlin project template for building full-stack JVM applications. It includes an HTTP4k web frontend with JTE templates, jOOQ/JDBI persistence with Flyway migrations, OpenTelemetry tracing, Micrometer metrics, RBAC security, and a Swing desktop client.
Is this a framework or a template?
It is a project template — you fork it and build on it. It is not a runtime dependency you add to your project. The architecture is opinionated but all code is yours to modify.
What databases does it support?
PostgreSQL for production and H2 for development. The persistence layer uses jOOQ (type-safe SQL) or JDBI as an alternative, with Flyway for schema migrations.
Does it support GraalVM native image?
Yes. The build is configured for GraalVM Native Image compilation via Maven.
What Java version is required?
JDK 21 or later, with Kotlin 2.x.