Icecream business

You are now the owner of a Korean-style yogurt ice cream shop, "Ko-yo". The shop is located in San Francisco and you need to open the shop and start your business. The shop is 20 square meters in size.
The concept of Korean-style yogurt ice cream is that customers can freely add their desired toppings to the yogurt base ice cream. You need to implement a order form to allow customers to select and add toppings freely.
start-business
First, let's create an akan app with the project code "koyo". The koyo project is a service that operates all services under your company as the brand "Ko-yo". Now, let's type the following command in the terminal.
akan create-application koyo
Now, you can run the koyo service locally with the following command. Then, you can access the service at http://localhost:4201.
akan start koyo

Create icecream order module

Now, customers want to order the ice cream. The order is simple. You need to select the size of the yogurt base ice cream and check the desired toppings.
In Akan.js, we organize features into "modules" - think of them as complete packages that handle everything related to one thing. An ice cream order module will contain all the code needed to create, display, and manage ice cream orders.
When you create a module, Akan.js automatically generates all the files you need following a consistent pattern. This makes your code organized and easy to understand.
toppings
1Fruit Ring
2Oreo
3Strawberry
4Mango
5Cheese Cube
6Corn
7Granola
8Banana
9Fig
Now, let's create a domain for the ice cream order. The domain name is icecreamOrder, and it stores information about each ice cream order.
akan create-module icecreamOrder
# then select koyo application
This command will ask you which application to add the module to - select "koyo" since that's our ice cream shop app. The module name "icecreamOrder" describes what this module handles.
After running this command, Akan.js creates a complete folder structure with all the files you need. Let's look at what gets created:
└── apps/          # Application code
    └── koyo/      # Individual application
        └── lib/          # Domain modules
            └── icecreamOrder/  # Icecream order domain module
                ├── icecreamOrder.constant.ts   # Types and schemas
                ├── icecreamOrder.dictionary.ts # Translations
                ├── icecreamOrder.document.ts   # Document
                ├── icecreamOrder.service.ts    # Business logic
                ├── icecreamOrder.signal.ts     # API endpoints
                ├── icecreamOrder.store.ts      # State management
                ├── icecreamOrder.Template.tsx  # Form UI
                ├── icecreamOrder.Unit.tsx      # Overview UI
                ├── icecreamOrder.Util.tsx      # Utility UI
                ├── icecreamOrder.View.tsx      # Detail view UI
                └── icecreamOrder.Zone.tsx      # Integration UI
Each file has a specific purpose in organizing your ice cream order feature:
📋
constant.ts: Defines what an ice cream order looks like (size, toppings, etc.)
🌍
dictionary.ts: Translates technical terms into user-friendly language
🗄️
document.ts: Handles database storage and retrieval
⚙️
service.ts: Contains business logic (creating orders, calculating prices)
🔗
signal.ts: Connects frontend to backend with API calls
📦
store.ts: Manages form state and user interactions
🎨
UI Files (.tsx): Create the visual components customers see and interact with
Don't worry about understanding every file right now! We'll work through them step by step. The important thing is that Akan.js is based on this organized structure.

Define Constant

Constant file is a file that defines the shape of the object in the domain. It stores the shape of the object in the database and allows the client to query and represent data based on this shape.
// File: apps/koyo/lib/icecreamOrder/icecreamOrder.constant.ts
import { enumOf, Int } from "@akanjs/base";
import { Field, Filter, Model, sortOf, via } from "@akanjs/constant";
export const IcecreamOrderStatus = enumOf(["active", "processing", "served"] as const);
export type IcecreamOrderStatus = enumOf<typeof IcecreamOrderStatus>;
export const Topping = enumOf(["fruitRings", "oreo", "strawberry", "mango", "cheeseCube", "corn", "granola", "banana", "fig"] as const);
export type Topping = enumOf<typeof Topping>;
          
@Model.Input("IcecreamOrderInput")
export class IcecreamOrderInput {
  @Field.Prop(() => Int, { default: 50 })
  size: 50 | 100 | 200;
  @Field.Prop(() => [String], { enum: Topping })
  toppings: Topping[];
}
// ...other code
The ice cream order can be represented as an object like the above. The IcecreamOrderInput, which is information for creating an order, can create an order by specifying the size and toppings of the ice cream.
Great! Now we have defined what our ice cream order looks like. But how will customers see "size" and "toppings" in their own language? That's where the dictionary comes in next.

Fill dictionary

