Files
agentic-dev/packages/media/AGENTS.md

7.3 KiB

AGENTS.md — media

Media upload collection (images, PDFs, etc.) and media-related use cases (get, list, delete). Provides the Media Payload collection and tRPC procedures for asset management. Full Clean Architecture scaffold added in Plan 8.

Overview

@repo/media owns: Media domain model, media-scoped errors, the IMediaRepository interface, three use cases, three controllers, a real Payload-backed repository, and the tRPC mediaRouter. No query builders today — ./ui is a placeholder.

Layer responsibilities

Layer Key files
entities/models media.tsmediaSchema + Media type (filename, mimeType, filesize, url, etc.)
entities/errors media.ts (MediaNotFoundError), common.ts (InputParseError)
application/use-cases get-media.use-case.ts, list-media.use-case.ts, delete-media.use-case.ts — factory functions + exported schemas
application/repositories media.repository.interface.tsIMediaRepository
infrastructure/repositories media.repository.ts (real Payload-backed), media.repository.mock.ts (in-memory)
interface-adapters/controllers get-media.controller.ts, list-media.controller.ts, delete-media.controller.ts — one file per use case
di symbols.ts (MEDIA_SYMBOLS), module.ts, container.ts, bind-production.ts
integrations/api procedures.ts (mediaProcedure), router.ts (mediaRouter), index.ts
integrations/cms collections/media.ts — Payload Media CollectionConfig
ui src/ui/index.ts — placeholder (no query builders today)

DI symbols

MEDIA_SYMBOLS includes: IMediaRepository, IGetMediaUseCase, IListMediaUseCase, IDeleteMediaUseCase, IGetMediaController, IListMediaController, IDeleteMediaController.

Public exports

Subpath Contents
. Media type; MediaNotFoundError, InputParseError; getMediaInputSchema, getMediaOutputSchema, listMediaInputSchema, listMediaOutputSchema, deleteMediaInputSchema; all XInput/XOutput types + IXUseCase aliases; IXController type aliases; MediaRouter type
./ui Placeholder — extend here when media gains React Query builders, never re-add to root
./api mediaRouter (tRPC router)
./cms Payload Media collection definition
./di/bind-production bindProductionMedia(ctx: BindProductionContext) — swaps mock impls for real Payload-backed ones at app boot
./di/bind-dev-seed bindDevSeedMedia(ctx: BindContext) — replaces the default empty mock with a populated one for dev / Storybook

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
getMediaUseCase getMediaInputSchema{ id: string } getMediaOutputSchema= mediaSchema Throws MediaNotFoundError when id not found; ends with getMediaOutputSchema.parse(media)
listMediaUseCase listMediaInputSchema{ limit?: int, offset?: int } (strict) listMediaOutputSchemaz.array(mediaSchema) Returns paginated list; ends with listMediaOutputSchema.parse(result)
deleteMediaUseCase deleteMediaInputSchema{ id: string } void (no xOutputSchema) Throws MediaNotFoundError when id not found; no output schema

Controllers

Controller Presenter Return type
getMediaController identity presenter Promise<ReturnType<typeof presenter>> (Media)
listMediaController identity presenter Promise<ReturnType<typeof presenter>> (Media[])
deleteMediaController none (void) Promise<void>

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

Errors → tRPC codes

Error class tRPC code Thrown by
InputParseError BAD_REQUEST controllers (safeParse failure)
MediaNotFoundError NOT_FOUND getMediaUseCase, deleteMediaUseCase

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

Tests

  • Factories: src/__factories__/media.factory.ts
  • Contract suite: src/__contracts__/media-repository.contract.ts — runs against mock and real MediaRepository
  • Unit tests: colocated *.test.ts next to each source file
  • Feature integration: src/integrations/api/router.test.ts — R26 router error-mapping tests (covers all three procedures)
  • R25 (output validation): get-media.use-case.test.ts and list-media.use-case.test.ts each have tests that inject a repository mock returning malformed data and assert .rejects.toBeInstanceOf(ZodError). deleteMedia is void — no R25.
  • R26 (router error mapping): router.test.ts asserts NOT_FOUND on getMedia with nonexistent id, BAD_REQUEST on getMedia with empty input, NOT_FOUND on deleteMedia with nonexistent id, and NOT_FOUND via an inline NullMediaRepository rebind.
  • R27/R28 (presenter shape): getMedia and listMedia use identity presenters — no reshape test obligation. deleteMedia is void — no presenter.
pnpm test --filter @repo/media
pnpm test --filter @repo/media -- --watch

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

Directory structure

src/
  entities/
    models/
      media.ts         # mediaSchema, Media type
    errors/
      media.ts         # MediaNotFoundError
      common.ts        # InputParseError
  application/
    repositories/
      media.repository.interface.ts
    use-cases/
      get-media.use-case.ts
      list-media.use-case.ts
      delete-media.use-case.ts
  infrastructure/
    repositories/
      media.repository.ts          # real Payload-backed
      media.repository.mock.ts
  interface-adapters/
    controllers/
      get-media.controller.ts
      list-media.controller.ts
      delete-media.controller.ts
  integrations/
    api/
      procedures.ts    # mediaProcedure
      router.ts        # mediaRouter
      index.ts
    cms/
      collections/
        media.ts
      index.ts
  di/
    symbols.ts         # MEDIA_SYMBOLS
    module.ts
    container.ts
    bind-production.ts
  ui/
    index.ts           # placeholder
  index.ts
  __factories__/
    media.factory.ts
  __contracts__/
    media-repository.contract.ts

What it must NOT import

  • Any other feature package (@repo/auth, @repo/blog, 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, full scaffold added in Plan 8
  • 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 — full scaffold), docs/superpowers/refactor-logs/2026-05-06-input-output-unification.md (Plan 9 — schemas + procedures)