Lockness Architecture

Lockness Architecture

VIEW

Understanding Lockness modular architecture and package system.

Core Philosophy

Lockness follows a minimal core, optional features approach:

  • @lockness/core - Essential framework only (App, DI, Hono)
  • Optional packages - Import explicitly when needed

Bootstrap Pipeline

The kernel loader uses a modular bootstrap step architecture to initialize your application. When you call createApp(KernelClass), the following steps execute in sequence:

  1. Database (100) - Database connection
  2. Session (110) - Session configuration
  3. Cache (120) - Cache system setup
  4. App Creation (200) - Create App instance
  5. Devtools (210) - Enable devtools (development only)
  6. Middleware (300) - Register global middlewares
  7. Boot Hooks (310) - Execute @OnBoot methods
  8. Middleware Discovery (400) - Auto-discover named middlewares
  9. Listener Registration (410) - Register event listeners
  10. Events (500) - Emit KernelBooted event
  11. App Initialization (550) - Initialize controllers and static files
  12. Devtools Routes (600) - Collect routes for devtools

Benefits:

  • ✅ Predictable initialization order
  • ✅ Each step isolated and testable
  • ✅ Optional packages loaded gracefully
  • ✅ Extensible without modifying core

See Kernel Lifecycle for details.

Package System

Core Package (@lockness/core)

Always required. Includes:

  • Framework fundamentals (App, routing, decorators)
  • Dependency Injection system
  • Complete Hono integration (all middleware & utilities)
  • JSX runtime and components
typescript
import {
    App, // Framework core
    basicAuth,
    cache,
    Controller, // Decorators
    cors,
    Get,
    Inject,
    jwt,
    logger, // Hono middleware
    Post,
    Service, // DI system
    validator,
    // ... all Hono exports
} from '@lockness/core'

What's NOT in core:

  • Sessions (optional for APIs)
  • Queue system (optional feature)
  • Cache system (separate from Hono cache middleware)
  • Logger system (separate from Hono logger middleware)
  • Mail, Storage, Socialite, etc.

Optional Packages

Import explicitly when needed:

@lockness/session

For: Traditional web apps with session-based auth Skip if: Building stateless JWT APIs

typescript
// In your kernel
import { sessionMiddleware } from '@lockness/session'

@Kernel({
    session: {
        driver: 'cookie',
        secret: Deno.env.get('SESSION_SECRET')!,
        lifetime: 7200,
    },
})
export class AppKernel {
    @DeclareGlobalMiddleware()
    globalMiddlewares = [
        sessionMiddleware(),
    ]
}

@lockness/queue

For: Background job processing (emails, exports, etc.) Skip if: No background tasks needed

typescript
import { configureQueue, Job, registerJob } from '@lockness/queue'

class SendEmailJob extends Job {
    async handle() {
        // Send email
    }
}

registerJob('send-email', SendEmailJob)

@lockness/cache

For: Application-level caching system Different from: Hono's HTTP cache middleware (in core)

typescript
import { cache, configureCache } from '@lockness/cache'

configureCache({ driver: 'deno-kv' })

// Cache data
await cache.remember('user:1', () => fetchUser(1), 3600)

@lockness/logger

For: Structured logging system with transports Different from: Hono's HTTP logger middleware (in core)

typescript
import { ConsoleTransport, Logger } from '@lockness/logger'

const logger = new Logger()
logger.addTransport(new ConsoleTransport())
logger.info('User logged in', { userId: 123 })

@lockness/auth

For: Authentication with guards and providers Requires: Usually needs @lockness/session for web apps

typescript
import { initializeAuthMiddleware, SessionGuard } from '@lockness/auth'
import { sessionMiddleware } from '@lockness/session'
import { UserProvider } from './auth/user_provider.ts'

@Kernel({
    session: { driver: 'cookie', secret: 'your-secret' },
})
export class AppKernel {
    @DeclareGlobalMiddleware()
    globalMiddlewares = [
        sessionMiddleware(),
        initializeAuthMiddleware({
            default: 'web',
            guards: {
                web: (ctx) => new SessionGuard('web', ctx, new UserProvider()),
            },
        }),
    ]
}

Architecture Benefits

1. Lightweight APIs

typescript
// Minimal JWT API (no sessions, no queue)
import { createApp, jwt, Kernel } from '@lockness/core'

@Kernel({
    staticDir: 'public',
    controllersDir: './app/controller',
})
export class AppKernel {
    @DeclareGlobalMiddleware()
    globalMiddlewares = [
        jwt({ secret: 'your-secret' }),
    ]
}

const app = await createApp(AppKernel)

Bundle includes: Only core + Hono (~2MB) Excludes: Session, queue, cache systems (unused code)

2. Full Web App

typescript
// Traditional web app with all features
import { createApp, DeclareGlobalMiddleware, Kernel } from '@lockness/core'
import { sessionMiddleware } from '@lockness/session'
import { configureQueue } from '@lockness/queue'
import { configureCache } from '@lockness/cache'

@Kernel({
    database: { url: Deno.env.get('DATABASE_URL') },
    session: { driver: 'cookie', secret: 'secret' },
    devtools: true,
    controllersDir: './app/controller',
})
export class AppKernel {
    @DeclareGlobalMiddleware()
    globalMiddlewares = [
        sessionMiddleware(),
    ]
}

// Configure optional features
configureQueue({ driver: 'deno-kv' })
configureCache({ driver: 'memory' })

const app = await createApp(AppKernel)

Bundle includes: Core + selected features Explicit: Clear what dependencies are used

3. Zero Naming Conflicts

Hono middleware keeps original names:

typescript
import {
    cache, // Hono HTTP cache middleware
    logger, // Hono HTTP logger middleware
    validator, // Hono request validator
} from '@lockness/core'

// Separate packages if needed:
import { cache as cacheSystem } from '@lockness/cache'
import { Logger } from '@lockness/logger'
import { Validator } from '@lockness/validator'

Project Examples

Minimal API (JWT only)

Dependencies:

  • @lockness/core

Setup:

typescript
import { createApp, DeclareGlobalMiddleware, jwt, Kernel } from '@lockness/core'

@Kernel({ controllersDir: './app/controller' })
export class AppKernel {
    @DeclareGlobalMiddleware()
    globalMiddlewares = [jwt({ secret: 'secret' })]
}

const app = await createApp(AppKernel)

Traditional Web App

Dependencies:

  • @lockness/core
  • @lockness/session
  • @lockness/auth

Setup:

typescript
import { createApp, DeclareGlobalMiddleware, Kernel } from '@lockness/core'
import { sessionMiddleware } from '@lockness/session'
import { initializeAuthMiddleware } from '@lockness/auth'

@Kernel({
    session: { driver: 'cookie', secret: 'secret' },
    controllersDir: './app/controller',
})
export class AppKernel {
    @DeclareGlobalMiddleware()
    globalMiddlewares = [
        sessionMiddleware(),
        initializeAuthMiddleware({/* ... */}),
    ]
}

const app = await createApp(AppKernel)

Full-Featured SaaS

Dependencies:

  • @lockness/core
  • @lockness/session
  • @lockness/auth
  • @lockness/queue
  • @lockness/cache
  • @lockness/mail
  • @lockness/storage

Setup:

typescript
import {
    createApp,
    DeclareGlobalMiddleware,
    Kernel,
    OnBoot,
} from '@lockness/core'
import { sessionMiddleware } from '@lockness/session'
import { configureQueue } from '@lockness/queue'
import { configureCache } from '@lockness/cache'
import { configureMail } from '@lockness/mail'
import { configureStorage } from '@lockness/storage'

@Kernel({
    database: { url: Deno.env.get('DATABASE_URL') },
    session: { driver: 'cookie', secret: 'secret', lifetime: 7200 },
    devtools: true,
    controllersDir: './app/controller',
    middlewaresDir: './app/middleware',
})
export class AppKernel {
    @DeclareGlobalMiddleware()
    globalMiddlewares = [
        sessionMiddleware(),
        // ... other middlewares
    ]

    @OnBoot({ priority: 100 })
    async configureServices() {
        configureQueue({/* ... */})
        configureCache({/* ... */})
        configureMail({/* ... */})
        configureStorage({/* ... */})
    }
}

const app = await createApp(AppKernel)

Migration Guide

If you have existing code importing from @lockness/core:

Sessions

typescript
// ❌ Old (imperative style)
import { configureSession, sessionMiddleware } from '@lockness/session'
configureSession({ driver: 'cookie', secret: 'secret' })
app.useMiddleware(sessionMiddleware())

// ✅ New (declarative with @Kernel)
import { sessionMiddleware } from '@lockness/session'

@Kernel({
    session: { driver: 'cookie', secret: 'secret' },
})
export class AppKernel {
    @DeclareGlobalMiddleware()
    globalMiddlewares = [sessionMiddleware()]
}

Queue

typescript
// ❌ Old (no longer works)
import { configureQueue, registerJob } from '@lockness/core'

// ✅ New (explicit import)
import { configureQueue, registerJob } from '@lockness/queue'

Cache System

typescript
// ❌ Old (no longer works)
import { cache, configureCache } from '@lockness/core'

// ✅ New (explicit import)
import { cache, configureCache } from '@lockness/cache'

// Note: Hono's cache middleware is still in core:
import { cache as honoCache } from '@lockness/core'
app.useMiddleware(honoCache())

FAQ

Q: Why split packages?
A: Lightweight apps don't need sessions/queues. Explicit imports show exactly what features are used.

Q: Is @lockness/core enough for an API?
A: Yes! It includes Hono with jwt, cors, logger, and all middleware you need.

Q: What about Hono's cache/logger/validator?
A: They're HTTP middleware (still in core). Separate packages are application-level systems.

Q: Do I need to install Hono separately?
A: No. @lockness/core re-exports everything from Hono. Never install Hono directly.

Q: Can I use Hono middleware with Lockness?
A: Yes! All Hono middleware is available through @lockness/core.