> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Enums

> Defining and utilizing Enum types

Enum is an enumeration type that can only select from a predefined list of values. It provides type safety and makes it easy to configure selection options in user interfaces.

## What is an Enum?

Enum defines a limited set of values to provide:

<CardGroup cols={2}>
  <Card title="Type Safety" icon="shield-check">
    Prevents undefined value input

    Automatically converts to Union type in TypeScript
  </Card>

  <Card title="Auto UI Generation" icon="list">
    Automatic selection list configuration

    Immediately usable in Select, ButtonSet components
  </Card>

  <Card title="Label Management" icon="tag">
    Separation of keys and display names

    Easy multi-language support
  </Card>

  <Card title="Maintainability" icon="wrench">
    Centralized management

    Only one place to modify when values change
  </Card>
</CardGroup>

## Defining Enums

### Defining in entity.json

Define as key-label pairs in the Entity's `enums` section.

```json title="user.entity.json" theme={null}
{
  "id": "User",
  "props": [
    {
      "name": "role",
      "type": "enum",
      "id": "UserRole",
      "desc": "User role"
    },
    {
      "name": "status",
      "type": "enum",
      "id": "UserStatus",
      "desc": "Account status"
    }
  ],
  "enums": {
    "UserRole": {
      "admin": "Administrator",
      "normal": "Normal User",
      "guest": "Guest"
    },
    "UserStatus": {
      "active": "Active",
      "inactive": "Inactive",
      "suspended": "Suspended",
      "deleted": "Deleted"
    }
  }
}
```

**Structure**:

* **Enum ID**: PascalCase (e.g., `UserRole`, `PostStatus`)
* **Key**: lowercase, numbers, underscores (e.g., `admin`, `draft_saved`)
* **Label**: Display text (e.g., "Administrator", "Draft Saved")

### Defining in Sonamu UI

<Steps>
  <Step title="Navigate to Entity edit page">
    Select an Entity in Sonamu UI.
  </Step>

  <Step title="Scroll to Enums section">
    The Enums section is below Props, Indexes, Subsets.
  </Step>

  <Step title="Click Add Enum">
    Add a new Enum.

    **Enter Enum ID**:

    * Enter in PascalCase
    * Use `{Entity}` pattern to associate with Entity
      * Example: `$ModelRole` → `UserRole` (auto-converted)
  </Step>

  <Step title="Add Enum values">
    Each Enum is displayed as a separate tab, add key-label pairs with the **"Add Row"** button.

    * **Key**: lowercase letters, numbers, underscores only
    * **Label**: Display name
  </Step>

  <Step title="Save">
    When you save the Entity, the Enum is saved together.
  </Step>
</Steps>

<Frame caption="📸 Needed: Sonamu UI Enums section - multiple Enums displayed as tabs" />

## Auto-Generated Code

When you define an Enum, Sonamu automatically generates the following:

### 1. Zod Schema

```typescript title="sonamu.generated.ts" theme={null}
import { z } from "zod";

// Enum schema
export const UserRole = z.enum(["admin", "normal", "guest"]);

// Enum labels
export const UserRoleLabels = {
  admin: "Administrator",
  normal: "Normal User",
  guest: "Guest",
} as const;
```

### 2. TypeScript Type

```typescript title="user.types.ts" theme={null}
import { UserRole } from "./sonamu.generated";

// Inferred as Union type
export type UserRole = z.infer<typeof UserRole>;
// Result: "admin" | "normal" | "guest"
```

### 3. Label Helper Function

```typescript title="sonamu.generated.ts" theme={null}
// Get label function
export function getUserRoleLabel(role: UserRole): string {
  return UserRoleLabels[role];
}
```

## Using Enums

### Using in Props

```json theme={null}
{
  "props": [
    {
      "name": "role",
      "type": "enum",
      "id": "UserRole",
      "desc": "User role",
      "dbDefault": "normal"
    }
  ]
}
```

**Database**:

* Column type: `text`
* Stored value: Key value (e.g., `"admin"`)

**TypeScript**:

```typescript theme={null}
type User = {
  id: number;
  role: "admin" | "normal" | "guest"; // Union type
};
```

### Using in API

