Sonamu is a TypeScript framework that enables entity-centric full-stack development . This guide explains Sonamuβs overall architecture and core operating principles.
Sonamuβs Philosophy
Sonamu is designed based on the following principles:
1. Entity First
All development starts with entity definition . Define the data structure first, and the rest is automatically generated.
2. Type Safety
Complete type safety is guaranteed from backend to frontend. Errors can be caught at compile time.
3. Code Generation
Repetitive boilerplate code is automatically generated . Developers can focus only on business logic.
4. Developer Experience
Excellent developer experience with HMR , type inference , Sonamu UI , and more.
Overall Architecture
Sonamu operates with 6 layers automatically connected:
Core Components
1. Entity
Entity is the starting point of everything in Sonamu.
{
"entityId" : "User" ,
"tableName" : "users" ,
"title" : "User" ,
"properties" : [
{
"name" : "id" ,
"type" : "int" ,
"isPrimary" : true
},
{
"name" : "email" ,
"type" : "varchar"
},
{
"name" : "name" ,
"type" : "varchar"
}
],
"subsets" : {
"A" : [ "id" , "email" , "name" , "created_at" ],
"C" : [ "id" , "email" , "name" ]
}
}
Role of Entity Definition
Source of database schema
Basis for TypeScript type generation
Definition of API interfaces
Standard for frontend types
2. Type System
3 type files are automatically generated from entity definitions:
user.types.ts (per-entity types)
sonamu.generated.ts (all Base schemas)
sonamu.generated.sso.ts (query definitions)
// Auto-generated + extensible
import { z } from "zod" ;
import { UserBaseSchema } from "../sonamu.generated" ;
// Base type (auto-generated)
export type User = z . infer < typeof UserBaseSchema >;
// Custom types (can be written directly)
export const UserSaveParams = UserBaseSchema . partial ({
id: true ,
created_at: true ,
});
export type UserSaveParams = z . infer < typeof UserSaveParams >;
Three Type Files
{entity}.types.ts - Per-entity types (extensible)
sonamu.generated.ts - All Base schemas (auto-generated)
sonamu.generated.sso.ts - Subset queries (auto-generated)
3. Model (Business Logic)
Model handles the business logic of entities.
import { api , BaseModelClass } from "sonamu" ;
import type { UserSubsetKey , UserSubsetMapping } from "../sonamu.generated" ;
import { userSubsetQueries } from "../sonamu.generated.sso" ;
class UserModelClass extends BaseModelClass <
UserSubsetKey ,
UserSubsetMapping ,
typeof userSubsetQueries
> {
constructor () {
super ( "User" , userSubsetQueries );
}
// CRUD API
@ api ({ httpMethod: "GET" , clients: [ "axios" , "tanstack-query" ] })
async findById < T extends UserSubsetKey >(
subset : T ,
id : number ,
) : Promise < UserSubsetMapping [ T ]> {
const user = await this . db (). where ( "id" , id ). first ();
return user ;
}
// Custom business logic
@ api ({ httpMethod: "POST" , clients: [ "axios" ] })
async changePassword ( userId : number , newPassword : string ) : Promise < void > {
await this . db ()
. where ( "id" , userId )
. update ({ password: await this . hashPassword ( newPassword ) });
}
private async hashPassword ( password : string ) : Promise < string > {
// Password hashing logic
return password ;
}
}
export const UserModel = new UserModelClass ();
Model Features
Auto REST API generation with @api decorator
Basic CRUD methods provided by inheriting BaseModelClass
Type-safe DB queries with Puri query builder
Focus only on business logic
4. Syncer (Synchronization System)
Syncer is Sonamuβs core engine. It detects file changes and automatically generates code.
// Main roles of Syncer
1. File change detection ( checksum - based )
- entity . json change β Types regeneration
- model . ts change β Service regeneration
- types . ts change β Copy to Web
2. Auto code generation
- sonamu . generated . ts
- sonamu . generated . sso . ts
- { Entity } Service . ts ( frontend )
3. File synchronization
- api / src / application β web / src / services
- Type file copying
- sonamu . shared . ts deployment
4. HMR trigger
- Invalidate changed modules
- Auto restart API server
When Syncer Runs
Auto : During file changes while pnpm dev is running (HMR)
Manual : When pnpm sync command is executed
5. API Layer (REST API)
The Modelβs @api decorator automatically generates REST APIs .
// Model method
@ api ({ httpMethod: "GET" , clients: [ "axios" ] })
async findById ( subset : UserSubsetKey , id : number ): Promise < User > {
// ...
}
// β Auto conversion
// REST API endpoint
GET / api / users / : id ? subset = A
// Request
curl http : //localhost:1028/api/users/1?subset=A
// Response
{
"id" : 1 ,
"email" : "user@example.com" ,
"name" : "John Doe" ,
"created_at" : "2025-01-06T12:00:00Z"
}
Whatβs Auto-Generated
β
REST API routes
β
Request parameter validation (Zod)
β
Response types
β
Error handling
β
API documentation (sonamu.generated.http)
6. Frontend Service (Frontend Integration)
Model APIs are automatically generated as frontend Services .
web/src/services/UserService.ts (auto-generated)
export class UserService {
static async findById ( subset : UserSubsetKey , id : number ) : Promise < User > {
const res = await axios . get ( `/api/users/ ${ id } ` , {
params: { subset },
});
return res . data ;
}
static async changePassword (
userId : number ,
newPassword : string ,
) : Promise < void > {
await axios . post ( "/api/users/changePassword" , {
userId ,
newPassword ,
});
}
}
Type Safety
Backend types are synchronized directly to the frontend, so type mismatch errors can be caught at compile time !
Development Flow
Letβs see how Sonamu works during actual development:
1. Entity Definition (Sonamu UI)
{
"entityId" : "Post" ,
"properties" : [
{ "name" : "id" , "type" : "int" , "isPrimary" : true },
{ "name" : "title" , "type" : "varchar" }
]
}
Auto-generated on save:
post.types.ts
sonamu.generated.ts updated
2. Migration (Migration tab)
CREATE TABLE posts (
id SERIAL PRIMARY KEY ,
title VARCHAR ( 255 ) NOT NULL
);
On execution:
Table created in database
3. Write Model (manual or scaffolding)
@ api ({ httpMethod: "GET" })
async findById ( id : number ): Promise < Post > {
return await this.db().where( "id" , id).first();
}
Auto-generated on save:
REST API: GET /api/posts/:id
PostService.ts (frontend)
sonamu.generated.http updated
4. Frontend Usage
// Type-safe API call
const post = await PostService . findById ( 1 );
console . log ( post . title ); // β
Type checked
console . log ( post . invalid ); // β Compile error!
Type safety:
Frontend immediately detects errors when backend types change
HMR (Hot Module Replacement)
Sonamu provides a powerful HMR system .
How HMR Works
// 1. File change detection
user . model . ts modified β Watcher detects
// 2. Module invalidation
hmr - hook analyzes dependency graph
user . model . ts and dependent modules invalidated
// 3. Regeneration (Syncer)
- UserService . ts regenerated
- API routes re - registered
// 4. Server restart
graceful shutdown β reload
Benefits of HMR
β
Fast feedback - Reflected within 1-2 seconds after code change
β
State preservation - Database connections, etc. maintained
β
Auto sync - Frontend Service auto-updated
Auto Generation Mechanism
Letβs summarize what Sonamu automatically generates:
On Entity Definition Change
user.entity.json modified
β
Auto-generated:
β
user.types.ts (type definitions)
β
sonamu.generated.ts (Base schemas)
β
sonamu.generated.sso.ts (Subset queries)
β
migration SQL (table changes)
On Model File Change
user.model.ts modified
β
Auto-generated:
β
UserService.ts (frontend)
β
services.generated.ts (Service integration)
β
sonamu.generated.http (API documentation)
β
REST API routes re-registered
On Types File Change
user.types.ts modified
β
Auto-synced:
β
web/src/services/user.types.ts (copied)
β
Immediately usable in frontend
Files You Should Never Modify
sonamu.generated.ts - Overwritten on next sync
{Entity}Service.ts - Overwritten on next sync
sonamu.generated.sso.ts - Overwritten on next sync
These files are always auto-generated, so donβt modify them directly!
Type Safety Flow
Visualizing Sonamuβs End-to-End type safety :
// 1. Entity definition
{
"name" : "email" ,
"type" : "varchar"
}
β
// 2. Type generation (auto)
type User = {
email : string ;
}
β
// 3. Model method (type-safe)
async findByEmail ( email : string ): Promise < User > {
return await this.db().where( "email" , email).first();
}
β
// 4. REST API (auto-generated, type-safe)
GET / api / users / email / : email
Response : User
β
// 5. Frontend Service (auto-generated, type-safe)
static async findByEmail ( email : string ): Promise < User > {
const res = await axios . get ( `/api/users/email/ ${ email } ` );
return res.data; // type: User
}
β
// 6. React Component (type-safe)
const user = await UserService . findByEmail ( "test@example.com" );
console . log ( user . email ); // β
Type checked
console . log ( user . invalid ); // β Compile error!
Type Safety Guaranteed
Entity definition β Type generation
Model β API type inference
API β Service type synchronization
Service β UI type checking
When types change at any stage, itβs reflected across the entire chain and errors are caught at compile time!
Key Advantages of Sonamu
1. Development Speed Improvement
Traditional approach:
1. Design database table
2. Write migration
3. Define backend types
4. Write API controller
5. Register API routes
6. Define frontend types
7. Write API client
β±οΈ Total time: 2-3 hours
Sonamu approach:
1. Define entity (Sonamu UI)
2. Scaffolding (auto Model generation)
β±οΈ Total time: 10-15 minutes
β
About 90% time reduction!
2. Type Safety
// β Traditional approach: runtime error
const user = await fetch ( "/api/users/1" ). then ( r => r . json ());
console . log ( user . eamil ); // Typo! Only discovered at runtime β οΈ
// β
Sonamu: compile error
const user = await UserService . findById ( "A" , 1 );
console . log ( user . eamil ); // Compile error! Discovered immediately β
3. Maintainability
// Entity change: email β username
// β Traditional approach:
// 1. Write DB Migration
// 2. Modify backend types
// 3. Modify API
// 4. Modify frontend types
// 5. Modify all API call sites
// β οΈ Missed spots cause runtime errors!
// β
Sonamu:
// 1. Change field name in entity.json
// 2. Migration auto-generated
// 3. All types auto-updated
// 4. Compile errors immediately show where changes are needed
// β
Safe changes without missing anything!
4. Consistency
// β
Sonamu automatically maintains consistent code style
// All Services follow the same pattern
UserService . findById ( ... )
PostService . findById ( ... )
CommentService . findById ( ... )
// All types have the same structure
type User = z . infer < typeof UserBaseSchema >;
type Post = z . infer < typeof PostBaseSchema >;
type Comment = z . infer < typeof CommentBaseSchema >;
Constraints and Trade-offs
Sonamuβs powerful features come with some constraints:
Constraints to Be Aware Of
Learning curve : Need to understand Sonamuβs concepts and rules
Cannot modify auto-generated files : Manual modifications get overwritten
Entity-centric design required : Must follow the Sonamu way
Complex queries : Very complex cases may require Raw SQL
But the advantages far outweigh β
Development speed improvement (90% time reduction)
β
Type safety guaranteed
β
Improved maintainability
β
Code consistency
β
Team productivity improvement
Next Steps
Now that you understand how Sonamu works, learn about each component in detail: