Skip to content
Back to skills

Creating Elysia Domains

ASecurity

Creates new domain modules in the Nexus Elysia API with proper typing for Eden Treaty consumers (Dashboard, The Machine)

  • 666 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added February 8, 2026
databasestypescriptbashsqlreactapidatabase

Works with

  • api

Security analysis

A100/100

Scanned February 10, 2026

npx -y skills add majiayu000/claude-skill-registry --skill creating-elysia-domains --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Creating Elysia Domains?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Creating Elysia Domains
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-creating-elysia-domains/badge)](https://www.skillsdirectory.com/skills/majiayu000-creating-elysia-domains)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: creating-elysia-domains
description: Creates new domain modules in the Nexus Elysia API with proper typing for Eden Treaty consumers (Dashboard, The Machine)
---

# Creating Elysia Domains

This skill guides creation of new feature domains in the Nexus API following established patterns for type-safe API development.

## Capabilities

- Create domain directory structure
- Define Drizzle database schemas
- Create Elysia `t.*` types for API contracts
- Implement repository and service layers
- Build typed route handlers
- Enable Eden Treaty type inference for consumers

## Domain Structure

Create in `apps/nexus/src/domains/<domain-name>/`:

```
domains/<domain-name>/
├── schema.ts      # Drizzle table definitions
├── types.ts       # Elysia t.* types for API contracts
├── service.ts     # Business logic
├── repository.ts  # Database queries
├── routes.ts      # Elysia route handlers
└── index.ts       # Re-exports
```

## File Templates

### schema.ts
```typescript
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";

export const items = sqliteTable("items", {
  id: text("id").primaryKey(),
  name: text("name").notNull(),
  status: text("status", { enum: ["active", "inactive"] }).notNull().default("active"),
  createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
  updatedAt: integer("updated_at", { mode: "timestamp" }).notNull(),
});

export type Item = typeof items.$inferSelect;
export type NewItem = typeof items.$inferInsert;
```

### types.ts
```typescript
import { t } from "elysia";

export const ItemParams = t.Object({
  id: t.String(),
});

export const CreateItemBody = t.Object({
  name: t.String({ minLength: 1 }),
  status: t.Optional(t.Union([t.Literal("active"), t.Literal("inactive")])),
});

export const UpdateItemBody = t.Object({
  name: t.Optional(t.String({ minLength: 1 })),
  status: t.Optional(t.Union([t.Literal("active"), t.Literal("inactive")])),
});

export const ItemResponse = t.Object({
  id: t.String(),
  name: t.String(),
  status: t.Union([t.Literal("active"), t.Literal("inactive")]),
  createdAt: t.String(),
  updatedAt: t.String(),
});

export const ItemListResponse = t.Array(ItemResponse);
```

### repository.ts
```typescript
import { eq } from "drizzle-orm";
import { db } from "../../infra/database";
import { items, type Item, type NewItem } from "./schema";

export const itemRepository = {
  async findAll(): Promise<Item[]> {
    return db.select().from(items);
  },

  async findById(id: string): Promise<Item | undefined> {
    const results = await db.select().from(items).where(eq(items.id, id));
    return results[0];
  },

  async create(data: NewItem): Promise<Item> {
    const results = await db.insert(items).values(data).returning();
    return results[0];
  },

  async update(id: string, data: Partial<NewItem>): Promise<Item | undefined> {
    const results = await db
      .update(items)
      .set({ ...data, updatedAt: new Date() })
      .where(eq(items.id, id))
      .returning();
    return results[0];
  },

  async delete(id: string): Promise<boolean> {
    const results = await db.delete(items).where(eq(items.id, id)).returning();
    return results.length > 0;
  },
};
```

### service.ts
```typescript
import { randomUUID } from "crypto";
import { itemRepository } from "./repository";
import type { Item } from "./schema";

export const itemService = {
  async list(): Promise<Item[]> {
    return itemRepository.findAll();
  },

  async get(id: string): Promise<Item | null> {
    return (await itemRepository.findById(id)) ?? null;
  },

  async create(data: { name: string; status?: "active" | "inactive" }): Promise<Item> {
    const now = new Date();
    return itemRepository.create({
      id: randomUUID(),
      name: data.name,
      status: data.status ?? "active",
      createdAt: now,
      updatedAt: now,
    });
  },

  async update(id: string, data: Partial<{ name: string; status: "active" | "inactive" }>): Promise<Item | null> {
    return (await itemRepository.update(id, data)) ?? null;
  },

  async delete(id: string): Promise<boolean> {
    return itemRepository.delete(id);
  },
};
```

### routes.ts
```typescript
import { Elysia } from "elysia";
import { itemService } from "./service";
import {
  ItemParams,
  CreateItemBody,
  UpdateItemBody,
  ItemResponse,
  ItemListResponse,
} from "./types";

const formatItem = (item: any) => ({
  ...item,
  createdAt: item.createdAt.toISOString(),
  updatedAt: item.updatedAt.toISOString(),
});

export const itemRoutes = new Elysia({ prefix: "/items" })
  .get("/", async () => {
    const items = await itemService.list();
    return items.map(formatItem);
  }, {
    response: ItemListResponse,
    detail: { tags: ["Items"], summary: "List all items" },
  })

  .get("/:id", async ({ params, error }) => {
    const item = await itemService.get(params.id);
    if (!item) return error(404, { message: "Item not found" });
    return formatItem(item);
  }, {
    params: ItemParams,
    response: ItemResponse,
  })

  .post("/", async ({ body }) => {
    const item = await itemService.create(body);
    return formatItem(item);
  }, {
    body: CreateItemBody,
    response: ItemResponse,
  })

  .patch("/:id", async ({ params, body, error }) => {
    const item = await itemService.update(params.id, body);
    if (!item) return error(404, { message: "Item not found" });
    return formatItem(item);
  }, {
    params: ItemParams,
    body: UpdateItemBody,
    response: ItemResponse,
  })

  .delete("/:id", async ({ params, error }) => {
    const deleted = await itemService.delete(params.id);
    if (!deleted) return error(404, { message: "Item not found" });
    return { success: true };
  }, {
    params: ItemParams,
  });
```

## Registration

Add to `apps/nexus/src/app.ts`:
```typescript
import { itemRoutes } from "./domains/items/routes";

const app = new Elysia()
  .use(itemRoutes)
```

## Eden Treaty Usage

### Dashboard (React)
```typescript
import { treaty } from "@elysiajs/eden";
import type { App } from "@nexus/app";

const api = treaty<App>(import.meta.env.VITE_API_URL);

const { data: items } = await api.items.get();
const { data: item } = await api.items({ id: "123" }).get();
const { data: newItem } = await api.items.post({ name: "Test" });
```

### The Machine (Discord Bot)
```typescript
import { treaty } from "@elysiajs/eden";
import type { App } from "@nexus/app";

const api = treaty<App>(process.env.API_URL!);
const items = await api.items.get();
```

## Critical Rules

1. **Never duplicate types** - Dashboard and The Machine import from Nexus via Eden Treaty
2. **Use `t.*` types** - Enables Eden type inference
3. **Export App type** - Required for consumers
4. **Format dates as ISO strings** - JSON serialization compatibility

## Protected Routes

```typescript
import { autheliaMiddleware } from "../../middleware/authelia";

export const protectedRoutes = new Elysia({ prefix: "/admin" })
  .use(autheliaMiddleware)
  .get("/dashboard", async ({ user }) => {
    return { message: `Hello ${user.name}` };
  });
```

## Commands

```bash
bun run db:push          # Push schema changes
bun run typecheck:api    # Verify types
bun run dev:api          # Start dev server
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.