<CodeGroup>
  ```typescript title="Using Enum in Model" theme={null}
  import { UserRole } from "./user.types";

  export class UserModel extends BaseModelClass {
    @api({ httpMethod: "POST" })
    async updateRole(userId: number, role: UserRole) {
      // role is type-safe
      await this.puri()
        .where("id", userId)
        .update({ role });
        
      return { success: true };
    }
  }
  ```

  ```typescript title="Validation with Zod" theme={null}
  import { UserRole } from "./sonamu.generated";

  export const UserUpdateParams = z.object({
    id: z.number(),
    role: UserRole, // Auto-validated with Enum schema
  });

  export type UserUpdateParams = z.infer<typeof UserUpdateParams>;
  ```
</CodeGroup>

### Displaying Labels

<CodeGroup>
  ```typescript title="Backend" theme={null}
  import { getUserRoleLabel } from "./sonamu.generated";

  const user = await UserModel.findById(1);
  const roleLabel = getUserRoleLabel(user.role);
  // "Administrator"
  ```

  ```typescript title="Frontend" theme={null}
  import { UserRoleLabels } from "@/services/sonamu.generated";

  function UserBadge({ role }: { role: UserRole }) {
    return <span>{UserRoleLabels[role]}</span>;
    // "Administrator"
  }
  ```
</CodeGroup>

## Common Enum Patterns

### 1. OrderBy Enum

Define sorting options.

```json theme={null}
{
  "enums": {
    "UserOrderBy": {
      "id-desc": "ID Newest First",
      "id-asc": "ID Oldest First",
      "created_at-desc": "Created At Newest First",
      "created_at-asc": "Created At Oldest First",
      "username-asc": "Name Order"
    }
  }
}
```

**Usage**:

```typescript theme={null}
async findAll(orderBy: UserOrderBy = "id-desc") {
  const [field, direction] = orderBy.split("-");
  return this.puri()
    .orderBy(field, direction as "asc" | "desc")
    .many();
}
```

### 2. SearchField Enum

Define searchable fields.

```json theme={null}
{
  "enums": {
    "UserSearchField": {
      "email": "Email",
      "username": "Name",
      "phone": "Phone"
    }
  }
}
```

**Usage**:

```typescript theme={null}
async search(field: UserSearchField, keyword: string) {
  return this.puri()
    .whereLike(field, `%${keyword}%`)
    .many();
}
```

### 3. Status Enum

Define statuses.

```json theme={null}
{
  "enums": {
    "PostStatus": {
      "draft": "Draft",
      "published": "Published",
      "archived": "Archived",
      "deleted": "Deleted"
    }
  }
}
```

**Usage**:

```typescript theme={null}
async publish(postId: number) {
  await this.puri()
    .where("id", postId)
    .update({ status: "published" });
}
```

### 4. Type/Category Enum

Define classifications.

```json theme={null}
{
  "enums": {
    "NotificationType": {
      "email": "Email",
      "sms": "SMS",
      "push": "Push Notification",
      "in_app": "In-App Notification"
    }
  }
}
```

## Enum Array Type

You can store multiple Enum values as an array.

```json theme={null}
{
  "props": [
    {
      "name": "permissions",
      "type": "enum[]",
      "id": "Permission",
      "desc": "Permission list"
    }
  ],
  "enums": {
    "Permission": {
      "read": "Read",
      "write": "Write",
      "delete": "Delete",
      "admin": "Admin"
    }
  }
}
```

**Database**:

* Column type: `text[]`
* Stored value: `["read", "write"]`

**TypeScript**:

```typescript theme={null}
type User = {
  id: number;
  permissions: ("read" | "write" | "delete" | "admin")[];
};
```

**Usage**:

```typescript theme={null}
// Check permission
function hasPermission(user: User, permission: Permission): boolean {
  return user.permissions.includes(permission);
}

// Grant permission
async grantPermission(userId: number, permission: Permission) {
  const user = await this.findById(userId);
  if (!user.permissions.includes(permission)) {
    await this.puri()
      .where("id", userId)
      .update({
        permissions: [...user.permissions, permission]
      });
  }
}
```

## Using Enums in Frontend

### Select Component

<CodeGroup>
  ```tsx title="Using Generated Component" theme={null}
  import { UserRoleSelect } from "@/components/UserRoleSelect";

  function UserForm() {
    const [role, setRole] = useState<UserRole>("normal");
    
    return (
      <UserRoleSelect
        value={role}
        onChange={setRole}
      />
    );
  }
  ```

  ```tsx title="Manual Implementation" theme={null}
  import { UserRole, UserRoleLabels } from "@/services/sonamu.generated";

  function UserForm() {
    return (
      <select>
        {UserRole.options.map(key => (
          <option key={key} value={key}>
            {UserRoleLabels[key]}
          </option>
        ))}
      </select>
    );
  }
  ```
