From ff506af2c80e8f10a223e49f0e31364d7aabed5c Mon Sep 17 00:00:00 2001 From: Assem Hafez Date: Fri, 27 Mar 2026 18:49:19 +0100 Subject: [PATCH 1/3] update docker image --- Dockerfile | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/Dockerfile b/Dockerfile index 305a4acf7..37299df35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,33 +1,21 @@ -FROM node:18-alpine AS base - -RUN apk update -RUN apk --no-cache add git -# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. -RUN apk add --no-cache libc6-compat - -# Install dependencies only when needed -FROM base AS deps -WORKDIR /app - -# Install dependencies based on the preferred package manager -COPY package.json package-lock.json ./ -RUN npm ci -RUN npm run install-idl - - +FROM node:18-bookworm-slim AS base FROM base AS dev - +# Install git + CA bundle so git https can verify TLS +RUN apt-get update \ + && apt-get install -y --no-install-recommends git ca-certificates WORKDIR /app -COPY --from=deps /app/node_modules ./node_modules COPY . . - # Rebuild the source code only when needed FROM base AS builder WORKDIR /app -COPY --from=deps /app/node_modules ./node_modules +RUN apt-get update \ + && apt-get install -y --no-install-recommends git ca-certificates +COPY package.json package-lock.json ./ +RUN npm ci +RUN npm run install-idl COPY . . # Next.js collects completely anonymous telemetry data about general usage. @@ -36,12 +24,13 @@ COPY . . ENV NEXT_TELEMETRY_DISABLED 1 # optimize Build size by including only required resources -RUN npm run generate:idl -RUN npm run build + +RUN npm run generate:idl --verbose + RUN npm run build-standalone RUN npm run post-build-standalone -# Production image, copy all the files and run next +# Production image, copy necessary files and run next FROM base AS runner WORKDIR /app @@ -61,7 +50,7 @@ RUN chown nextjs:nodejs .next # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=builder --chown=nextjs:nodejs /app/src/__generated__/ ./src/__generated__/ +COPY --from=builder --chown=nextjs:nodejs /app/src/__generated__/ ./src/__generated__/ COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static From e8b06b99f17caef277b63cec4b61bc0bc202d893 Mon Sep 17 00:00:00 2001 From: Assem Hafez Date: Fri, 27 Mar 2026 19:16:25 +0100 Subject: [PATCH 2/3] update env variables --- Dockerfile | 9 +- agents.md | 803 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 807 insertions(+), 5 deletions(-) create mode 100644 agents.md diff --git a/Dockerfile b/Dockerfile index 37299df35..d6007030d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,12 +21,11 @@ COPY . . # Next.js collects completely anonymous telemetry data about general usage. # Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry during the build. -ENV NEXT_TELEMETRY_DISABLED 1 +ENV NEXT_TELEMETRY_DISABLED=1 # optimize Build size by including only required resources -RUN npm run generate:idl --verbose - +RUN npm run generate:idl RUN npm run build-standalone RUN npm run post-build-standalone @@ -34,9 +33,9 @@ RUN npm run post-build-standalone FROM base AS runner WORKDIR /app -ENV NODE_ENV production +ENV NODE_ENV=production # Uncomment the following line in case you want to disable telemetry during runtime. -ENV NEXT_TELEMETRY_DISABLED 1 +ENV NEXT_TELEMETRY_DISABLED=1 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs diff --git a/agents.md b/agents.md new file mode 100644 index 000000000..25f7850cd --- /dev/null +++ b/agents.md @@ -0,0 +1,803 @@ +# Cadence Web UI - Development Guidelines for AI Agents + +This document provides comprehensive guidelines for AI agents working with the Cadence Web UI codebase. It outlines the established patterns, conventions, and architectural decisions to ensure consistent and maintainable code. + +## Table of Contents + +- [Project Overview](#project-overview) +- [Architecture Patterns](#architecture-patterns) +- [File Organization](#file-organization) +- [Component Patterns](#component-patterns) +- [Route Handler Patterns](#route-handler-patterns) +- [URL Params and Encoding](#url-params-and-encoding) +- [TypeScript Conventions](#typescript-conventions) +- [Styling Patterns](#styling-patterns) +- [Configuration Patterns](#configuration-patterns) +- [Testing Patterns](#testing-patterns) +- [Utility Patterns](#utility-patterns) +- [Hook Patterns](#hook-patterns) +- [Error Handling](#error-handling) +- [Performance Considerations](#performance-considerations) + +## Project Overview + +Cadence Web UI is a Next.js 14 application built with TypeScript, React 18, and BaseUI. It provides a web interface for viewing and managing Cadence workflows, domains, and task lists. + +### Key Technologies +- **Framework**: Next.js 14 with App Router +- **Language**: TypeScript +- **UI Library**: BaseUI (Uber's design system) +- **Styling**: Styletron (CSS-in-JS) +- **State Management**: TanStack Query (React Query) +- **Form Handling**: React Hook Form with Zod validation +- **Testing**: Jest with React Testing Library +- **Build Tool**: Webpack (via Next.js) + +## Architecture Patterns + +### 1. App Router Structure +The application uses Next.js App Router with the following structure: +``` +src/app/ +├── (Home)/ # Route groups +├── api/ # API routes +├── layout.tsx # Root layout +├── page.tsx # Home page +└── not-found.tsx # 404 page +``` + +### 2. Feature-Based Organization +Components and views are organized by feature rather than by type: +``` +src/ +├── components/ # Reusable abstract UI components (design system) +├── views/ # Page-level components +│ └── shared/ # Business logic components for Cadence objects +├── route-handlers/ # API route handlers +├── hooks/ # Custom React hooks +├── utils/ # Utility functions +└── config/ # Configuration files +``` + +### 3. Component Directory Distinction + +**`src/components/`** - Reusable Abstract Components: +- Generic UI components that are framework-agnostic +- Design system components (buttons, inputs, tables, etc.) +- Components that can be used across different domains +- No business logic or Cadence-specific functionality +- Examples: `Button`, `Table`, `PageSection`, `ErrorBoundary` + +**`src/views/shared/`** - Reusable Business Logic Components: +- Components with Cadence-specific business logic +- Components that fetch and render Cadence objects (workflows, domains, etc.) +- Components that understand Cadence data structures +- Components that integrate with Cadence APIs +- Examples: `WorkflowStatusTag`, `DomainStatusTag`, `WorkflowActions` + +```typescript +// src/components/ - Abstract, reusable +export default function Button({ children, onClick }: ButtonProps) { + return ; +} + +// src/views/shared/ - Business logic, Cadence-specific +export default function WorkflowStatusTag({ + status, + isArchived +}: WorkflowStatusTagProps) { + const statusConfig = getWorkflowStatusConfig(status, isArchived); + return ; +} +``` + +## File Organization + +### 1. Component Structure +Each component follows a consistent file structure: + +``` +component-name/ +├── component-name.tsx # Main component +├── component-name.types.ts # TypeScript types +├── component-name.styles.ts # Styled components +├── __tests__/ # Test files +│ └── component-name.test.tsx +└── __fixtures__/ # Test fixtures (if needed) + └── component-name.fixtures.ts +``` + +### 2. Naming Conventions +- **Files**: kebab-case (`component-name.tsx`) +- **Components**: PascalCase (`ComponentName`) +- **Types**: PascalCase with descriptive suffixes (`ComponentProps`, `ComponentConfig`) +- **Constants**: UPPER_SNAKE_CASE (`DEFAULT_TIMEOUT_SECONDS`) +- **Functions**: camelCase (`getComponentData`) + +### 3. Directory Nesting Limits +Limit directory nesting to maintain a clean and navigable codebase structure. Maximum nesting levels: + +**`src/views/`** - Two levels maximum: +``` +src/views/ +├── domain-page/ # Level 1: Page +│ ├── domain-page-header/ # Level 2: Page component +│ │ ├── domain-page-header.tsx +│ │ ├── domain-page-header.types.ts +│ │ └── __tests__/ # Level 3: Tests (allowed) +│ │ └── domain-page-header.test.tsx +│ └── domain-page-tabs/ +│ ├── domain-page-tabs.tsx +│ └── __tests__/ +│ └── domain-page-tabs.test.tsx +└── workflow-page/ + ├── workflow-page-header/ + └── workflow-page-tabs/ +``` + +**`src/components/`** - Two levels maximum: +``` +src/components/ +├── table/ # Level 1: Component +│ ├── table.tsx +│ ├── table.types.ts +│ ├── table-head-cell/ # Level 2: Sub-component +│ │ ├── table-head-cell.tsx +│ │ └── __tests__/ # Level 3: Tests (allowed) +│ │ └── table-head-cell.test.tsx +│ └── table-body-cell/ +│ ├── table-body-cell.tsx +│ └── __tests__/ +│ └── table-body-cell.test.tsx +└── button/ + ├── button.tsx + └── __tests__/ + └── button.test.tsx +``` + +**Guidelines:** +- **Level 1**: Main feature/page/component directories +- **Level 2**: Sub-components, utilities, or related files +- **Level 3**: Only `__tests__/` directories are allowed at this level +- **Avoid**: Deeper nesting that makes navigation difficult +- **Refactor**: If you need more than 3 levels, consider splitting into separate features or components + +## Component Patterns + +### 1. Component Definition +```typescript +import React from 'react'; +import { styled } from './component-name.styles'; +import { type Props } from './component-name.types'; + +export default function ComponentName({ prop1, prop2 }: Props) { + return ( + + {/* Component content */} + + ); +} +``` + +### 2. Props Interface +```typescript +export type Props = { + requiredProp: string; + optionalProp?: number; + children?: React.ReactNode; +}; +``` + +### 3. Styled Components +```typescript +import { styled as createStyled, type Theme } from 'baseui'; + +export const styled = { + Container: createStyled('div', ({ $theme }: { $theme: Theme }) => ({ + display: 'flex', + flexDirection: 'column', + gap: $theme.sizing.scale500, + })), +}; +``` + +### 4. Component Composition +- Use composition over inheritance +- Prefer render props and children patterns +- Keep components focused and single-purpose +- Use TypeScript generics for reusable components + +## Route Handler Patterns + +### 1. Handler Structure +```typescript +import { type NextRequest, NextResponse } from 'next/server'; +import { getHTTPStatusCode, GRPCError } from '@/utils/grpc/grpc-error'; +import logger, { type RouteHandlerErrorPayload } from '@/utils/logger'; + +import { type Context, type RequestParams } from './handler-name.types'; +import requestBodySchema from './schemas/request-body-schema'; + +export async function handlerName( + request: NextRequest, + requestParams: RequestParams, + ctx: Context +) { + const requestBody = await request.json(); + const { data, error } = requestBodySchema.safeParse(requestBody); + + if (error) { + return NextResponse.json( + { + message: 'Invalid values provided', + validationErrors: error.errors, + }, + { status: 400 } + ); + } + + const params = requestParams.params; // Next.js already decodes route params—do not decode again + + try { + const response = await ctx.grpcClusterMethods.someMethod({ + // Method parameters from params + }); + + return NextResponse.json(response); + } catch (e) { + logger.error( + { requestParams: params, error: e }, + 'Error description' + ); + + return NextResponse.json( + { + message: e instanceof GRPCError ? e.message : 'Error message', + cause: e, + }, + { status: getHTTPStatusCode(e) } + ); + } +} +``` + +### 2. Validation Patterns +- Use Zod schemas for request validation +- Validate both request body and URL parameters +- Return structured error responses with validation details + +### 3. Error Handling +- Use structured error logging with context +- Handle gRPC errors specifically +- Return appropriate HTTP status codes +- Include error causes for debugging + +## URL Params and Encoding + +Next.js App Router provides **already decoded** `params` and `searchParams` to API route handlers, pages, and layouts. Dynamic segment and catch-all values are decoded once by the framework. + +- **Do not** call `decodeUrlParams()` or `decodeURIComponent()` on `requestParams.params`, `options.params`, or page/layout `params`. Doing so double-decodes and can cause `URIError` or corrupted values (e.g. task list names containing `%` or `@`). +- **Do** use `encodeURIComponent()` when building URLs from user input (e.g. before `href`, `router.push()`, or `fetch(url)`). +- **Rule of thumb:** If the value comes from Next.js (route handler `params`, page `params`, or `searchParams`), treat it as already decoded. + +## TypeScript Conventions + +### 1. Type Definitions +```typescript +// Use descriptive type names +export type WorkflowExecutionStatus = 'RUNNING' | 'COMPLETED' | 'FAILED'; + +// Use generics for reusable types +export type ListTableItem = { + key: string; + label: string; + renderValue: React.ComponentType | ((props: T) => React.ReactNode); +}; + +// Use utility types +export type Props = { + data: T; + config: Array>; +}; +``` + +### 2. Interface vs Type +- Use `type` for unions, intersections, and computed types +- Use `interface` for object shapes that might be extended +- Prefer `type` for most cases in this codebase + +### 3. Generic Constraints +```typescript +// Use meaningful constraints +export default function Table>({ + data, + columns, +}: Props) { + // Implementation +} +``` + +## Styling Patterns + +### 1. Styled Components Structure +```typescript +import { styled as createStyled, type Theme } from 'baseui'; +import { type StyleObject } from 'styletron-react'; + +export const styled = { + Container: createStyled( + 'div', + ({ $theme }: { $theme: Theme }): StyleObject => ({ + display: 'flex', + flexDirection: 'column', + gap: $theme.sizing.scale500, + // Use theme values consistently + }) + ), +}; +``` + +### 2. Theme Usage +- Always use theme values for spacing, colors, and typography +- Use `$theme.sizing.scale*` for consistent spacing +- Use `$theme.colors.*` for colors +- Use `$theme.typography.*` for text styles + +### 3. Responsive Design +```typescript +// Use media queries from theme +{ + [$theme.mediaQuery.medium]: { + flexDirection: 'row', + }, +} +``` + +## Configuration Patterns + +### 1. Dynamic Configuration +```typescript +// config/dynamic/dynamic.config.ts +const dynamicConfigs: { + FEATURE_FLAG: ConfigAsyncResolverDefinition< + FeatureFlagParams, + boolean, + 'request', + true + >; +} = { + FEATURE_FLAG: { + resolver: featureFlagResolver, + evaluateOn: 'request', + isPublic: true, + }, +}; +``` + +### 2. Environment Variables +- Use descriptive names with `CADENCE_` prefix +- Provide sensible defaults +- Document all environment variables in README.md + +### 3. Feature Flags +- Use environment variables for simple flags +- Use dynamic config for complex feature toggles +- Make feature flags public when needed for client-side logic + +## Testing Patterns + +### 1. Test File Naming Conventions + +**Browser Tests** (`.test.tsx`): +- All React components and UI-related functionality +- Client-side utilities and hooks +- Browser-specific APIs and features +- User interactions and DOM manipulation + +**Server Tests** (`.node.ts`): +- API route handlers +- Server-side utilities +- Node.js-specific modules +- Modules that use Node.js APIs (fs, path, etc.) + +```typescript +// Browser test example: component.test.tsx +import React from 'react'; +import { render, screen } from '@/test-utils/rtl'; +import ComponentName from '../component-name'; + +describe(ComponentName.name, () => { + it('should render correctly', () => { + // Browser test logic + }); +}); + +// Server test example: utility.node.ts +import utilityFunction from '../utility-function'; + +describe('utilityFunction', () => { + it('should handle server-side logic', () => { + // Server test logic + }); +}); +``` + +**Default Rule**: Use `.test.tsx` unless the code is specifically server-only or uses Node.js APIs. + +### 2. Running Individual Tests +To run a single test file for validation during development: + +**Browser Tests** (`.test.tsx`): +```bash +npm run test:unit:browser {fileName} +``` + +**Server Tests** (`.node.ts`): +```bash +npm run test:unit:node {fileName} +``` + +**Examples:** +```bash +# Run a specific browser test +npm run test:unit:browser cron-schedule-input.test.tsx + +# Run a specific server test +npm run test:unit:node cron-validate.node.ts + +# Run all browser tests +npm run test:unit:browser + +# Run all server tests +npm run test:unit:node +``` + +### 3. Test Structure +```typescript +import React from 'react'; +import { render, screen, userEvent } from '@/test-utils/rtl'; + +import ComponentName from '../component-name'; + +describe(ComponentName.name, () => { + it('should render correctly', () => { + setup({}); + + expect(screen.getByRole('button')).toBeInTheDocument(); + }); + + it('should handle user interactions', async () => { + const { user, mockHandler } = setup({}); + + await user.click(screen.getByRole('button')); + + expect(mockHandler).toHaveBeenCalledWith(expectedArgs); + }); +}); + +function setup(props: Partial) { + const mockHandler = jest.fn(); + const user = userEvent.setup(); + + render(); + + return { user, mockHandler }; +} +``` + +### 4. Setup Method Best Practices +**Always use a `setup` function when tests share common initialization steps.** This pattern provides: + +**Benefits:** +- **Consistency**: Ensures all tests use the same initialization logic +- **Maintainability**: Changes to setup logic only need to be made in one place +- **Readability**: Tests focus on behavior rather than setup boilerplate +- **Flexibility**: Easy to override defaults for specific test cases + +**When to Use Setup:** +- Multiple tests need similar steps +- Tests require mock handlers or event handlers +- Tests need userEvent instances for interactions +- Tests share common prop configurations +- Tests need error boundary or provider setup + +**Setup Function Responsibilities:** +```typescript +function setup(props: Partial = {}) { + // 1. Create mock handlers + const mockHandler = jest.fn(); + const mockErrorHandler = jest.fn(); + + // 2. Setup userEvent instance + const user = userEvent.setup(); + + // 3. Provide default props with overrides + const defaultProps: Props = { + title: 'Default Title', + isEnabled: true, + onAction: mockHandler, + onError: mockErrorHandler, + ...props, // Allow test-specific overrides + }; + + // 4. Render component with providers if needed + render( + + + + ); + + // 5. Return commonly used test utilities + return { + user, + mockHandler, + mockErrorHandler, + // Return screen for convenience + screen, + }; +} +``` + +**Usage Examples:** +```typescript +describe(ComponentName.name, () => { + it('should render with default props', () => { + setup(); // Uses all defaults + + expect(screen.getByText('Default Title')).toBeInTheDocument(); + }); + + it('should render with custom props', () => { + setup({ title: 'Custom Title', isEnabled: false }); + + expect(screen.getByText('Custom Title')).toBeInTheDocument(); + expect(screen.getByRole('button')).toBeDisabled(); + }); + + it('should handle user interactions', async () => { + const { user, mockHandler } = setup(); + + await user.click(screen.getByRole('button')); + + expect(mockHandler).toHaveBeenCalledTimes(1); + }); +}); +``` + +### 5. Test Utilities +- Use custom test utilities from `@/test-utils/rtl` +- Create setup functions for complex test scenarios +- Use fixtures for test data +- Mock external dependencies appropriately + +### 6. Test Coverage +- Test user interactions, not implementation details +- Test error states and edge cases +- Use descriptive test names +- Group related tests with `describe` blocks + +### 7. Component Mocking +Mock child components in unit tests to isolate the parent component's behavior and allow for flexible testing of sub-behaviors in forks: + +```typescript +import React from 'react'; +import { render, screen } from '@/test-utils/rtl'; + +// Mock child components +jest.mock('../child-component', () => { + return function MockChildComponent({ onAction, data }: any) { + return ( +
+ +
+ ); + }; +}); + +import ParentComponent from '../parent-component'; + +describe(ParentComponent.name, () => { + it('should handle child component interactions', () => { + const mockHandler = jest.fn(); + render(); + + // Test parent component behavior without depending on child implementation + expect(screen.getByTestId('mock-child-component')).toBeInTheDocument(); + }); +}); +``` + +**Benefits of Component Mocking:** +- **Isolation**: Test parent component logic independently of child component implementation +- **Flexibility**: Allow forks to modify child component behavior without breaking parent tests +- **Performance**: Faster test execution by avoiding complex child component rendering +- **Maintainability**: Reduce test brittleness when child components change +- **Focus**: Concentrate on testing the specific behavior of the component under test + +## Utility Patterns + +### 1. Utility Function Structure +```typescript +/** + * Brief description of what the function does. + * + * @param param1 - Description of parameter + * @param param2 - Description of parameter + * @returns Description of return value + */ +export default function utilityFunction( + param1: string, + param2: T +): ReturnType { + // Implementation with proper error handling + try { + // Logic here + return result; + } catch (error) { + logger.warn({ param1, param2, error }, 'Utility function failed'); + return defaultValue; + } +} +``` + +### 2. Error Handling in Utilities +- Use structured logging with context +- Return sensible defaults when possible +- Don't throw errors unless absolutely necessary +- Use TypeScript for type safety + +### 3. Generic Utilities +```typescript +// Use generics for reusable utilities +export default function processArray( + array: T[], + processor: (item: T) => R +): R[] { + return array.map(processor); +} +``` + +## Hook Patterns + +### 1. Custom Hook Structure +```typescript +import { useCallback, useState, useMemo } from 'react'; +import { type Props, type ReturnType } from './hook-name.types'; + +export default function useHookName({ + initialValue, + options, +}: Props): ReturnType { + const [state, setState] = useState(initialValue); + + const computedValue = useMemo(() => { + // Expensive computation + return processState(state); + }, [state]); + + const handler = useCallback((newValue: T) => { + setState(newValue); + }, []); + + return { + state, + computedValue, + handler, + }; +} +``` + +### 2. Hook Types +```typescript +export type Props = { + initialValue: T; + options?: HookOptions; +}; + +export type ReturnType = { + state: T; + computedValue: ProcessedValue; + handler: (value: T) => void; +}; +``` + +### 3. Hook Best Practices +- Use TypeScript generics for reusable hooks +- Memoize expensive computations +- Use `useCallback` for event handlers +- Return objects for multiple values +- Provide clear prop and return types + +## Error Handling + +### 1. Error Boundaries +```typescript +import { ErrorBoundary } from 'react-error-boundary'; + +export default function ErrorBoundaryWrapper({ children }: Props) { + return ( + { + logger.error({ error, errorInfo }, 'Component error boundary triggered'); + }} + > + {children} + + ); +} +``` + +### 2. Structured Logging +```typescript +// Use structured logging with context +logger.error( + { requestParams, error, userId }, + 'Descriptive error message' +); +``` + +### 3. Error Types +```typescript +// Define specific error types +export class ValidationError extends Error { + constructor(message: string, public validationErrors: ValidationError[]) { + super(message); + this.name = 'ValidationError'; + } +} +``` + +## Performance Considerations + +### 1. Code Splitting +- Use dynamic imports for large components +- Implement route-based code splitting +- Lazy load non-critical features + +### 2. Memoization +```typescript +// Use React.memo for expensive components +export default React.memo(function ExpensiveComponent({ data }: Props) { + // Component implementation +}); + +// Use useMemo for expensive calculations +const processedData = useMemo(() => { + return expensiveCalculation(data); +}, [data]); +``` + +### 3. Virtualization +- Use `react-virtuoso` for large lists +- Implement virtual scrolling for tables +- Consider pagination for large datasets + +### 4. Bundle Optimization +- Use tree shaking effectively +- Minimize bundle size with proper imports +- Use dynamic imports for optional features + +## Best Practices Summary + +1. **Consistency**: Follow established patterns throughout the codebase +2. **Type Safety**: Use TypeScript effectively with proper types and generics +3. **Error Handling**: Implement comprehensive error handling and logging +4. **Testing**: Write meaningful tests that focus on user behavior +5. **Performance**: Consider performance implications of all changes +6. **Documentation**: Document complex logic and architectural decisions +7. **Accessibility**: Ensure components are accessible and follow WCAG guidelines +8. **Security**: Validate all inputs and handle sensitive data appropriately + +## Common Pitfalls to Avoid + +1. **Don't** bypass TypeScript types with `any` +2. **Don't** create components without proper error boundaries +3. **Don't** ignore performance implications of re-renders +4. **Don't** hardcode values that should come from configuration +5. **Don't** skip validation for user inputs +6. **Don't** forget to handle loading and error states +7. **Don't** create overly complex components - split them up +8. **Don't** ignore accessibility requirements + +This document should be updated as new patterns emerge and existing patterns evolve. Always refer to the existing codebase for the most current examples of these patterns in practice. From 97139fd89e8a585be0677ebd55997579c94e26a0 Mon Sep 17 00:00:00 2001 From: Assem Hafez Date: Fri, 27 Mar 2026 19:19:47 +0100 Subject: [PATCH 3/3] remove apt-get cache --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index d6007030d..0f28423ad 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,8 @@ FROM node:18-bookworm-slim AS base FROM base AS dev # Install git + CA bundle so git https can verify TLS RUN apt-get update \ - && apt-get install -y --no-install-recommends git ca-certificates + && apt-get install -y --no-install-recommends git ca-certificates \ + && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY . .