From 0b1643a965753012f25efb05f8fb455dd85f14d3 Mon Sep 17 00:00:00 2001 From: Dhemy Date: Sat, 23 May 2026 17:56:41 +0200 Subject: [PATCH] redesign home page --- src/components/landing/content.ts | 141 +++++-- src/components/landing/landing.module.css | 435 ++++++++++++++++------ src/pages/index.tsx | 192 ++++++---- 3 files changed, 566 insertions(+), 202 deletions(-) diff --git a/src/components/landing/content.ts b/src/components/landing/content.ts index fc876ec..f25ba34 100644 --- a/src/components/landing/content.ts +++ b/src/components/landing/content.ts @@ -1,42 +1,92 @@ export const problemPoints = [ - 'Projects become messy as they grow.', - 'Teams drift because there is no shared structure.', - 'Every new service starts with another round of library decisions.', - 'Functional programming sounds good, but applying it consistently is hard.', + 'Application setup starts from one configuration object, so service wiring is visible before request handling begins.', + 'Routes, middleware, validation, static files, and event subscribers are registered through the same service shape.', + 'Security, testing, serialization, password helpers, and request-scoped state stay available as focused framework utilities.', + 'New contributors can inspect the same function-first structure before changing backend behavior.', ] as const; export const ideaPoints = [ - 'Clear architecture from day one.', - 'Built-in patterns that reduce incidental decisions.', - 'Practical functional programming without turning everything into theory.', - 'A workflow focused on shipping backend features, not rebuilding conventions.', + 'Start with application configuration so service setup has one readable entry point.', + 'Compose behavior from functions: routes, middleware, validators, subscribers, and utilities.', + 'Keep request data, response data, and validation rules explicit at the boundary.', + 'Let framework utilities support real backend work without hiding the application flow.', ] as const; export const featureItems = [ { - title: 'Batteries included', + title: 'Application configuration', description: - 'Start with routing, middleware, request and response handling, and request-scoped context without stitching together a framework from scratch.', + 'Give each service the same starting point: routes, global middleware, static files, and event subscribers declared in configuration.', }, { - title: 'Functional-first approach', + title: 'Function-first routing', description: - 'Keep application logic in plain functions with explicit inputs and dependencies instead of hiding behavior behind implicit state.', + 'Define HTTP methods and paths as route functions that keep backend entry points easy to scan and review.', }, { - title: 'Consistent structure', + title: 'Request and response primitives', description: - 'Use the same route, middleware, and configuration patterns across services so teams can read and extend code without re-learning the project shape.', + 'Handle body, query, parameters, headers, status, response body, and response headers through explicit HTTP primitives.', }, { - title: 'Scalable by design', + title: 'Validation toolkit', description: - 'Grow from simple endpoints to larger modules while keeping HTTP concerns, application logic, and shared utilities understandable.', + 'Describe input rules with built-in constraints, custom validators, flattened violations, and reusable validation middleware.', }, { - title: 'Focus on real backend problems', + title: 'Security utilities', description: - 'Solve request flow, validation, context propagation, and service boundaries instead of spending that time debating libraries and wiring.', + 'Apply firewall middleware for authenticated routes and use password hashing utilities for credential workflows.', + }, + { + title: 'Static files and assets', + description: + 'Serve public assets from configurable static file settings when a service needs to expose files directly.', + }, + { + title: 'Testing support', + description: + 'Create HTTP test agents from application configuration, including authenticated request scenarios through act-as support.', + }, + { + title: 'Serialization and normalization', + description: + 'Normalize common response data structures with framework utilities for arrays, records, dates, and null values.', + }, + { + title: 'Request-scoped context', + description: + 'Propagate per-request data across async work when handlers, middleware, subscribers, and shared utilities need the same context.', + }, +] as const; + +export const proofItems = [ + { + value: 'Shape', + label: 'One application configuration for service setup', + }, + { + value: 'Functions', + label: 'Routes, middleware, validators, and utilities compose explicitly', + }, + { + value: 'Coverage', + label: 'HTTP, validation, security, testing, static files, and serialization', + }, +] as const; + +export const modelSteps = [ + { + title: 'Give the service one shape', + body: 'Start from create(...) and declare routes, global middleware, static files, and event subscribers in configuration.', + }, + { + title: 'Compose behavior as functions', + body: 'Use function-first routes, middleware, validators, and subscribers so request flow stays visible in code review.', + }, + { + title: 'Use utilities where they belong', + body: 'Add security, testing agents, password helpers, serializers, static files, and request-scoped storage when the service needs them.', }, ] as const; @@ -47,41 +97,74 @@ export const gettingStartedSteps = [ }, { title: 'Configure and run', - body: 'Set your environment values, install dependencies, and start the server with the generated project scripts.', + body: 'Set environment values, review the application configuration, install dependencies, and start the server.', }, { - title: 'Add your first endpoint', - body: 'Define a route, register it explicitly, and build from the documented basics for requests, responses, and middleware.', + title: 'Add backend behavior', + body: 'Register a function-first route, add validation or middleware where needed, and build from the documented request and response model.', }, ] as const; export const architectureCards = [ { - title: 'Application shape', + title: 'Application setup stays explicit', + description: + 'Routes, global middleware, static files, and event subscribers are registered through configuration instead of scattered setup code.', + }, + { + title: 'Functional composition stays practical', description: - 'Function-first routes define HTTP entry points, middleware handles cross-cutting concerns, and the HTTP scope keeps request and response data explicit.', + 'Routes, middleware, validators, and utilities remain plain pieces that can be composed, reviewed, tested, and refactored.', }, { - title: 'Why it matters', + title: 'Framework utilities stay focused', description: - 'That structure reduces accidental coupling and makes it easier to reason about behavior as the codebase and team both grow.', + 'Validation, security, password hashing, testing, and serialization solve specific service needs without taking over application code.', }, ] as const; export const codeTabs = [ + { + label: 'Application', + language: 'ts', + code: `import {create} from '@koala-ts/framework'; +import {statusRoute} from './routes'; + +const app = create({ + routes: [statusRoute], +}); + +app.listen(3000);`, + }, { label: 'Routing', language: 'ts', - code: `export const dashboardRoute = Get('/dashboard', async (scope) => { - scope.response.body = {ok: true}; + code: `import {Get} from '@koala-ts/framework/routing'; + +export const statusRoute = Get('/status', async (scope) => { + scope.response.body = {status: 'ok'}; });`, }, { label: 'Validation', language: 'ts', - code: `const constrains = { + code: `import { + builtInConstraints, + createValidationMiddleware, + createValidator, +} from '@koala-ts/framework/validator'; + +const validate = createValidator({ + constraints: builtInConstraints, +}); + +const rules = { username: ['notBlank'], email: ['notBlank', 'email'], -};`, +}; + +const validateBody = createValidationMiddleware({validate}); + +export const validateUser = validateBody(rules);`, }, ] as const; diff --git a/src/components/landing/landing.module.css b/src/components/landing/landing.module.css index 632c7a7..301b20c 100644 --- a/src/components/landing/landing.module.css +++ b/src/components/landing/landing.module.css @@ -1,29 +1,31 @@ .page { background: - radial-gradient(circle at top center, rgba(45, 212, 191, 0.12), transparent 26rem), - linear-gradient(180deg, #ffffff 0%, #ffffff 100%); + linear-gradient(rgba(15, 118, 110, 0.035) 1px, transparent 1px), + linear-gradient(90deg, rgba(15, 118, 110, 0.035) 1px, transparent 1px), + linear-gradient(180deg, #ffffff 0%, #f8fafc 54%, #ffffff 100%); + background-size: 3rem 3rem, 3rem 3rem, auto; color: #0b0f14; } .container { - width: min(100% - 2rem, 68.75rem); + width: min(100% - 2rem, 74rem); margin: 0 auto; } .section { - padding: 5.5rem 0; + padding: 5.25rem 0; } .sectionHeader { - max-width: 40rem; - margin-bottom: 2.5rem; + max-width: 44rem; + margin-bottom: 2.25rem; } .eyebrow { margin: 0 0 0.75rem; color: #0f766e; - font-size: 0.75rem; - font-weight: 700; + font-size: 0.76rem; + font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; } @@ -31,51 +33,52 @@ .sectionTitle { margin: 0; color: #0b0f14; - font-size: clamp(2rem, 4vw, 2.9rem); - line-height: 1.1; + font-size: clamp(2rem, 4vw, 3rem); + line-height: 1.08; } .sectionDescription { margin: 1rem 0 0; color: rgba(11, 15, 20, 0.72); - font-size: 1.05rem; + font-size: 1.04rem; line-height: 1.75; } .hero { - padding: 6rem 0 4.5rem; + padding: 6.5rem 0 4.75rem; } .heroGrid { display: grid; - gap: 2.5rem; + gap: 3rem; align-items: center; - grid-template-columns: minmax(0, 1.2fr) minmax(18rem, 0.8fr); + grid-template-columns: minmax(0, 1fr) minmax(25rem, 0.9fr); } .heroCopy { - max-width: 40rem; + max-width: 43rem; } .heroTitle { + max-width: 48rem; margin: 0; color: #0b0f14; - font-size: clamp(2.8rem, 7vw, 4.8rem); + font-size: clamp(3rem, 7vw, 5.4rem); line-height: 0.96; - letter-spacing: -0.04em; } .heroText { - margin: 1.5rem 0 0; + max-width: 42rem; + margin: 1.45rem 0 0; color: rgba(11, 15, 20, 0.72); - font-size: 1.125rem; + font-size: 1.13rem; line-height: 1.8; } .buttonRow { display: flex; flex-wrap: wrap; - gap: 1rem; + gap: 0.85rem; margin-top: 2rem; } @@ -83,126 +86,295 @@ display: inline-flex; align-items: center; justify-content: center; - min-height: 3rem; - padding: 0.85rem 1.2rem; + min-height: 3.1rem; + padding: 0.82rem 1.15rem; border: 1px solid transparent; - border-radius: 999px; - font-weight: 700; + border-radius: 0.5rem; + font-weight: 800; text-decoration: none; - transition: border-color 120ms ease, background-color 120ms ease, color 120ms ease; + transition: + border-color 140ms ease, + background-color 140ms ease, + color 140ms ease, + transform 140ms ease; } .button:hover { text-decoration: none; + transform: translateY(-1px); } .buttonPrimary { background: #0f766e; - color: #f9fafb; + color: #ffffff; + box-shadow: 0 14px 30px rgba(15, 118, 110, 0.18); } .buttonPrimary:hover { background: #115e59; - color: #f9fafb; + color: #ffffff; } .buttonSecondary { - border-color: rgba(15, 118, 110, 0.18); - background: #f9fafb; + border-color: rgba(15, 23, 42, 0.12); + background: #ffffff; color: #0b0f14; } .buttonSecondary:hover { - border-color: #0f766e; + border-color: rgba(15, 118, 110, 0.45); color: #0b0f14; } .card { height: 100%; - padding: 1.5rem; - border: 1px solid rgba(15, 118, 110, 0.1); - border-radius: 1.25rem; - background: #f9fafb; - box-shadow: 0 14px 38px rgba(15, 23, 42, 0.06); + padding: 1.4rem; + border: 1px solid rgba(15, 23, 42, 0.1); + border-radius: 0.5rem; + background: rgba(255, 255, 255, 0.92); + box-shadow: 0 18px 44px rgba(15, 23, 42, 0.055); } -.heroCard { - display: grid; +.architecturePanel { + padding: 1rem; + border: 1px solid rgba(15, 23, 42, 0.12); + border-radius: 0.75rem; + background: #ffffff; + box-shadow: 0 24px 60px rgba(15, 23, 42, 0.1); +} + +.panelHeader { + display: flex; gap: 1rem; + align-items: flex-start; + justify-content: space-between; + padding: 0.45rem 0.45rem 1rem; +} + +.panelEyebrow { + margin: 0 0 0.35rem; + color: #0f766e; + font-size: 0.7rem; + font-weight: 800; + letter-spacing: 0.12em; + text-transform: uppercase; } -.heroCardTitle { +.panelTitle { margin: 0; color: #0b0f14; font-size: 1.1rem; + line-height: 1.25; } -.heroCardText { - margin: 0; - color: rgba(11, 15, 20, 0.72); - line-height: 1.7; +.panelBadge { + flex: 0 0 auto; + padding: 0.4rem 0.58rem; + border: 1px solid rgba(15, 118, 110, 0.2); + border-radius: 999px; + background: rgba(240, 253, 250, 0.85); + color: #0f766e; + font-size: 0.72rem; + font-weight: 800; } -.heroCardList { - margin: 0; - padding: 0; - list-style: none; +.flowGrid { display: grid; - gap: 0.85rem; + gap: 0.75rem; } -.heroCardList li { - color: rgba(11, 15, 20, 0.8); - padding-left: 1.1rem; +.flowStep { position: relative; + display: grid; + grid-template-columns: 2.5rem minmax(0, 1fr); + column-gap: 0.85rem; + padding: 1rem; + border: 1px solid rgba(15, 23, 42, 0.09); + border-radius: 0.5rem; + background: #f8fafc; } -.heroCardList li::before { +.flowStep::after { content: ''; position: absolute; - top: 0.7rem; - left: 0; - width: 0.45rem; - height: 0.45rem; - border-radius: 50%; - background: #2dd4bf; + left: 2.24rem; + bottom: -0.76rem; + width: 1px; + height: 0.76rem; + background: rgba(15, 118, 110, 0.26); +} + +.flowStep:last-child::after { + display: none; +} + +.flowIndex { + display: inline-flex; + grid-row: span 2; + align-items: center; + justify-content: center; + width: 2.5rem; + height: 2.5rem; + border-radius: 0.45rem; + background: #0b0f14; + color: #ffffff; + font-size: 0.75rem; + font-weight: 800; +} + +.flowStep h3 { + margin: 0; + color: #0b0f14; + font-size: 0.98rem; +} + +.flowStep p { + margin: 0.25rem 0 0; + color: rgba(11, 15, 20, 0.66); + font-size: 0.92rem; + line-height: 1.55; +} + +.panelCode { + margin: 1rem 0 0; + padding: 1rem; + overflow-x: auto; + border-radius: 0.5rem; + background: #0b0f14; + color: #e5e7eb; + font-family: var(--ifm-font-family-monospace); + font-size: 0.82rem; + line-height: 1.65; +} + +.proofStrip { + display: grid; + gap: 1rem; + grid-template-columns: repeat(3, minmax(0, 1fr)); + margin-top: 3rem; + border-block: 1px solid rgba(15, 23, 42, 0.09); + background: rgba(255, 255, 255, 0.74); +} + +.proofItem { + padding: 1.25rem 1rem; + border-right: 1px solid rgba(15, 23, 42, 0.09); +} + +.proofItem:last-child { + border-right: 0; +} + +.proofItem strong { + display: block; + color: #0b0f14; + font-size: 1.05rem; +} + +.proofItem span { + display: block; + margin-top: 0.25rem; + color: rgba(11, 15, 20, 0.64); + font-size: 0.92rem; + line-height: 1.5; } .splitGrid { display: grid; - gap: 1.5rem; - grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1.25rem; + grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr); +} + +.statementCard { + background: #0b0f14; + color: #ffffff; +} + +.statementCard .sectionDescription, +.statementText { + color: rgba(255, 255, 255, 0.74); +} + +.statementCard .sectionDescription { + margin-top: 0; +} + +.statementTitle { + margin: 0; + color: #ffffff; + font-size: clamp(1.5rem, 3vw, 2.25rem); + line-height: 1.1; +} + +.statementText { + margin: 1rem 0 0; + font-size: 1.02rem; + line-height: 1.7; +} + +.listCard { + background: #ffffff; } .copyList { + display: grid; + gap: 1rem; margin: 0; padding: 0; list-style: none; - display: grid; - gap: 1rem; } .copyList li { - color: rgba(11, 15, 20, 0.8); - line-height: 1.75; - padding-left: 1.25rem; position: relative; + padding-left: 1.35rem; + color: rgba(11, 15, 20, 0.78); + line-height: 1.72; } .copyList li::before { content: ''; position: absolute; - top: 0.75rem; + top: 0.72rem; left: 0; - width: 0.5rem; - height: 0.5rem; + width: 0.48rem; + height: 0.48rem; border-radius: 50%; - background: #2dd4bf; + background: #0f766e; +} + +.modelGrid { + display: grid; + gap: 1.5rem; + align-items: start; + grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); +} + +.modelIntro { + padding: 1.5rem 0; +} + +.modelIntro .copyList { + margin-top: 1.4rem; +} + +.modelSteps { + display: grid; + gap: 1rem; +} + +.modelStepCard { + display: grid; + grid-template-columns: 2.2rem minmax(0, 1fr); + column-gap: 1rem; +} + +.modelStepCard .stepText { + grid-column: 2; } .featureGrid { display: grid; - gap: 1.25rem; + gap: 1rem; grid-template-columns: repeat(5, minmax(0, 1fr)); } @@ -213,53 +385,56 @@ } .featureCardText { - margin: 0.8rem 0 0; - color: rgba(11, 15, 20, 0.7); - line-height: 1.7; + margin: 0.75rem 0 0; + color: rgba(11, 15, 20, 0.68); + line-height: 1.68; } .codeTabs { overflow: hidden; - border: 1px solid rgba(15, 118, 110, 0.1); - border-radius: 1.25rem; - background: #f9fafb; + border: 1px solid rgba(15, 23, 42, 0.1); + border-radius: 0.75rem; + background: #ffffff; + box-shadow: 0 22px 56px rgba(15, 23, 42, 0.08); } .tabList { display: flex; flex-wrap: wrap; - gap: 0.75rem; - padding: 1rem; - border-bottom: 1px solid rgba(15, 118, 110, 0.08); + gap: 0.6rem; + padding: 0.85rem; + border-bottom: 1px solid rgba(15, 23, 42, 0.08); + background: #f8fafc; } .tabButton, .tabButtonActive { appearance: none; - border: 0; - border-radius: 999px; - padding: 0.65rem 0.95rem; + border: 1px solid transparent; + border-radius: 0.45rem; + padding: 0.58rem 0.82rem; background: transparent; color: rgba(11, 15, 20, 0.62); font: inherit; - font-weight: 700; + font-weight: 800; cursor: pointer; } .tabButtonActive { - background: rgba(45, 212, 191, 0.18); + border-color: rgba(15, 118, 110, 0.18); + background: #ffffff; color: #0f766e; } .codePanel { - padding: 0 1rem 1rem; + padding: 1rem; } .codeBlock { margin: 0; padding: 1.5rem; overflow-x: auto; - border-radius: 1rem; + border-radius: 0.5rem; background: #0b0f14; color: #e5e7eb; font-size: 0.92rem; @@ -268,26 +443,26 @@ .architectureGrid { display: grid; - gap: 1.5rem; - grid-template-columns: minmax(0, 1.1fr) minmax(18rem, 0.9fr); + gap: 1.25rem; + grid-template-columns: minmax(0, 1.08fr) minmax(20rem, 0.92fr); } .architectureCardGrid { display: grid; - gap: 1.5rem; + gap: 1rem; } .architectureList { + display: grid; + gap: 0.85rem; margin: 1.25rem 0 0; padding: 0; list-style: none; - display: grid; - gap: 0.9rem; } .architectureList li { - color: rgba(11, 15, 20, 0.8); - line-height: 1.75; + color: rgba(255, 255, 255, 0.76); + line-height: 1.7; } .architectureDetailCard { @@ -296,7 +471,7 @@ .stepsGrid { display: grid; - gap: 1.25rem; + gap: 1rem; grid-template-columns: repeat(3, minmax(0, 1fr)); } @@ -307,22 +482,22 @@ width: 2rem; height: 2rem; margin-bottom: 1rem; - border-radius: 50%; - background: rgba(45, 212, 191, 0.18); + border-radius: 0.45rem; + background: rgba(15, 118, 110, 0.1); color: #0f766e; - font-weight: 700; + font-weight: 800; } .stepTitle { margin: 0; color: #0b0f14; - font-size: 1.1rem; + font-size: 1.08rem; } .stepText { - margin: 0.8rem 0 0; - color: rgba(11, 15, 20, 0.72); - line-height: 1.7; + margin: 0.75rem 0 0; + color: rgba(11, 15, 20, 0.7); + line-height: 1.68; } .ctaSection { @@ -331,19 +506,27 @@ } .ctaCard { + padding: 2.6rem; text-align: center; - padding: 2.5rem; + background: + linear-gradient(135deg, rgba(15, 118, 110, 0.12), transparent 34%), + #ffffff; +} + +.ctaCard .buttonRow { + justify-content: center; } .ctaTitle { - margin: 0; + max-width: 48rem; + margin: 0 auto; color: #0b0f14; - font-size: clamp(2rem, 4vw, 3rem); - line-height: 1.1; + font-size: clamp(2rem, 4vw, 3.2rem); + line-height: 1.08; } .ctaText { - max-width: 36rem; + max-width: 42rem; margin: 1rem auto 0; color: rgba(11, 15, 20, 0.72); line-height: 1.75; @@ -352,6 +535,7 @@ @media (max-width: 996px) { .heroGrid, .splitGrid, + .modelGrid, .architectureGrid, .stepsGrid { grid-template-columns: 1fr; @@ -360,9 +544,17 @@ .featureGrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } + + .architecturePanel { + max-width: 40rem; + } } @media (max-width: 640px) { + .container { + width: min(100% - 1.25rem, 74rem); + } + .section { padding: 4rem 0; } @@ -371,11 +563,42 @@ padding-top: 4.5rem; } + .heroTitle { + font-size: clamp(2.5rem, 15vw, 3.4rem); + } + + .button, + .buttonRow { + width: 100%; + } + + .proofStrip, .featureGrid { grid-template-columns: 1fr; } + .proofItem { + border-right: 0; + border-bottom: 1px solid rgba(15, 23, 42, 0.09); + } + + .proofItem:last-child { + border-bottom: 0; + } + + .panelHeader { + display: grid; + } + + .modelStepCard { + grid-template-columns: 1fr; + } + + .modelStepCard .stepText { + grid-column: auto; + } + .ctaCard { - padding: 2rem 1.25rem; + padding: 2rem 1.1rem; } } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 359fda5..3356ec4 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -13,7 +13,9 @@ import { featureItems, gettingStartedSteps, ideaPoints, + modelSteps, problemPoints, + proofItems, } from '@site/src/components/landing/content'; import styles from '@site/src/components/landing/landing.module.css'; @@ -29,98 +31,149 @@ export default function Home(): React.JSX.Element { return (
-

KoalaTS

+

KoalaTs for backend teams

- Build robust Node.js backends without overthinking + Function-first TypeScript backends with one readable shape

- KoalaTS is a batteries-included framework that brings - structure, scalability, and functional programming into - real-world backend development. + KoalaTs gives Node teams a consistent service model: configure + the application once, compose backend behavior from explicit + functions, and use framework utilities for the work that every + backend service usually needs.

- - +
- -

Why teams reach for it

-

- KoalaTS gives backend projects a clear starting point: - function-first routes, middleware for request flow, explicit - request and response handling, and utilities like request - scope storage when context needs to follow async work. -

-
    -
  • Clear entry points for HTTP and application code
  • -
  • Practical defaults instead of repeated framework assembly
  • -
  • Patterns that stay readable as features and teams grow
  • -
-
+
+
+
+

Function-first flow

+

+ One service shape from setup to response +

+
+ Function-first +
+
+
+ 01 +

Config

+

Register routes, middleware, static files, and events.

+
+
+ 02 +

Pipeline

+

Apply validation, security, and request flow concerns.

+
+
+ 03 +

Handler

+

Run application behavior with explicit HTTP primitives.

+
+
+ 04 +

Utilities

+

+ Use testing, serialization, passwords, and request scope + when needed. +

+
+
+
+                  {`const app = create({
+  routes,
+  globalMiddleware,
+  staticFiles,
+});`}
+                
+
+
+
+ {proofItems.map((item) => ( +
+ {item.value} + {item.label} +
+ ))}
- + +

+ Consistency works best when the code still reads plainly. +

+

+ KoalaTs keeps the common path explicit: configure the + service, compose behavior from functions, and keep the request + and response model visible enough for the team to review. +

+
+
    {problemPoints.map((point) => (
  • {point}
  • ))}
- -

- Most Node backends work at first, then accumulate ad hoc - structure. Each team solves routing, validation, state, and - boundaries a little differently, which makes the code harder - to reason about over time. -

-
-
- +
+

- KoalaTS gives you a stable baseline built around explicit - routes, middleware, request and response primitives, and - predictable application structure. You spend less time - inventing conventions and more time building backend behavior. + The framework shape is deliberately simple: one application + configuration, function-first routes and middleware, explicit + HTTP primitives, and focused utilities that support the + service without hiding the flow.

- -
    {ideaPoints.map((point) => (
  • {point}
  • ))}
-
+
+
+ {modelSteps.map((step, index) => ( + + {index + 1} +

{step.title}

+

{step.body}

+
+ ))} +
{featureItems.map((item) => ( @@ -135,8 +188,8 @@ export default function Home(): React.JSX.Element {
@@ -144,25 +197,29 @@ export default function Home(): React.JSX.Element {
- +

- KoalaTS is influenced by the same ideas that make larger - systems maintainable: clear boundaries, explicit dependencies, - and a separation between transport concerns and application - behavior. + KoalaTs keeps architecture close to the code: setup is + configuration, request flow is middleware, backend behavior is + composed from functions, and supporting utilities stay in + their lane. The result is a service shape the team can discuss + and change without decoding hidden framework state.

    -
  • Inspired by DDD and Clean Architecture without turning them into ceremony.
  • -
  • Separation of concerns between HTTP handling, middleware, and application logic.
  • -
  • Code that stays easier to discuss, review, and evolve as a system.
  • +
  • Application setup remains visible in configuration.
  • +
  • Routes, middleware, and validators compose as functions.
  • +
  • Security, testing, and serialization stay focused.
{architectureCards.map((card) => ( - +

{card.title}

{card.description}

@@ -174,7 +231,7 @@ export default function Home(): React.JSX.Element {
{gettingStartedSteps.map((step, index) => ( @@ -190,17 +247,18 @@ export default function Home(): React.JSX.Element {

- Start building structured backends today + Build the first function-first service your team can reuse

- Start with the documentation when you want the full model, or - jump into the quick start and build your first structured - endpoint right away. + Use the quick start to create a running KoalaTs application, or + read the framework guide to understand the application + configuration, function-first routing, validation, request, and + response model before you build.

- - +