</CodeGroup>

### ButtonSet Component

```tsx theme={null}
import { UserStatusButtonSet } from "@/components/UserStatusButtonSet";

function StatusFilter() {
  const [status, setStatus] = useState<UserStatus | null>(null);
  
  return (
    <UserStatusButtonSet
      value={status}
      onChange={setStatus}
      allowNull // Allow deselection
    />
  );
}
```

## Enum Validation

Zod automatically validates Enum values.

<CodeGroup>
  ```typescript title="API Parameter Validation" theme={null}
  import { UserRole } from "./sonamu.generated";

  export const UpdateRoleParams = z.object({
    userId: z.number(),
    role: UserRole, // Auto-validated
  });

  // When invalid value is input
  UpdateRoleParams.parse({
    userId: 1,
    role: "invalid_role" // Error!
  });
  ```

  ```typescript title="Custom Validation" theme={null}
  import { UserRole } from "./sonamu.generated";

  // Allow only specific roles
  export const AdminOnlyParams = z.object({
    role: UserRole.refine(
      (val) => val === "admin" || val === "superadmin",
      { message: "Admin permission required" }
    ),
  });
  ```
</CodeGroup>

## Enum Naming Conventions

### Recommended Patterns

| Purpose       | Pattern               | Example                           |
| ------------- | --------------------- | --------------------------------- |
| Entity status | `{Entity}Status`      | `PostStatus`, `OrderStatus`       |
| Entity type   | `{Entity}Type`        | `NotificationType`, `PaymentType` |
| Entity role   | `{Entity}Role`        | `UserRole`, `MemberRole`          |
| Sort options  | `{Entity}OrderBy`     | `UserOrderBy`, `PostOrderBy`      |
| Search fields | `{Entity}SearchField` | `UserSearchField`                 |
| Category      | `{Entity}Category`    | `ProductCategory`                 |
| Permission    | `{Entity}Permission`  | `UserPermission`                  |

### \$Model Pattern

Use `$Model` to dynamically include the Entity name:

```json theme={null}
{
  "enums": {
    "$ModelRole": {
      "admin": "Administrator",
      "normal": "Normal"
    },
    "$ModelStatus": {
      "active": "Active",
      "inactive": "Inactive"
    }
  }
}
```

**Conversion result**:

* `User` Entity → `UserRole`, `UserStatus`
* `Post` Entity → `PostRole`, `PostStatus`

## Cautions

<Warning>
  **Caution When Changing Enum Values**

  Changing an Enum key that's already stored in the database will cause mismatch with existing data.

  **How to change**:

  1. Add new key
  2. Data migration (old key → new key)
  3. Remove old key
</Warning>

<Warning>
  **Key Naming Restrictions**

  Enum Keys can only use:

  * Lowercase letters (a-z)
  * Numbers (0-9)
  * Underscores (\_)

  Hyphens (-) cannot be used.
</Warning>

<Tip>
  **Labels Can Be Changed Freely**

  Labels are for display purposes, so they can be changed anytime. Only Keys are stored in the database.
</Tip>

## Enum vs Separate Table

| Criteria         | Enum               | Separate Table                    |
| ---------------- | ------------------ | --------------------------------- |
| Number of values | Few (\< 20)        | Many (> 20)                       |
| Change frequency | Rarely             | Frequently                        |
| Additional info  | Not needed         | Needed (description, order, etc.) |
| Performance      | Fast (no JOIN)     | Slower (JOIN needed)              |
| Recommended use  | Status, role, type | Category, code tables             |

**Enum use examples**:

* User roles (admin, user, guest)
* Post status (draft, published, deleted)
* Notification types (email, sms, push)

**Separate table use examples**:

* Region list (Seoul, Busan, ...)
* Product categories (hierarchical structure)
* Country codes (many additional info)

## Next Steps

<CardGroup cols={2}>
  <Card title="Field Types" icon="list" href="/en/core-concepts/entity/field-types">
    Learn about other field types
  </Card>

  <Card title="Validation" icon="shield-check" href="/en/api-development/validation/zod-schemas">
    Validate data with Zod
  </Card>

  <Card title="Frontend Components" icon="browser" href="/en/frontend-integration/generated-services/using-services">
    Use generated components
  </Card>

  <Card title="API Development" icon="code" href="/en/api-development/creating-apis/basic-crud">
    API development using Enums
  </Card>
</CardGroup>
