Files
agentic-dev-template/packages/auth/AGENTS.md

8.4 KiB

AGENTS.md — auth

Users collection + authentication use cases (sign-in, sign-up, sign-out). Provides the Users Payload collection, AuthenticationService, and tRPC procedures for authentication workflows.

Overview

@repo/auth owns: User/Session/Cookie domain models, auth-scoped errors, the IUsersRepository + IAuthenticationService interfaces, three use cases, three controllers, a real Payload-backed repository + service, and the tRPC authRouter. All procedures are mutations — there are no query builders.

Layer responsibilities

Layer Key files
entities/models user.ts, session.ts, cookie.ts — Zod schemas + inferred types
entities/errors auth.ts (AuthenticationError, UnauthenticatedError, UnauthorizedError), common.ts (InputParseError)
application/use-cases sign-in.use-case.ts, sign-up.use-case.ts, sign-out.use-case.ts — factory functions + exported schemas
application/repositories users.repository.interface.tsIUsersRepository
application/services authentication.service.interface.tsIAuthenticationService
infrastructure/repositories users.repository.ts (real Payload-backed), users.repository.mock.ts (in-memory)
infrastructure/services authentication.service.ts (real Payload-backed), authentication.service.mock.ts (in-memory)
interface-adapters/controllers sign-in.controller.ts, sign-up.controller.ts, sign-out.controller.ts — one file per use case
di symbols.ts (AUTH_SYMBOLS), module.ts, container.ts, bind-production.ts
integrations/api procedures.ts (authProcedure), router.ts (authRouter)
integrations/cms collections/users.ts — Payload Users CollectionConfig
ui src/ui/index.ts — placeholder (auth is mutations only; no query builders today)

Public exports

Subpath Contents
. User, Session, Cookie types; AuthenticationError, UnauthenticatedError, UnauthorizedError, InputParseError; SESSION_COOKIE; all use-case schemas + input/output types + IXUseCase aliases; IXController type aliases; AuthRouter type
./ui Placeholder — extend here when auth gains React Query builders, never re-add to root
./api authRouter (tRPC router)
./cms Payload Users collection definition
./di/bind-production bindProductionAuth(ctx: BindProductionContext) — swaps mock impls for real Payload-backed ones at app boot
./di/bind-dev-seed bindDevSeedAuth(ctx: BindContext) — replaces the default empty mock with a populated one for dev / Storybook
./di/container authContainer — the per-feature inversify container (consumed by e2e tests + production Payload event-tasks)
./di/symbols AUTH_SYMBOLS — DI symbol registry (consumed by e2e tests + production Payload event-tasks)

Use-case + controller patterns

See CLAUDE.md Key Conventions and docs/architecture/overview.md for the canonical factory templates.

Use cases

Use case Input schema Output schema Notes
signInUseCase signInInputSchema{ username, password } signInOutputSchema{ session, cookie } Throws AuthenticationError on bad credentials
signUpUseCase signUpInputSchema{ username, password, confirmPassword } with .refine signUpOutputSchema{ session, cookie } Throws AuthenticationError on taken username
signOutUseCase signOutInputSchema{ sessionId } void (no xOutputSchema) Calls authenticationService.invalidateSession

Controllers

Controller Presenter Return type
signInController presenter(value) { return value.cookie; } ReturnType<typeof presenter> (Cookie)
signUpController presenter(value) { return value.cookie; } ReturnType<typeof presenter> (Cookie)
signOutController none (void) Promise<void>

Controllers accept unknown input and safeParse with the use-case's xInputSchema, throwing InputParseError on failure.

Real Payload implementations (Plan 8)

  • UsersRepository (infrastructure/repositories/users.repository.ts) — calls getPayload({ config }) for getUser, getUserByUsername, and createUser. Receives SanitizedConfig at constructor time.
  • AuthenticationService (infrastructure/services/authentication.service.ts) — implements hashPassword and verifyPassword with Node.js crypto (pbkdf2). Three session-related methods (createSession, validateSession, invalidateSession) are deferred — they throw NotImplementedError with a reference to refactor log §7. The mock (authentication.service.mock.ts) handles all test paths.