To display and describe each data of the object to the user, you need to fill the dictionary file. You can set how to display each field to the user in the dictionary, and multi-language display is supported by default.
The dictionary starts with two important entries that describe your entire module:
🏷️modelName
This is what users will see as the title or name of your feature. Instead of the technical "icecreamOrder", users see "Ice cream Order" in English or "아이스크림 주문" in Korean.
📝modelDesc
This provides a longer explanation of what this feature does. It helps users understand the purpose and context of ice cream orders in your shop.
// File: apps/koyo/lib/icecreamOrder/icecreamOrder.dictionary.ts
// ...other code
const modelDictionary = {
  ...baseTrans,
  modelName: ["IcecreamOrder", "아이스크림 주문"],
  modelDesc: [
    "IcecreamOrder is an option that customers can choose when ordering icecream at koyo store.",
    "아이스크림 주문은 koyo 가게에서 고객이 아이스크림을 주문할 때 커스텀할 수 있는 옵션들을 선택할 수 있습니다.",
  ],
  // * ==================== Model ==================== * //
  size: ["Size", "사이즈"],
  "desc-size": ["Size", "사이즈"],
  toppings: ["Toppings", "토핑"],
  "desc-toppings": ["Toppings", "토핑"],
  // * ==================== Model ==================== * //
  
  // ...other code
  // * ==================== Etc ==================== * //
  "enum-status-active": ["Active", "활성"],
  "enumdesc-status-active": ["Active status", "활성 상태"],
  "enum-size-50": ["Small", "소형"],
  "enumdesc-size-50": ["Small size", "소형 사이즈"],
  "enum-size-100": ["Medium", "중형"],
  "enumdesc-size-100": ["Medium size", "중형 사이즈"],
  "enum-size-200": ["Large", "대형"],
  "enumdesc-size-200": ["Large size", "큰 사이즈"],
  "enum-toppings-fruitRings": ["Fruit Rings", "과일 링"],
  "enumdesc-toppings-fruitRings": ["Fruit Rings", "과일 링"],
  "enum-toppings-oreo": ["Oreo", "오레오"],
  "enumdesc-toppings-oreo": ["Oreo", "오레오"],
  "enum-toppings-strawberry": ["Strawberry", "딸기"],
  "enumdesc-toppings-strawberry": ["Strawberry", "딸기"],
  "enum-toppings-mango": ["Mango", "망고"],
  "enumdesc-toppings-mango": ["Mango", "망고"],
  "enum-toppings-cheeseCube": ["Cheese Cube", "치즈 큐브"],
  "enumdesc-toppings-cheeseCube": ["Cheese Cube", "치즈 큐브"],
  "enum-toppings-corn": ["Corn", "옥수수"],
  "enumdesc-toppings-corn": ["Corn", "옥수수"],
  "enum-toppings-granola": ["Granola", "그래놀라"],
  "enumdesc-toppings-granola": ["Granola", "그래놀라"],
  "enum-toppings-banana": ["Banana", "바나나"],
  "enumdesc-toppings-banana": ["Banana", "바나나"],
  "enum-toppings-fig": ["Fig", "무화과"],
  "enumdesc-toppings-fig": ["Fig", "무화과"],
  // * ==================== Etc ==================== * //
  // ...other code
These translations make your app user-friendly! For example, when customers visit your ice cream shop website, they'll see "Ice cream Order" as a page title, not the technical "icecreamOrder". The description helps explain what the page is for.
Now customers will see "Size" instead of "size" and "Small/Medium/Large" instead of "50/100/200". Next, let's create the actual form where customers can place their orders.

Make template file

Now let's create the order form that customers will use. The Template file creates input forms where customers can select ice cream size and toppings.
// File: apps/koyo/lib/icecreamOrder/IcecreamOrder.Template.tsx
"use client";
import { cnst, st, usePage } from "@myapp/client";
import { Layout, Field } from "@akanjs/ui";
interface IcecreamOrderEditProps {
  className?: string;
}
export const General = ({ className }: IcecreamOrderEditProps) => {
  const icecreamOrderForm = st.use.icecreamOrderForm();
  const { l } = usePage();
  return (
    <Layout.Template className={className}>
      <Field.ToggleSelect
        model="icecreamOrder"
        field="size"
        label={l.field("icecreamOrder", "size")}
        items={[50, 100, 200] as const}
        value={icecreamOrderForm.size}
        onChange={st.do.setSizeOnIcecreamOrder}
      />
      <Field.MultiToggleSelect
        model="icecreamOrder"
        field="toppings"
        label={l.field("icecreamOrder", "toppings")}
        items={cnst.Topping}
        value={icecreamOrderForm.toppings}
        onChange={st.do.setToppingsOnIcecreamOrder}
      />
    </Layout.Template>
  );
};
This code creates two input fields: one for selecting ice cream size (small/medium/large) and another for choosing multiple toppings. The Field.ToggleSelect shows three size options as buttons, while Field.MultiToggleSelect allows customers to pick several toppings at once.
The "st.use.icecreamOrderForm()" gets the current form data, while "st.do.setSizeOnIcecreamOrder" and "st.do.setToppingsOnIcecreamOrder" update the form when customers make selections.
🎉 Now customers can create orders using your form. But how do we show those orders in a nice, visual way? Let's create a card design to display each order beautifully.

Update unit file

The Unit file shows how each order looks in a list or card view. Think of it as the "receipt" or "order summary" that displays the order information nicely.
// File: apps/koyo/lib/icecreamOrder/IcecreamOrder.Unit.tsx
import { clsx, ModelProps } from "@akanjs/client";
import { cnst, usePage } from "@myapp/client";
export const Card = ({ icecreamOrder }: ModelProps<"icecreamOrder", cnst.LightIcecreamOrder>) => {
  const { l } = usePage();
  return (
    <div className="animate-fadeIn group flex h-36 w-full overflow-hidden rounded-xl bg-gradient-to-br from-pink-100 via-yellow-50 to-pink-200 px-8 py-6 shadow-md transition-all duration-300 hover:shadow-xl">
      <div className="flex w-full flex-col justify-center">
        <div className="flex items-center gap-2 text-lg font-semibold text-pink-700">
          <span className="inline-block rounded bg-pink-200 px-2 py-1 text-xs font-bold tracking-wider uppercase">
            {l.field("icecreamOrder", "id")}
          </span>
          <span className="ml-2 font-mono text-pink-900">{icecreamOrder.id}</span>
        </div>
        <div className="mt-4 flex items-center gap-2">
          <span className="inline-block rounded bg-yellow-200 px-2 py-1 text-xs font-bold tracking-wider text-yellow-800 uppercase">
            {l.field("icecreamOrder", "status")}
          </span>
          <span
            className={clsx("ml-2 rounded-full px-3 py-1 text-sm font-semibold", {
              "bg-green-100 text-green-700": icecreamOrder.status === "active",
              "bg-blue-100 text-blue-700": icecreamOrder.status === "processing",
              "bg-red-100 text-red-700": icecreamOrder.status === "served",
            })}
          >
            {l.enum("icecreamOrder", "status", icecreamOrder.status)}
          </span>
        </div>
      </div>
    </div>
  );
};
This creates a card design for each ice cream order. The card shows the order ID and status with different colors - green for "active", blue for "processing", and red for "served".
The clsx function changes the card's appearance based on the order status, and l.enum() displays the status text in the user's language.
🚀 We have the form (Template) and the display card (Unit). Now let's put it all together on a webpage so customers can actually visit and use your ice cream ordering system!

Expose to page

Finally, let's create a page where customers can actually place their ice cream orders. This page connects everything together and makes it accessible through a web URL.
// File: apps/koyo/app/[lang]/icecreamOrder/page.tsx
import { Load } from "@akanjs/ui";
import { fetch, IcecreamOrder } from "@myapp/client";
export default function Page() {
  return (
    <Load.Page
      of={Page}
      loader={async () => {
        const { icecreamOrderInitInPublic } = await fetch.initIcecreamOrderInPublic();
        return { icecreamOrderInitInPublic };
      }}
      render={({ icecreamOrderInitInPublic }) => {
        return (
          <div>
            <div className="flex items-center gap-4 pb-5 text-5xl font-black">
              {l("icecreamOrder.modelName")}
              <Model.New
                className="btn btn-primary"
                sliceName="icecreamOrderInPublic"
                renderTitle="name"
                partial={icecreamOrderForm}
              >
                <IcecreamOrder.Template.General />
              </Model.New>
            </div>
            <IcecreamOrder.Zone.Card className="space-y-2" init={icecreamOrderInitInPublic} />
          </div>
        );
      }}
    />
  );
}
This complete page implementation shows how all the pieces work together! Let's break down what each part does:
🏷️l("icecreamOrder.modelName")
This displays the page title using our dictionary! It shows "Ice cream Order" (or "아이스크림 주문" in Korean) as a big, bold heading.
Model.New Button
This creates a "New Order" button that opens the form (Template.General) when clicked. Customers can use this to place new ice cream orders.
📋Zone.Card
This displays all existing ice cream orders as cards, showing the order details and status.
Now visit http://localhost:4201/icecreamOrder to see your ice cream ordering system!
Component Architecture

Model.View.tsx

Page-level components that display a full page or section

Model.Unit.tsx

Card or list item components that display a single instance

Model.Template.tsx

Form components for creating or editing models

Model.Zone.tsx

Layout containers that organize multiple components

Released under the MIT License
Official Akan.js Consulting onAkansoft
Copyright © 2025 Akan.js. All rights reserved.
System managed bybassman