AgentSkillsCN

common-codes

适用于领域代码的枚举约定,包括CommonCode接口、EnumType.STRING以及各类分类模式

SKILL.md
--- frontmatter
name: common-codes
description: Enum conventions for domain codes including CommonCode interface, EnumType.STRING, and categorization patterns
triggers:
  - enum
  - common code
  - enum type
  - ordinal
argument-hint: ""

Common codes & enums

Overview

This document defines rules for categorized domain codes as enums. All domain enums that represent classifiable codes must implement the CommonCode interface from the common module.

Key Principle: All categorized domain codes must implement CommonCode. Always persist enums as STRING in JPA entities — never use ORDINAL.

CommonCode interface

CommonCode in io.glory.common.codes defines the contract for all domain code enums.

kotlin
interface CommonCode {
    val code: String        // Machine-readable code value
    val description: String // Human-readable description
    val name: String        // Enum constant name (provided by Kotlin enum)
}

IMPORTANT: All enums that represent categorized business codes must implement CommonCode. This approach ensures consistent code/description access across the project and enables automatic REST Docs generation via CommonCodeDocsTest.


Enum definition

Standard pattern

kotlin
import io.glory.common.codes.CommonCode

enum class OrderStatus(
    override val code: String,
    override val description: String,
) : CommonCode {
    PENDING("PENDING", "Order placed, awaiting payment"),
    PAID("PAID", "Payment confirmed"),
    SHIPPED("SHIPPED", "Order shipped"),
    DELIVERED("DELIVERED", "Order delivered"),
    CANCELLED("CANCELLED", "Order cancelled"),
    REFUNDED("REFUNDED", "Order refunded"),
    ;

    companion object {
        fun fromCode(code: String): OrderStatus =
            entries.find { it.code == code }
                ?: throw IllegalArgumentException("Unknown OrderStatus code: $code")
    }
}

Naming conventions

ElementConventionExample
Enum classPascalCase, descriptive nounOrderStatus, PaymentMethod, BookingType
Enum constantsSCREAMING_SNAKE_CASEPENDING, IN_PROGRESS, CREDIT_CARD
code valueMatches constant name or domain-specific code"PENDING", "CC"
descriptionClear English description"Order placed, awaiting payment"

Trailing semicolon

IMPORTANT: Add a trailing semicolon (;) after the last enum constant when the enum has a body (companion object, methods, or properties).

kotlin
// Good: Trailing semicolon before companion object
enum class UserRole(
    override val code: String,
    override val description: String,
) : CommonCode {
    ADMIN("ADMIN", "System administrator"),
    USER("USER", "Regular user"),
    GUEST("GUEST", "Guest user"),
    ;  // Required when enum has a body

    companion object { ... }
}

// Bad: Missing semicolon
enum class UserRole(...) : CommonCode {
    ADMIN("ADMIN", "System administrator"),
    GUEST("GUEST", "Guest user")  // Compilation error if companion follows
    companion object { ... }
}

JPA entity usage

IMPORTANT: Use @Enumerated(EnumType.STRING) for enum fields in JPA entities. Never use EnumType.ORDINAL — it breaks silently when you reorder or remove enum constants.

Correct: EnumType.STRING

kotlin
@Entity
@Table(name = "orders")
class Order(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long = 0,

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 20)
    var status: OrderStatus = OrderStatus.PENDING,
) : BaseTimeEntity()

Incorrect: EnumType.ORDINAL

kotlin
// Bad: ORDINAL stores position index — breaks when enum order changes
@Enumerated(EnumType.ORDINAL)
@Column(nullable = false)
var status: OrderStatus = OrderStatus.PENDING
// DB stores: 0, 1, 2... If PENDING moves to position 2, all data corrupts

Column length

Set @Column(length = N) to match the longest enum constant name. This setting prevents truncation and documents the expected range.

kotlin
// Good: length matches longest constant ("CANCELLED" = 9 chars, use 20 for safety)
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 20)
var status: OrderStatus = OrderStatus.PENDING

// Bad: No length specified — defaults to 255, wastes storage
@Enumerated(EnumType.STRING)
@Column(nullable = false)
var status: OrderStatus = OrderStatus.PENDING

Lookup methods

fromCode factory

Provide a fromCode companion method when external systems send code values that must be mapped to enum constants.

kotlin
companion object {
    fun fromCode(code: String): PaymentMethod =
        entries.find { it.code == code }
            ?: throw IllegalArgumentException("Unknown PaymentMethod code: $code")
}

Nullable lookup

Use a nullable variant when the code may not exist and null is an acceptable result.

kotlin
companion object {
    fun fromCodeOrNull(code: String): PaymentMethod? =
        entries.find { it.code == code }
}

When to use CommonCode

ScenarioUse CommonCodeExample
Business status codesYesOrderStatus, BookingStatus
Category/type classificationsYesPaymentMethod, BookingType
Role/permission typesYesUserRole, MembershipTier
Configuration flagsNoSimple Boolean or constant
Internal-only markersNoPrivate sealed class or plain enum
Response codesNoUse ResponseCode interface instead

When not to implement CommonCode

Do not implement CommonCode for:

  • Response codes — Use ResponseCode (e.g., ErrorCode and SuccessCode)
  • Internal flags — Simple enums without code/description that are never exposed externally
  • Sealed classes — Use sealed classes for complex state with data
kotlin
// Good: ResponseCode for HTTP response codes (not CommonCode)
enum class ErrorCode(
    override val status: Int,
    override val message: String,
) : ResponseCode {
    DATA_NOT_FOUND(406, "Data not found"),
}

// Good: Simple enum without CommonCode (internal use only)
enum class SortDirection {
    ASC, DESC
}

Package location

ModuleLocationExample
Domain-specific codesdomain/{feature}/entity/ (alongside Entity)domain/order/entity/OrderStatus.kt
Shared across featuresdomain/common/codes/domain/common/codes/Gender.kt
Common module codescommon/codes/common/codes/response/ErrorCode.kt

REST Docs integration

CommonCodeDocsTest automatically documents enums implementing CommonCode. The test generates REST Docs snippets listing all code and description pairs, ensuring API documentation stays in sync with the codebase.


Common pitfalls

PitfallProblemSolution
EnumType.ORDINALData corruption on reorder/removalAlways use EnumType.STRING
Missing CommonCodeInconsistent code/description accessImplement CommonCode for all domain codes
No @Column(length) on enum fieldsDefaults to 255, wastes storageSet length to match longest constant
Missing fromCode methodNo safe mapping from external code valuesAdd companion object { fun fromCode() }
Enum without trailing semicolonCompilation error when body is added laterAlways add ; after last constant
Hardcoded string comparisonsFragile, bypasses type safetyUse enum constants directly

Summary checklist

Before submitting code with enums, verify:

  • All categorized domain codes implement CommonCode
  • Enum has code and description properties
  • JPA entity fields use @Enumerated(EnumType.STRING) — never ORDINAL
  • @Column(length = N) is set to a reasonable value for enum fields
  • Trailing semicolon is present after the last constant when the enum has a body
  • fromCode companion method exists when external code mapping is needed
  • Enum is placed in the correct package (domain/{feature}/entity/ or domain/common/codes/)
  • Response codes use ResponseCode, not CommonCode