Skip to content

guinness-backend Directory Architecture

The guinness-backend monorepo is a Turborepo workspace using Bun. It contains 4 apps (user API, admin API, MCP-v2 server, PostgreSQL migrations) and 4 shared packages. For infrastructure topology, see Admin Infrastructure and User Infrastructure.

Repository Structure

guinness-backend/
  apps/
    app/                    # @guinness-backend/app โ€” User-facing REST API (Hono + Bun)
    admin/                  # @guinness-backend/admin โ€” Admin REST API (Hono + Bun)
    mcp-v2/                 # @guinness-backend/mcp-v2 โ€” Model Context Protocol server
    migration-pg/           # @guinness-backend/migration-pg โ€” PostgreSQL schema migrations (Drizzle Kit)
  packages/
    models/                 # @guinness-backend/models โ€” PostgreSQL Drizzle ORM schemas
    utils/                  # @guinness-backend/utils โ€” Shared utilities (auth, errors, pagination, etc.)
    guinness-backend-sdk/   # Shared backend and test helpers
    typescript-config/      # @guinness-backend/typescript-config โ€” Shared tsconfig
  docs/                     # MkDocs documentation site
  bin/                      # Operational scripts (SSM sessions for RDS/DocDB)
  api-collections/          # API collection files (Postman/Bruno)

App Structure Pattern

Each API app (app, admin, mcp-v2) follows a 4-layer architecture: routes โ†’ services โ†’ repositories โ†’ models.

apps/app/src/
  server.ts                   # Bun server entry point
  app.ts                      # Hono app configuration
  config/
    env.ts                    # Environment variable validation (Zod)
    database.ts               # Database connection config
    cognito.ts                # AWS Cognito client config
  middlewares/
    protected-route.ts        # JWT auth middleware
    error-handler.ts          # Global error handling
    rate-limit.ts             # Rate limiting
    winston-logger.ts         # Request logging
  routes/v1/                  # HTTP handlers (per-domain files)
  services/                   # Business logic (per-domain files)
  repositories/               # Data access โ€” Drizzle queries (per-domain files)
  schemas/
    components/               # OpenAPI component schemas (Zod)
    routes/                   # Per-route request/response schemas (Zod)
  types/
    endpoint/                 # Per-endpoint type definitions
  lib/
    database.ts               # DB connection pool singleton
    server.ts                 # Server setup helper
  utils/
    pagination.ts             # Pagination helpers
    security.ts               # Security utilities

The admin app extends this pattern with additional authorization middlewares (require-admin-access, require-organization-access, require-project-access, require-user-access, resolve-actor-admin, access-level-rank).

Request Flow

Requests pass through the following layers in order.

Client Request
    โ†“
Middlewares (auth, logging, error handling)
    โ†“
Routes (request validation, response formatting)
    โ†“
Services (business logic)
    โ†“
Repositories (data access)
    โ†“
Database / External Services (AWS Cognito, S3, SQS)

Middleware Pipeline

Middleware File Role
requestId() hono/request-id Attaches a unique request ID for tracing
winstonLogger() middlewares/winston-logger.ts Structured request / response logging (including duration)
cors() hono/cors Cross-origin resource sharing
compress() hono/compress Gzip response compression
rateLimit() middlewares/rate-limit.ts Request rate limiting
protectedRoute middlewares/protected-route.ts JWT verification and Cognito sub extraction
errorHandler middlewares/error-handler.ts Centralized error handling with unified response format

Layer Implementation Patterns

Routes Layer

Handles HTTP, validation, and response formatting. Contains no business logic โ€” delegates to Services.

route.openapi(getUser, async (c) => {
  const { user_id } = c.req.valid('param');
  const { sub: requesterUsername } = c.get('auth');

  try {
    const user = await userService.findOneById(user_id, requesterUsername);
    return c.json(formatOutput(user));
  } catch (error) {
    logger.error('Failed to fetch user', { error, user_id });
    throw error;
  }
});

Services Layer

Implements business rules, orchestrates multiple repositories, and integrates with external services (Cognito, S3, SQS).

export async function findOneById(
  userId: string,
  requesterUsername: string
): Promise<User> {
  const user = await userRepository.findById(userId);
  if (!user) throw new NotFoundError(`User ${userId} not found`);
  if (!hasPermission(requesterUsername, user)) throw new ForbiddenError('Insufficient permissions');
  return user;
}

Repositories Layer

Responsible only for database operations using Drizzle ORM. Contains no business logic.

export async function findById(userId: string): Promise<User | null> {
  const result = await db
    .select()
    .from(users)
    .where(and(eq(users.id, userId), isNull(users.deletedAt)))
    .limit(1);
  return result[0] ?? null;
}

Error Handling

Standard Error Response

All errors are returned in the following JSON format.

{
  "error": {
    "message": "Error description",
    "code": "ERROR_CODE",
    "details": {}
  }
}

HTTP Status Codes

Status Usage
400 Bad Request Invalid input data
401 Unauthorized Missing or invalid authentication
403 Forbidden Insufficient permissions
404 Not Found Resource not found
409 Conflict Resource conflict (e.g. duplicate)
500 Internal Server Error Unexpected server error

Shared Package Responsibilities

Package Key files Responsibility
packages/models postgresql/*.ts Drizzle ORM schema definitions for all tables, per-table files with relations
packages/models postgresql/shared/audit-fields.ts Shared audit columns (created_at, updated_at)
packages/models postgresql/shared/constants.ts Shared DB constants
packages/utils src/cognito-jwt.ts JWT verification for Cognito tokens
packages/utils src/error.ts Custom error classes (Validation, Unauthorized, Forbidden, NotFound, Conflict, InternalServer)
packages/utils src/pagination.ts Pagination helpers
packages/utils src/logger.ts Winston logger setup
packages/utils src/encryption.ts Encryption/decryption utilities
packages/utils src/response.ts API response formatting
packages/utils src/retry.ts Retry logic with exponential backoff
packages/utils src/request-validation.ts Request validation helpers
packages/utils src/figma.ts Figma API helpers
packages/guinness-backend-sdk src/test-utils/postgres-container.ts Testcontainers PostgreSQL setup
packages/guinness-backend-sdk src/test-utils/vitest-global-setup.ts Vitest global setup for test DB
packages/typescript-config base.json, app.json Shared tsconfig presets

Shared Dependencies

Package Purpose
hono Web framework (v4.12) โ€” routing, middleware, OpenAPI
drizzle-orm Database ORM โ€” PostgreSQL query builder
drizzle-kit Schema migration tool
zod (v4) Schema validation โ€” request/response, env vars
@aws-sdk/client-* AWS SDK โ€” S3, SQS, Cognito, DocumentDB
winston Structured logging
testcontainers PostgreSQL testcontainers for integration tests
vitest Test runner
biome Linting + formatting
turbo Monorepo build orchestration
lefthook Git hooks management