.agents/skills/architecture-boundaries/SKILL.md
Layering and boundaries, web vs public API, app layout (clients, routes, logging), ports/adapters, runtime-portable domain/shared/utils code, multi-tenancy, DDD layout, or anti-patterns.
npx skillsauth add latitude-dev/latitude-llm architecture-boundariesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
When to use: Layering and boundaries, web vs public API, app layout (clients, routes, logging), ports/adapters, runtime-portable domain/shared/utils code, multi-tenancy, DDD layout, or anti-patterns.
apps/*)Apps only handle:
No business logic in handlers, controllers, or jobs.
apps/*)apps/*/clients.ts and import from boundaries — avoid scattering raw clients.apps/*/routes/ with a registerRoutes() (or equivalent) pattern so the HTTP surface stays modular.createLogger() from @repo/observability with a stable service name per app.parseEnv / parseEnvOptional — see env-configuration.apps/web and apps/api)apps/api is the stable public API surface. Treat its routes/contracts as externally consumed and evolve them carefully.apps/web must not call or proxy through apps/api for internal product features.apps/web server functions by composing domain use-cases and platform adapters directly.apps/web by adding web-private server functions/stores while preserving apps/api stability.apps/web and apps/api should both orchestrate domain use-cases rather than duplicating policy.packages/domain/*)Business logic lives here. Domain packages expose:
packages/domain/*/src/entities/<entity>.ts.packages/domain/*/src/constants.ts.packages/domain/*/src/errors.ts.packages/domain/*/src/helpers.ts.packages/platform/*)Infrastructure details live here only. Platform packages implement adapters for domain ports.
Reference implementation: packages/platform/db-weaviate/src/client.ts — createWeaviateClientEffect (and the thin createWeaviateClient wrapper used by scripts).
Use this pattern when a platform package owns an external SDK client so composition roots can stay in Effect and errors stay typed.
createXClientEffect(...): Effect.Effect<Client, E, never> (or with requirements R if unavoidable). Scripts and one-off CLIs may export async function createXClient() as Effect.runPromise(createXClientEffect(...)) only at the boundary that needs promises.Data.TaggedError (or shared env errors from @platform/env). Union them into a single CreateXClientError (or similar) exported next to the constructor.parseEnv / parseEnvOptional from @platform/env inside the Effect pipeline, not ad hoc process.env reads scattered outside the client module.Effect.tryPromise and map failures to tagged errors. Compose steps with Effect.pipe, Effect.flatMap, and Effect.map.migrateWeaviateCollectionsEffect after connect) so callers get a ready client or a single error channel.PortLive(client) => Layer.succeed(Port, implementation) (or Layer.effect when the adapter holds fiber-scoped state). The composition root acquires the client with createXClientEffect and maps to the layer, for example createWeaviateClientEffect().pipe(Effect.map((c) => IssueProjectionRepositoryLive(c))) in apps/workflows/src/clients.ts.Not every legacy adapter has been migrated; prefer this shape for new work and when touching client construction.
packages/utils)General-purpose utility functions that can be shared across any package (domain, platform, or app) live in @repo/utils. This package should contain pure, stateless helper functions with no domain or infrastructure dependencies.
Examples: formatCount, formatPrice, string helpers, number formatters.
When writing a utility function that is not specific to a single domain or package, place it in @repo/utils instead of keeping it local.
@domain/shared and @repo/utils have different responsibilities and should not be merged.
@domain/shared for domain-level shared contracts, types, errors, and IDs used across bounded contexts.@repo/utils for global pure, stateless helpers that are reusable anywhere.@domain/shared; otherwise, use @repo/utils.Repository, CacheStore, Publisher)organizationId and projectId in event/task/workflow payloads by default (except MagicLinkEmailRequested, UserDeletionRequested, domain-events, magic-link-email, and user-deletion payloads).In packages/domain/*, packages/utils, @domain/shared, or any code that may run outside Node (browser, edge, isolates), prefer Web Standard APIs over Node-only modules so those layers stay portable.
crypto.subtle / crypto.getRandomValues instead of node:cryptofetch instead of Node-specific HTTP clientsTextEncoder / TextDecoder instead of Buffer.from(…, 'utf-8')Uint8Array for binary data in public interfacesReadableStream instead of node:stream / node:fs streamsURL, URLSearchParams, Headers, Request, Response from the global scopestructuredClone instead of JSON round-trips for deep cloningNode-only APIs are acceptable in build tooling, scripts, CLI utilities, and test infrastructure. If you need Node outside those scopes, add a brief comment explaining why.
For access patterns, schema, and migrations, see database-postgres and database-clickhouse-weaviate.
organizationIdLAT_ prefix (see env-configuration)"use client" or "use server" directives — these are Next.js-specific; the web app uses TanStack Startdata-ai
Continuous Agentation annotation handling. Use when the user says "watch mode", asks you to watch for Agentation annotations, process feedback as it arrives, or keep fixing annotation-driven changes until told to stop or a timeout is reached.
development
apps/web UI — routes, @repo/ui, TanStack Start server functions and collections, forms, Tailwind layout rules, design-system updates, and useEffect / useMountEffect policy.
tools
Installing dependencies, running dev/build/test/lint, filtering packages, single-test runs, git hooks, preparing a clone (.env.development / .env.test), or Docker-backed local services and dev servers.
tools
Writing or debugging tests, choosing unit vs integration style, Postgres/ClickHouse tests, regenerating ClickHouse test schema, or exporting test helpers from packages without pulling test code into production bundles.