Errors → tRPC codes

Error class tRPC code Thrown by
InputParseError BAD_REQUEST controllers (safeParse failure)
AuthenticationError UNAUTHORIZED sign-in / sign-up use cases
UnauthenticatedError UNAUTHORIZED future session-guard middleware
UnauthorizedError FORBIDDEN future authorization checks

Defined in src/integrations/api/procedures.ts via authProcedure = t.procedure.use(defineErrorMiddleware([...])).

Tests

  • Factories: src/__factories__/user.factory.ts, src/__factories__/session.factory.ts
  • Contract suite: src/__contracts__/users-repository.contract.ts — runs against mock and real UsersRepository
  • Unit tests: colocated *.test.ts next to each source file
  • Feature integration: tests/sign-in-flow.feature.test.ts — full slice: tRPC caller → controller → use case → mock repo/service
  • R25 (output validation): sign-in.use-case.test.ts and sign-up.use-case.test.ts each have a test that injects a malformed service mock and asserts .rejects.toBeInstanceOf(ZodError). signOut is void — no R25.
  • R26 (router error mapping): router.test.ts has UNAUTHORIZED on bad credentials and BAD_REQUEST on schema failure.
  • R27/R28 (presenter shape): sign-in and sign-up controller tests assert result.name, result.value, etc. (Cookie shape), not the full { session, cookie } use-case output.
pnpm test --filter @repo/auth
pnpm test --filter @repo/auth -- --watch

See docs/guides/tdd-workflow.md for the full cycle.

Directory structure

src/
  entities/
    models/
      user.ts
      session.ts
      cookie.ts
    errors/
      auth.ts          # AuthenticationError, UnauthenticatedError, UnauthorizedError
      common.ts        # InputParseError
  application/
    repositories/
      users.repository.interface.ts
    services/
      authentication.service.interface.ts
    use-cases/
      sign-in.use-case.ts
      sign-up.use-case.ts
      sign-out.use-case.ts
  infrastructure/
    repositories/
      users.repository.ts          # real Payload-backed
      users.repository.mock.ts
    services/
      authentication.service.ts    # real (session methods deferred)
      authentication.service.mock.ts
  interface-adapters/
    controllers/
      sign-in.controller.ts
      sign-up.controller.ts
      sign-out.controller.ts
  integrations/
    api/
      procedures.ts    # authProcedure
      router.ts        # authRouter
    cms/
      collections/
        users.ts
      index.ts
  di/
    symbols.ts         # AUTH_SYMBOLS
    module.ts
    container.ts
    bind-production.ts
  ui/
    index.ts           # placeholder
  index.ts
  __factories__/
    user.factory.ts
    session.factory.ts
  __contracts__/
    users-repository.contract.ts
tests/
  sign-in-flow.feature.test.ts

What it must NOT import

  • Any other feature package (@repo/blog, @repo/media, etc.)
  • Any app package
  • @repo/core-api, @repo/core-cms, @repo/core-trpc, @repo/core-ui directly; only @repo/core-shared

Note: @repo/core-trpc and @repo/core-ui are optional packages scaffolded via pnpm turbo gen core-package trpc / ui. If not present, these constraints still apply to any future installation.

  • ADR-012 (docs/decisions/adr-012-lazar-conformance.md) — factory-style use cases, per-use-case controllers, file-naming conventions
  • ADR-013 (docs/decisions/adr-013-input-output-unification.md) — schemas-in-use-case, presenter, ./ui subpath, error middleware
  • Refactor logs: docs/superpowers/refactor-logs/2026-05-05-lazar-pattern-conformance.md (Plan 8), docs/superpowers/refactor-logs/2026-05-06-input-output-unification.md (Plan 9)