# Docker Build Fix Summary

## Issue
When deploying to Google Cloud, the application failed with:
```
Error: Cannot find module '/app/apps/api/dist/index.js'
```

## Root Causes

### 1. Missing `.dockerignore`
- Local `dist/` folders were being copied into the Docker build context
- This caused nested `dist/dist/` structures and incorrect file locations

### 2. TypeScript Compilation Structure  
- `tsconfig.json` was missing `rootDir: "./src"` 
- TypeScript compiled `src/index.ts` to `dist/src/index.js` instead of `dist/index.js`
- The start script expected `dist/index.js`

### 3. pnpm Symlink Issues
- Docker's `COPY` command was not preserving pnpm's symlink structure
- `node_modules` were copied but symlinks to packages in `.pnpm/` were lost
- Node.js couldn't resolve packages like `@hono/node-server`

## Solutions Implemented

### 1. Created `.dockerignore` at Repository Root
```
**/dist
**/node_modules
**/__tests__
# ... and other build artifacts
```

This ensures Docker doesn't copy local build artifacts into the image.

### 2. Updated `apps/api/tsconfig.json`
Added:
```json
{
  "compilerOptions": {
    "rootDir": "./src",
    // ...
  },
  "include": ["src/**/*"]
}
```

This ensures TypeScript compiles `src/index.ts` → `dist/index.js` (not `dist/src/index.js`).

### 3. Fixed Dockerfile Dependency Installation
Changed from copying `node_modules` to installing them fresh in the final stage:

**Before:**
```dockerfile
COPY --from=prod-deps /app/node_modules ./node_modules
```

**After:**
```dockerfile
# Copy built files and workspace structure
COPY --from=build /app/apps/api/dist ./apps/api/dist
COPY --from=build /app/apps/api/package.json ./apps/api/package.json
COPY --from=prod-deps /app/packages ./packages

# Install dependencies with proper symlinks
RUN pnpm install --frozen-lockfile --prod --filter @xtablo/api...
```

This ensures pnpm creates proper symlinks in `/app/apps/api/node_modules/` that point to packages in `/app/node_modules/.pnpm/`.

### 4. Updated `cloudbuild.yaml`
Changed build command to run from monorepo root:

**Before:**
```yaml
args: [ 'build', '--target', '$_NODE_ENV', '-t', '...', 'apps/api' ]
```

**After:**
```yaml
args: [ 'build', '-f', 'apps/api/Dockerfile', '--target', '$_NODE_ENV', '-t', '...', '.' ]
```

## Verification

### Module Resolution Test
```bash
docker run --rm --entrypoint sh xtablo-api:production -c \
  "ls -la /app/apps/api/node_modules/@hono/"
```

Shows proper symlinks:
```
lrwxrwxrwx node-server -> ../../../../node_modules/.pnpm/@hono+node-server@...
```

### Application Start Test
```bash
docker run --rm -e SUPABASE_URL=test -e SUPABASE_SERVICE_ROLE_KEY=test \
  xtablo-api:production
```

Application starts successfully (fails only on missing GCP credentials, not module resolution).

## Final Image Details
- **Size**: 1GB (production)
- **Node.js**: 18.20.8
- **pnpm**: 10.19.0
- **User**: nodejs (non-root, UID 1001)
- **Working Directory**: `/app/apps/api`
- **Module Structure**: Proper pnpm workspace with symlinks

## Files Modified

1. `/apps/api/Dockerfile` - Updated multi-stage build
2. `/apps/api/tsconfig.json` - Added `rootDir` and `include`
3. `/apps/api/cloudbuild.yaml` - Fixed build context
4. `/.dockerignore` - Created to exclude build artifacts
5. `/apps/api/DOCKER_BUILD.md` - Added comprehensive documentation

## Key Takeaways

1. **Always use `.dockerignore`** to prevent local artifacts from contaminating Docker builds
2. **pnpm symlinks require special handling** - install dependencies in the final stage rather than copying
3. **TypeScript `rootDir` matters** - set it explicitly to control output structure
4. **Monorepo builds must run from root** - use `-f` flag to specify Dockerfile location

## Testing in Production

The image is now ready for deployment. All module resolution issues are fixed. Make sure to provide proper environment variables at runtime:

```bash
docker run -p 8080:8080 \
  -e SUPABASE_URL=... \
  -e SUPABASE_SERVICE_ROLE_KEY=... \
  -e STREAM_API_KEY=... \
  -e STREAM_SECRET=... \
  # ... other env vars
  xtablo-api:production
```

## Date
Fixed: November 13, 2024

