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

# Effect Orchestration

> How Tuturuuu uses Effect for server and service workflows

# Effect Orchestration

Tuturuuu uses [Effect](https://effect.website/docs/quickstart) as the default
tool for new or substantially edited TypeScript server/service orchestration
when it adds concrete value: typed expected errors, explicit dependencies,
retry/scheduling policy, resource boundaries, or controlled concurrency.

Import Effect through the platform entrypoint:

```ts theme={null}
import {
  Effect,
  Layer,
  runEffectAsResult,
  TuturuuuEffectError,
} from '@tuturuuu/utils/effect';
```

Do not import directly from `effect` in app or package code unless the curated
entrypoint is missing a module that the code genuinely needs. Add that module to
`@tuturuuu/utils/effect` first when it should become a platform pattern.

## Where Effect Fits

Use Effect for:

* Server-side workflows that coordinate several async operations.
* Expected failures that should stay typed until the route/action boundary.
* Service dependencies that need live, test, or mock implementations.
* Retry, timeout, scheduling, queue, stream, or concurrency policy.
* Shared packages that expose additive orchestration subpaths such as
  `@tuturuuu/ai/effect` or `@tuturuuu/trigger/effect`.

Avoid Effect for:

* React UI state and component-local event handlers.
* TanStack Query client fetching and mutation wrappers.
* Zod validation and generated database type contracts.
* Simple pure helpers, formatting utilities, and one-line transforms.
* Existing stable call sites where a rewrite adds churn without improving an
  error boundary or dependency boundary.

## Boundary Pattern

Keep route handlers and client helpers familiar. Build the richer orchestration
inside shared server modules, then convert to existing result shapes at the
boundary.

```ts theme={null}
import {
  Effect,
  fromDataError,
  runEffectAsResult,
} from '@tuturuuu/utils/effect';

const loadWorkspace = (query: () => Promise<{
  data: { id: string } | null;
  error: unknown;
}>) =>
  fromDataError(query, {
    code: 'WORKSPACE_READ_FAILED',
    message: 'Workspace read failed.',
  });

export async function loadWorkspaceResult(query: Parameters<typeof loadWorkspace>[0]) {
  return runEffectAsResult(
    Effect.map(loadWorkspace(query), (workspace) => ({ workspace }))
  );
}
```

API routes should still return sanitized public errors. Use
`serializeTuturuuuEffectError` or `runEffectAsResult` to cross the route/action
boundary, and log only sanitized server-side context through the existing
logging path.

## Reliability Policy

Use the Tuturuuu helpers for common server/service reliability controls before
dropping to raw Effect operators. They keep retry, timeout, and concurrency
defaults consistent across packages while still returning typed expected errors.

```ts theme={null}
import {
  Effect,
  forEachConcurrently,
  fromPromise,
  withTuturuuuRetry,
  withTuturuuuTimeout,
} from '@tuturuuu/utils/effect';

const request = fromPromise((signal) => fetch(url, { signal }), {
  code: 'UPSTREAM_REQUEST_FAILED',
  message: 'Upstream request failed.',
});

const resilientRequest = withTuturuuuRetry(
  withTuturuuuTimeout(request, {
    code: 'UPSTREAM_REQUEST_TIMEOUT',
    duration: '10 seconds',
    message: 'Upstream request timed out.',
  }),
  { times: 2, delay: '250 millis' }
);

const hydrateRows = (rows: readonly { id: string }[]) =>
  forEachConcurrently(
    rows,
    (row) => Effect.map(resilientRequest, (response) => ({ row, response })),
    { concurrency: 4 }
  );
```

Retries should be reserved for transient failures such as network errors,
timeouts, `408`, `425`, `429`, and `5xx` responses. Do not retry validation
errors, authorization failures, tenant-binding failures, or non-idempotent
mutations unless the owning service has explicit idempotency protection.

## Services And Layers

For dependencies that need replacement in tests, define a service tag and a live
layer near the owning package:

```ts theme={null}
import { Context, Effect, Layer } from '@tuturuuu/utils/effect';

interface BillingServiceShape {
  readonly charge: (amount: number) => Promise<{ ok: true }>;
}

class BillingService extends Context.Tag('BillingService')<
  BillingService,
  BillingServiceShape
>() {}

export const BillingLive = Layer.succeed(BillingService, {
  charge: async (amount) => ({ ok: true }),
});

export const chargeEffect = (amount: number) =>
  Effect.gen(function* () {
    const billing = yield* BillingService;
    return yield* Effect.promise(() => billing.charge(amount));
  });
```

Prefer package-specific entrypoints such as `@tuturuuu/ai/effect` when the
service belongs to a domain package. Keep the root `@tuturuuu/utils/effect`
entrypoint for shared primitives and small platform helpers.

## App Integration

* Server Components may call Effect programs from server-only helpers and then
  render plain data.
* Server Actions may return existing action result shapes after
  `runEffectAsResult`.
* API routes may use Effect for orchestration but must keep existing auth,
  tenant binding, Zod parsing, and sanitized response rules.
* Client components should consume normal props, TanStack Query hooks, or
  `packages/internal-api` helpers. Do not push Effect requirements into React
  component trees.

## Verification

When adding an Effect workflow:

1. Test the Effect program with a provided service/layer or a fake service.
2. Test the boundary conversion with `runEffectAsResult`.
3. Run the owning package test and type-check commands.
4. Finish with `bun check` when TypeScript, JavaScript, package metadata, docs,
   or repo guidance changed.
