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

# Entity

> Define database models as TypeORM entity classes on a shared IEntity contract.

The `@ooneex/entity` component is the foundation for domain models in the Ooneex framework. It ships the `IEntity` interface and the `EntityClassType` constructor type that every entity satisfies, so repositories, the container, and the database layer can refer to entities in a uniform, type-safe way. The package itself is intentionally tiny and dependency-free; the actual column mapping is done with [TypeORM](https://typeorm.io) decorators on classes you generate with the CLI.

## Why this component

* **One contract for every entity.** Each entity exposes a string `id` through `IEntity`, so repositories and DI can treat any model uniformly.
* **Type-safe class references.** `EntityClassType` types a constructor that produces an `IEntity`, letting you pass entity classes around (DI tokens, repository factories) without `any`.
* **TypeORM-native mapping.** Columns, primary keys, timestamps, and relations are declared with standard TypeORM decorators — nothing proprietary to learn.
* **Zero runtime dependencies.** The package contributes only types; it adds nothing to your bundle at runtime.
* **Generator-driven.** `ooneex entity:create` scaffolds a ready-to-edit entity plus its test file and registers it in the module.

## How it works

The package surface is two declarations:

| Export            | Kind        | Purpose                                                                                     |
| ----------------- | ----------- | ------------------------------------------------------------------------------------------- |
| `IEntity`         | `interface` | Base shape for every entity — requires a string `id`.                                       |
| `EntityClassType` | `type`      | Constructor type `new (...args: any[]) => IEntity` for passing entity classes by reference. |

```typescript theme={null}
export interface IEntity {
  id: string;
}

export type EntityClassType = new (...args: any[]) => IEntity;
```

An entity is a TypeORM class whose properties map to columns. You declare the table with `@Entity`, the primary key with `@PrimaryColumn`, plain columns with `@Column`, and the audit timestamps with `@CreateDateColumn`, `@UpdateDateColumn`, and `@DeleteDateColumn`. The `id` is generated up front so an instance always satisfies `IEntity` before it is persisted.

## Usage

A minimal entity needs an `id` to satisfy `IEntity`:

```typescript theme={null}
import type { IEntity } from "@ooneex/entity";

export class UserEntity implements IEntity {
  id = "";
  name = "";
  email = "";
}
```

In practice entities are TypeORM classes. Declare the table and map each property to a column:

```typescript theme={null}
import { random } from "@ooneex/utils/random";
import { Column, CreateDateColumn, DeleteDateColumn, Entity, PrimaryColumn, UpdateDateColumn } from "typeorm";

@Entity({
  name: "users",
})
export class UserEntity {
  @PrimaryColumn({ name: "id", type: "varchar", length: 25 })
  public id: string = random.nanoid(25);

  @Column({ name: "email", type: "varchar", length: 255 })
  public email!: string;

  @Column({ name: "name", type: "varchar", length: 100, nullable: true })
  public name?: string | null;

  @CreateDateColumn({ name: "created_at", nullable: true })
  public createdAt?: Date | null;

  @UpdateDateColumn({ name: "updated_at", nullable: true })
  public updatedAt?: Date | null;

  @DeleteDateColumn({ name: "deleted_at", nullable: true })
  public deletedAt?: Date | null;
}
```

`EntityClassType` lets helpers accept any entity class as a value:

```typescript theme={null}
import type { EntityClassType } from "@ooneex/entity";

const register = (entityClass: EntityClassType): void => {
  // pass the class to a repository factory, DI token, etc.
  const instance = new entityClass();
  console.log(instance.id);
};

register(UserEntity);
```

Relations use the standard TypeORM decorators (`@ManyToOne`, `@OneToMany`, `@ManyToMany`, `@OneToOne`) alongside the columns.

## Best practices

* **Always give entities a string `id`.** Satisfy `IEntity` by generating the id at construction (for example with `random.nanoid(25)`), so an instance is valid before it is saved.
* **Map every property explicitly.** Pass `name`, `type`, and `length` to `@Column` so the database schema is predictable rather than inferred.
* **Mark nullable columns `nullable: true` and type them `| null`.** Keep the TypeScript type and the database constraint in sync.
* **Use the audit columns.** Keep `@CreateDateColumn`, `@UpdateDateColumn`, and `@DeleteDateColumn` for created/updated tracking and soft deletes.
* **Reference classes with `EntityClassType`.** When passing an entity class around, type it as `EntityClassType` instead of `Function` or `any`.
* **Generate, then trim.** Scaffold with `entity:create` and remove the columns you do not need rather than starting from a blank file.

## CLI command

Scaffold an entity class and its test file with the generator. It writes the class under `modules/<module>/src/entities/<Name>Entity.ts`, a spec under `modules/<module>/tests/entities/<Name>Entity.spec.ts`, and registers the class in the module's `entities` array.

```bash theme={null}
# Interactive: prompts for the name
ooneex entity:create

# Provide the name
ooneex entity:create --name=User

# Target a module and set the table name
ooneex entity:create --name=User --module=auth --table-name=users
```

| Option         | Description                                                                                 | Default                                                |
| -------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `--name`       | Entity class name. Normalized to PascalCase; the `Entity` suffix is appended automatically. | Prompted if omitted                                    |
| `--module`     | Target module the class is generated into.                                                  | `shared`                                               |
| `--table-name` | Database table name.                                                                        | snake\_case plural of the name (e.g. `User` → `users`) |
| `--override`   | Overwrite an existing entity without prompting.                                             | `false`                                                |

The generated entity comes pre-populated with common columns (locking, blocking, visibility, locale, and audit timestamps) ready for you to keep, adjust, or remove:

```typescript theme={null}
import type { LocaleType } from "@ooneex/translation";
import { random } from "@ooneex/utils/random";
import { Column, CreateDateColumn, DeleteDateColumn, Entity, PrimaryColumn, UpdateDateColumn } from "typeorm";

@Entity({
  name: "users",
})
export class UserEntity {
  @PrimaryColumn({ name: "id", type: "varchar", length: 20, nullable: false })
  id: string = random.id();

  @Column({
    name: "is_locked",
    type: "boolean",
    default: false,
    nullable: true,
  })
  isLocked?: boolean | null;

  @Column({ name: "locked_at", type: "timestamptz", nullable: true })
  lockedAt?: Date | null;

  @Column({
    name: "is_blocked",
    type: "boolean",
    default: false,
    nullable: true,
  })
  isBlocked?: boolean | null;

  @Column({ name: "blocked_at", type: "timestamptz", nullable: true })
  blockedAt?: Date | null;

  @Column({ name: "block_reason", type: "text", nullable: true })
  blockReason?: string | null;

  @Column({ name: "is_public", type: "boolean", default: true, nullable: true })
  isPublic?: boolean | null;

  @Column({ name: "lang", type: "varchar", length: 10, nullable: true })
  lang?: LocaleType | null;

  @CreateDateColumn({ name: "created_at", nullable: true })
  createdAt?: Date | null;

  @UpdateDateColumn({ name: "updated_at", nullable: true })
  updatedAt?: Date | null;

  @DeleteDateColumn({ name: "deleted_at", nullable: true })
  deletedAt?: Date | null;
}
```

See [entity:create](/cli/commands/entity-create) for the full command reference.

## Use with Claude and Codex

The generator ships a matching `entity:create` skill. It runs the scaffold and then guides your AI agent through completing the entity — adding the columns and relations the model needs, removing the scaffolded ones that do not apply, and finishing the test file. Initialize the skills once for your agent:

<Tabs>
  <Tab title="Claude">
    ```bash theme={null}
    ooneex claude:init
    ```

    Then ask Claude in natural language — it maps the request to the generator, runs it, and fills in the implementation:

    ```text Prompt icon="terminal" wrap theme={null}
    Create a User entity with email and name columns.
    ```
  </Tab>

  <Tab title="Codex">
    ```bash theme={null}
    ooneex codex:init
    ```

    Then ask Codex in natural language — it maps the request to the generator, runs it, and fills in the implementation:

    ```text Prompt icon="terminal" wrap theme={null}
    Create a User entity with email and name columns.
    ```
  </Tab>
</Tabs>

For example, the prompt above maps to `entity:create --name=User`, then adds `email` and `name` columns and trims the scaffolded ones.
