Skip to content

Project structure

This chapter covers Neton's module layout, the standard directory conventions, the configuration files and the KSP code generation step.

Modules

Neton is modular: each module has a clear responsibility and is pulled in only when needed.

ModuleWhat it providesRequired
neton-coreFramework core: startup, the component model (NetonComponent), the runtime container, configuration loading, HTTP abstractions (HttpContext, HttpRequest, HttpResponse) and the security contextYes
neton-loggingStructured logging: one Logger API, JSON output, asynchronous writes, sink routing, traceId / spanId propagation, automatic redactionYes
neton-httpHTTP: the inbound server adapter plus the outbound NetonHttpClient, streaming, SSE and the error modelYes
neton-routingRouting: route resolution, route groups, directory-based grouping, DSL registration, controller bindingYes
neton-securitySecurity: the two-layer Authenticator + Guard architecture with JWT and mock authenticators (session authentication is not built in for 1.0) and annotation-driven authorizationNo
neton-redisRedis client: connection management, core commands, distributed locks (@Lock / LockManager)No
neton-cacheTwo-tier caching: L1 in-process plus L2 Redis, with @Cacheable / @CachePut / @CacheEvictNo
neton-databaseDatabase access: the entity + table model, a type-safe query DSL, the logic layer, sqlx4k driver integrationNo
neton-storageStorage abstraction: local and S3 backends, StorageOperator / StorageManager, multi-source [[sources]] configurationNo
neton-jobsScheduling: @Job plus JobScheduler, supporting cron / fixedRate and SINGLE_NODE / ALL_NODESNo
neton-aiAI abstraction: generateText / streamText / tool loop / router / usage, OpenAI-compatible and AnthropicNo
neton-kspCompile-time code generation for @Controller, @Table, @Logic, @Job, @NetonConfig and friends — routes, parameter binding, tables and the config SPINo (recommended)
neton-validationValidation annotations and compile-time validator generationNo

Minimum set

A minimal Neton application needs only neton-core, neton-logging, neton-http and neton-routing. Add the rest as your requirements demand.

Standard layout

Neton projects follow the Kotlin Multiplatform layout with a few framework conventions on top:

my-neton-app/
├── build.gradle.kts                  # build script
├── settings.gradle.kts               # project settings
├── config/                           # configuration directory
│   ├── application.conf              # main configuration (TOML)
│   ├── application.dev.conf          # development overrides (optional)
│   ├── application.prod.conf         # production overrides (optional)
│   └── routing.conf                  # route group configuration (optional)
├── src/
│   ├── commonMain/
│   │   └── kotlin/
│   │       ├── Main.kt               # entry point
│   │       ├── controller/           # controllers
│   │       │   ├── HomeController.kt
│   │       │   ├── admin/            # controllers in the "admin" route group
│   │       │   │   └── AdminController.kt
│   │       │   └── app/              # controllers in the "app" route group
│   │       │       └── AppController.kt
│   │       ├── config/               # application config classes
│   │       │   └── AppSecurityConfig.kt
│   │       ├── model/                # data models
│   │       └── module/               # business modules (optional)
│   │           └── payment/
│   │               └── controller/
│   └── macosArm64Main/
│       └── kotlin/                   # platform-specific code
└── build/
    └── generated/
        └── ksp/                      # KSP output (generated)

Controller directory convention

Route groups map onto the package structure:

  • controllers directly under controller/ belong to the default group
  • controllers under controller/admin/ belong to the admin group (mounted through routing.conf)
  • controllers under controller/app/ belong to the app group
  • module/<name>/controller/ supports modular organisation

At compile time KSP reads each controller's package path, resolves its route group and generates the matching registration code.

Configuration files

application.conf

The main configuration file. TOML, placed in config/, loaded automatically at startup.

toml
[application]
name = "my-app"
debug = true

[server]
port = 8080

[logging]
level = "INFO"

[logging.async]
enabled = true
queueSize = 8192
flushEveryMs = 200
flushBatchSize = 64
shutdownFlushTimeoutMs = 2000

[[logging.sinks]]
name = "access"
file = "logs/access.log"
levels = "INFO"
route = "http.access"

[[logging.sinks]]
name = "error"
file = "logs/error.log"
levels = "ERROR,WARN"

Precedence, highest first:

  1. command-line arguments and environment variables
  2. environment-specific application.<env>.conf
  3. the main application.conf
  4. framework defaults

routing.conf

Declares route groups and the prefix each is mounted at:

toml
[[groups]]
group = "admin"
mount = "/admin"

[[groups]]
group = "app"
mount = "/app"

The mount field supplies the URL prefix. An /index route in the admin group is served at /admin/index.

KSP code generation

Neton generates code at compile time with KSP (Kotlin Symbol Processing), which is what lets it avoid reflection and runtime scanning entirely.

How it works

  1. You write annotated code (@Controller, @Get, @NetonConfig, …)
  2. During compilation the KSP processors read those annotations
  3. Route registration, parameter binding, config SPI and other code is written to build/generated/ksp/
  4. The generated code is compiled into the native binary alongside your own

What gets generated

AnnotationGenerated output
@Controller with @Get / @Post / …Route registration, argument binding, controller instantiation
@NetonConfigConfig SPI registration (ConfigRegistryProvider)
@Table (entity)The table object, EntityMeta, the row mapper and the update(id) { } extension
@LogicLogic instantiation and dependency wiring
@JobScheduled job registration
Validation annotationsCompile-time validators

Build configuration

kotlin
plugins {
    alias(libs.plugins.ksp)
}

dependencies {
    add("kspMacosArm64", project(":neton-ksp"))
}

// make sure KSP runs before compilation
tasks.named("compileKotlinMacosArm64").configure {
    dependsOn(tasks.named("kspKotlinMacosArm64"))
}

// add the generated code to the source set
kotlin.sourceSets.named("macosArm64Main") {
    kotlin.srcDir("build/generated/ksp/macosArm64/macosArm64Main/kotlin")
}

Without KSP

You can still register routes by hand with the DSL. See Routing and controllers.

Further reading

Neton Framework Documentation