Skip to content

Implementing a Full Feature End-to-End

Follow this process to implement a feature across the service, gateway, and frontend layers.

Layer order

Always work bottom-up:

  1. Database + Service — Schema, migration, business logic
  2. Gateway — HTTP route + OpenAPI spec
  3. Frontend — Queries + UI components

Step 1: Service action (if the feature needs new backend logic)

See the /service-action-development skill for the complete guide on:

  • Directory structure, IO types, database schemas
  • Query/command utilities, action implementation
  • Error handling with structured error codes
  • Test fixtures and integration tests

Quick summary of the action pattern:

typescript
@action('my-action')
async myAction(input: MyActionInput): Promise<IRPCResponse<MyActionOutput>> {
  return this.handleAction(
    { data: input, schema: myActionInputSchema },
    { successMessage: 'Action completed.' },
    async (validated) => {
      // Drizzle queries + business logic
      return result
    },
  )
}

Step 2: Gateway route

In apps/gateway/src/api/v1/:

  1. Create route file(s) following [verb]-[resource].ts naming
  2. Define Zod request/response schemas (gateway owns its own schemas — independent of service types)
  3. Export inferred types (propagate to SDK automatically)
  4. Add authJwt() + access() middleware (see /gateway-route-creation for scope patterns)
  5. Implement handler delegating to service binding
  6. Register in apps/gateway/src/index.ts

See the /gateway-route-creation skill for detailed patterns.

Step 3: Frontend

In apps/frontend/app/:

  1. Create query definitions in queries/
  2. Create page in pages/
  3. Create components in components/
  4. Create form schemas in schemas/ (if forms are needed)
  5. Add route middleware in middleware/ (if access control needed)

See the /frontend-feature-development skill for detailed patterns.

Step 4: Verify

  1. Run bun typecheck to verify types across the monorepo
  2. Run bun lint to check formatting/linting
  3. Run bun test:<service> to verify service tests pass (e.g. bun test:order, bun test:auth)
  4. Run bun test:gw for all gateway tests (unit + integration, excludes E2E)
  5. Run bun test:fe for frontend unit tests
  6. Run bun test:e2e for Playwright E2E tests (optional, runs in a browser)

Checklist

Before considering the feature complete:

  • [ ] Service action exists and returns IRPCResponse<T> (custom services only)
  • [ ] Input Zod schema defined and validated via handleAction
  • [ ] Output types use InferSelectModel from drizzle-orm (not Zod)
  • [ ] DB schema uses base mixin from @develit-io/backend-sdk
  • [ ] Gateway route has full OpenAPI spec with its own Zod schemas
  • [ ] Gateway route exports inferred types
  • [ ] Gateway route has authJwt() + access() middleware
  • [ ] Route registered in apps/gateway/src/index.ts
  • [ ] Frontend query uses typed SDK client (useTxsApi())
  • [ ] Frontend types derived from @devizovaburza/txs-sdk/v1 — never defined manually
  • [ ] Tests cover happy path + error cases
  • [ ] No any or unknown types anywhere
  • [ ] All imports use import type where applicable
  • [ ] Files use kebab-case naming
  • [ ] Code passes bun lint and bun typecheck