memory-journal-mcp 7.2.0 → 7.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -64
- package/dist/{chunk-GR4T3SRW.js → chunk-5ZA77VUW.js} +688 -121
- package/dist/{chunk-ORV7ZZOE.js → chunk-P5V2VY6N.js} +365 -74
- package/dist/{chunk-IWKLHSPU.js → chunk-WXDEVIFL.js} +6 -6
- package/dist/cli.js +9 -4
- package/dist/github-integration-YODGZH3K.js +1 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +3 -3
- package/dist/{tools-CXR2FEB2.js → tools-WZUENKJ6.js} +2 -2
- package/package.json +4 -4
- package/skills/README.md +5 -1
- package/skills/docker/SKILL.md +262 -0
- package/skills/github-actions/SKILL.md +315 -0
- package/skills/package.json +5 -1
- package/skills/python/SKILL.md +257 -0
- package/skills/tailwind-css/SKILL.md +268 -0
- package/dist/github-integration-2TFMXHIJ.js +0 -1
|
@@ -35,7 +35,7 @@ var ERROR_SUGGESTIONS = [
|
|
|
35
35
|
{
|
|
36
36
|
pattern: /SQLITE_CONSTRAINT|unique constraint/i,
|
|
37
37
|
suggestion: "A uniqueness or integrity constraint was violated. Check input values.",
|
|
38
|
-
code: "
|
|
38
|
+
code: "VALIDATION_ERROR"
|
|
39
39
|
},
|
|
40
40
|
// Disk / space patterns
|
|
41
41
|
{
|
|
@@ -46,18 +46,18 @@ var ERROR_SUGGESTIONS = [
|
|
|
46
46
|
{
|
|
47
47
|
pattern: /malformed|invalid json|unexpected token/i,
|
|
48
48
|
suggestion: "The input appears malformed. Check the format and try again.",
|
|
49
|
-
code: "
|
|
49
|
+
code: "VALIDATION_ERROR"
|
|
50
50
|
},
|
|
51
51
|
// Schema / types patterns
|
|
52
52
|
{
|
|
53
53
|
pattern: /invalid input syntax for type|requires a.*column/i,
|
|
54
54
|
suggestion: "The provided value is not valid for the assigned type.",
|
|
55
|
-
code: "
|
|
55
|
+
code: "VALIDATION_ERROR"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
pattern: /^Missing required parameters:/i,
|
|
59
59
|
suggestion: "Provide all required parameters in your request.",
|
|
60
|
-
code: "
|
|
60
|
+
code: "VALIDATION_ERROR"
|
|
61
61
|
},
|
|
62
62
|
// Codemode / Sandbox patterns
|
|
63
63
|
{
|
|
@@ -68,7 +68,7 @@ var ERROR_SUGGESTIONS = [
|
|
|
68
68
|
{
|
|
69
69
|
pattern: /code validation failed/i,
|
|
70
70
|
suggestion: "Check for blocked patterns. Use mj.* API instead.",
|
|
71
|
-
code: "
|
|
71
|
+
code: "VALIDATION_ERROR"
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
74
|
pattern: /sandbox.*not initialized/i,
|
|
@@ -148,7 +148,7 @@ var QueryError = class extends MemoryJournalMcpError {
|
|
|
148
148
|
};
|
|
149
149
|
var ValidationError = class extends MemoryJournalMcpError {
|
|
150
150
|
constructor(message, details) {
|
|
151
|
-
super(message, "
|
|
151
|
+
super(message, "VALIDATION_ERROR", "validation" /* VALIDATION */, {
|
|
152
152
|
suggestion: "Check input parameters against the tool schema",
|
|
153
153
|
recoverable: false,
|
|
154
154
|
details
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { VERSION, createServer } from './chunk-
|
|
2
|
-
import { DEFAULT_AUDIT_LOG_MAX_SIZE_BYTES } from './chunk-
|
|
1
|
+
import { VERSION, createServer } from './chunk-5ZA77VUW.js';
|
|
2
|
+
import { DEFAULT_AUDIT_LOG_MAX_SIZE_BYTES } from './chunk-P5V2VY6N.js';
|
|
3
3
|
import './chunk-OKOVZ5QE.js';
|
|
4
|
-
import { logger } from './chunk-
|
|
4
|
+
import { logger } from './chunk-WXDEVIFL.js';
|
|
5
5
|
import { Command } from 'commander';
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
|
|
@@ -35,6 +35,10 @@ program.name("memory-journal-mcp").description("Project context management for A
|
|
|
35
35
|
"--rebuild-index-interval <minutes>",
|
|
36
36
|
"Vector index rebuild interval in minutes, HTTP only (0 = disabled)",
|
|
37
37
|
"0"
|
|
38
|
+
).option(
|
|
39
|
+
"--digest-interval <minutes>",
|
|
40
|
+
"Analytics digest interval in minutes, HTTP only (0 = disabled; recommended: 1440 for daily)",
|
|
41
|
+
"0"
|
|
38
42
|
).option(
|
|
39
43
|
"--sandbox-mode <mode>",
|
|
40
44
|
'Code Mode sandbox: "worker" (production, default) or "vm" (lightweight)',
|
|
@@ -150,7 +154,8 @@ program.name("memory-journal-mcp").description("Project context management for A
|
|
|
150
154
|
backupIntervalMinutes: parseInt(options.backupInterval, 10),
|
|
151
155
|
keepBackups: parseInt(options.keepBackups, 10),
|
|
152
156
|
vacuumIntervalMinutes: parseInt(options.vacuumInterval, 10),
|
|
153
|
-
rebuildIndexIntervalMinutes: parseInt(options.rebuildIndexInterval, 10)
|
|
157
|
+
rebuildIndexIntervalMinutes: parseInt(options.rebuildIndexInterval, 10),
|
|
158
|
+
digestIntervalMinutes: parseInt(options.digestInterval, 10)
|
|
154
159
|
},
|
|
155
160
|
sandboxMode: options.sandboxMode,
|
|
156
161
|
// OAuth 2.1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { GitHubIntegration } from './chunk-WXDEVIFL.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -383,7 +383,7 @@ interface IDatabaseAdapter {
|
|
|
383
383
|
getEntryByIdIncludeDeleted(id: number): JournalEntry | null;
|
|
384
384
|
getEntriesByIds(ids: number[]): Map<number, JournalEntry>;
|
|
385
385
|
calculateImportance(entryId: number): ImportanceResult;
|
|
386
|
-
getRecentEntries(limit?: number, isPersonal?: boolean): JournalEntry[];
|
|
386
|
+
getRecentEntries(limit?: number, isPersonal?: boolean, sortBy?: 'timestamp' | 'importance'): JournalEntry[];
|
|
387
387
|
getEntriesPage(offset: number, limit: number): JournalEntry[];
|
|
388
388
|
getActiveEntryCount(): number;
|
|
389
389
|
updateEntry(id: number, updates: {
|
|
@@ -405,6 +405,7 @@ interface IDatabaseAdapter {
|
|
|
405
405
|
entryType?: EntryType;
|
|
406
406
|
startDate?: string;
|
|
407
407
|
endDate?: string;
|
|
408
|
+
sortBy?: 'timestamp' | 'importance';
|
|
408
409
|
}): JournalEntry[];
|
|
409
410
|
searchByDateRange(startDate: string, endDate: string, options?: {
|
|
410
411
|
entryType?: EntryType;
|
|
@@ -415,6 +416,7 @@ interface IDatabaseAdapter {
|
|
|
415
416
|
prNumber?: number;
|
|
416
417
|
workflowRunId?: number;
|
|
417
418
|
limit?: number;
|
|
419
|
+
sortBy?: 'timestamp' | 'importance';
|
|
418
420
|
}): JournalEntry[];
|
|
419
421
|
getStatistics(groupBy?: 'day' | 'week' | 'month' | 'year', startDate?: string, endDate?: string, projectBreakdown?: boolean): Record<string, unknown>;
|
|
420
422
|
getTagsForEntry(entryId: number): string[];
|
|
@@ -468,6 +470,17 @@ interface IDatabaseAdapter {
|
|
|
468
470
|
getRawDb(): unknown;
|
|
469
471
|
pragma(command: string): void;
|
|
470
472
|
executeRawQuery(sql: string, params?: unknown[]): QueryResult[];
|
|
473
|
+
saveAnalyticsSnapshot(type: string, data: Record<string, unknown>): number;
|
|
474
|
+
getLatestAnalyticsSnapshot(type: string): {
|
|
475
|
+
id: number;
|
|
476
|
+
createdAt: string;
|
|
477
|
+
data: Record<string, unknown>;
|
|
478
|
+
} | null;
|
|
479
|
+
getAnalyticsSnapshots(type: string, limit?: number): {
|
|
480
|
+
id: number;
|
|
481
|
+
createdAt: string;
|
|
482
|
+
data: Record<string, unknown>;
|
|
483
|
+
}[];
|
|
471
484
|
}
|
|
472
485
|
|
|
473
486
|
/**
|
|
@@ -488,6 +501,8 @@ interface SchedulerOptions {
|
|
|
488
501
|
vacuumIntervalMinutes: number;
|
|
489
502
|
/** Vector index rebuild interval in minutes (0 = disabled) */
|
|
490
503
|
rebuildIndexIntervalMinutes: number;
|
|
504
|
+
/** Analytics digest interval in minutes (0 = disabled; recommended: 1440 for daily) */
|
|
505
|
+
digestIntervalMinutes: number;
|
|
491
506
|
}
|
|
492
507
|
|
|
493
508
|
/**
|
|
@@ -510,7 +525,7 @@ type SandboxMode = 'vm' | 'worker';
|
|
|
510
525
|
/**
|
|
511
526
|
* Tool group definitions mapping group names to tool names
|
|
512
527
|
*
|
|
513
|
-
* All
|
|
528
|
+
* All 68 tools are categorized here for filtering support.
|
|
514
529
|
*/
|
|
515
530
|
declare const TOOL_GROUPS: Record<ToolGroup, string[]>;
|
|
516
531
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { VERSION, createServer } from './chunk-
|
|
2
|
-
export { META_GROUPS, TOOL_GROUPS, calculateTokenSavings, filterTools, getAllToolNames, getFilterSummary, getToolFilterFromEnv, getToolGroup, isToolEnabled, parseToolFilter } from './chunk-
|
|
1
|
+
export { VERSION, createServer } from './chunk-5ZA77VUW.js';
|
|
2
|
+
export { META_GROUPS, TOOL_GROUPS, calculateTokenSavings, filterTools, getAllToolNames, getFilterSummary, getToolFilterFromEnv, getToolGroup, isToolEnabled, parseToolFilter } from './chunk-P5V2VY6N.js';
|
|
3
3
|
import './chunk-OKOVZ5QE.js';
|
|
4
|
-
export { logger } from './chunk-
|
|
4
|
+
export { logger } from './chunk-WXDEVIFL.js';
|
|
5
5
|
|
|
6
6
|
// src/types/index.ts
|
|
7
7
|
var DEFAULT_CONFIG = {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { callTool, getGlobalAuditLogger, getTools, initializeAuditLogger } from './chunk-
|
|
1
|
+
export { callTool, getGlobalAuditLogger, getTools, initializeAuditLogger } from './chunk-P5V2VY6N.js';
|
|
2
2
|
import './chunk-OKOVZ5QE.js';
|
|
3
|
-
import './chunk-
|
|
3
|
+
import './chunk-WXDEVIFL.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memory-journal-mcp",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.0",
|
|
4
4
|
"description": "Project context management for AI-assisted development - Persistent knowledge graphs and intelligent context recall across fragmented AI threads",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "tsup",
|
|
19
19
|
"dev": "tsc --watch",
|
|
20
|
-
"lint": "eslint src/",
|
|
21
|
-
"lint:fix": "eslint src/ --fix",
|
|
20
|
+
"lint": "eslint src/ tests/",
|
|
21
|
+
"lint:fix": "eslint src/ tests/ --fix",
|
|
22
22
|
"typecheck": "tsc --noEmit",
|
|
23
23
|
"check": "npm run lint && npm run typecheck",
|
|
24
24
|
"test": "vitest run",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@playwright/test": "^1.59.1",
|
|
77
77
|
"@types/better-sqlite3": "^7.6.13",
|
|
78
78
|
"@types/express": "^5.0.6",
|
|
79
|
-
"@types/node": "^25.
|
|
79
|
+
"@types/node": "^25.6.0",
|
|
80
80
|
"@vitest/coverage-v8": "^4.1.3",
|
|
81
81
|
"eslint": "^10.2.0",
|
|
82
82
|
"globals": "^17.4.0",
|
package/skills/README.md
CHANGED
|
@@ -42,18 +42,22 @@ The markdown body contains the full instructions the agent follows once the skil
|
|
|
42
42
|
| ---------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
43
43
|
| `autonomous-dev` | Harness for autonomous software development — alignment gates, adversarial agents, Git workflows, and CI/CD pipelines |
|
|
44
44
|
| `bun` | Master the Bun all-in-one toolkit — runtime, package manager, test runner, and bundler |
|
|
45
|
+
| `docker` | Production-grade Docker — multi-stage builds, security hardening, Compose v2, BuildKit, and CI/CD integration |
|
|
46
|
+
| `github-actions` | GitHub Actions CI/CD — SHA pinning, reusable workflows, caching, matrix strategies, and artifacts v4 |
|
|
45
47
|
| `github-commander` | GitHub pipeline workflows for orchestrating issues, regressions, and deployments |
|
|
46
48
|
| `gitlab` | Specialized assistant skill for managing repositories, code search, and CI/CD in GitLab |
|
|
47
49
|
| `golang` | Master Go development with production-grade best practices from Google and Uber style guides |
|
|
48
|
-
| `typescript` | Enterprise-grade TypeScript development with type-safe patterns, Zod validation, and modern tooling |
|
|
49
50
|
| `mysql` | Enterprise MySQL production rules — query safety, connection pooling, strict schema configurations |
|
|
50
51
|
| `playwright-standard` | Opinionated guidance for Playwright E2E/API tests, Page Object Models, and CI/CD resilience |
|
|
51
52
|
| `postgres` | Advanced PostgreSQL patterns — indexing layouts, JSONB querying, transactional guardrails, and RLS |
|
|
53
|
+
| `python` | Modern Python engineering — uv, ruff, type hints, pytest, Pydantic v2, and src/ layout project structure |
|
|
52
54
|
| `react-best-practices` | Vercel engineering guidelines for React/Next.js performance, hooks, and bundle optimization |
|
|
53
55
|
| `rust` | Master Rust development using a layer-based "meta-cognition" framework for borrowing, lifetimes, and architecture |
|
|
54
56
|
| `shadcn-ui` | Deep knowledge of shadcn/ui components, patterns, forms, and best practices |
|
|
55
57
|
| `skill-builder` | Guide for creating, evaluating, and refining agent skills — progressive disclosure, triggers, and testing |
|
|
56
58
|
| `sqlite` | Production configurations for concurrency (WAL), typing (STRICT), and data integrity |
|
|
59
|
+
| `tailwind-css` | Tailwind CSS v4 — CSS-first configuration, @theme directive, dark mode, responsive design, and v3 migration |
|
|
60
|
+
| `typescript` | Enterprise-grade TypeScript development with type-safe patterns, Zod validation, and modern tooling |
|
|
57
61
|
| `vitest-standard` | Comprehensive unit testing expertise covering Vitest, TDD, mocking strategies, and test architecture |
|
|
58
62
|
|
|
59
63
|
## GitHub Commander Workflows
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docker
|
|
3
|
+
description: |
|
|
4
|
+
Production-grade Docker and container best practices. Use when writing
|
|
5
|
+
Dockerfiles, configuring Docker Compose, optimizing image size and build
|
|
6
|
+
speed, implementing security hardening, or debugging container issues.
|
|
7
|
+
Triggers on "Docker", "Dockerfile", "container", "Compose", "BuildKit",
|
|
8
|
+
"multi-stage build", "image size", "docker-compose".
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Docker & Container Engineering Standards
|
|
12
|
+
|
|
13
|
+
This skill codifies 2026 Docker best practices — secure, minimal, reproducible container images using BuildKit, multi-stage builds, and Compose v2.
|
|
14
|
+
|
|
15
|
+
## 1. Dockerfile Fundamentals
|
|
16
|
+
|
|
17
|
+
### Always Start With BuildKit Syntax
|
|
18
|
+
|
|
19
|
+
```dockerfile
|
|
20
|
+
# syntax=docker/dockerfile:1
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Place this as the **first line** of every Dockerfile. It enables:
|
|
24
|
+
|
|
25
|
+
- Parallel stage execution
|
|
26
|
+
- Cache mounts (`--mount=type=cache`)
|
|
27
|
+
- Secret mounts (`--mount=type=secret`)
|
|
28
|
+
- Reproducible builds across Docker versions
|
|
29
|
+
|
|
30
|
+
### Base Image Selection
|
|
31
|
+
|
|
32
|
+
| Use Case | Recommended Base | Why |
|
|
33
|
+
| ----------- | ------------------------- | --------------------------------------- |
|
|
34
|
+
| **Node.js** | `node:22-slim` | Debian Slim — small, has essential libs |
|
|
35
|
+
| **Python** | `python:3.13-slim` | Minimal Debian, no build tools |
|
|
36
|
+
| **Go** | `scratch` or `distroless` | Static binary needs nothing |
|
|
37
|
+
| **General** | `debian:bookworm-slim` | Stable, well-patched, small |
|
|
38
|
+
|
|
39
|
+
- **NEVER** use `:latest` — always pin to a specific version tag
|
|
40
|
+
- **Prefer `-slim` variants** over full images to reduce attack surface
|
|
41
|
+
- **Consider `distroless`** for production — no shell, no package manager = minimal attack surface
|
|
42
|
+
|
|
43
|
+
## 2. Multi-Stage Builds (Required for Production)
|
|
44
|
+
|
|
45
|
+
Multi-stage builds are **mandatory** for any production image. They separate build-time dependencies from runtime.
|
|
46
|
+
|
|
47
|
+
```dockerfile
|
|
48
|
+
# syntax=docker/dockerfile:1
|
|
49
|
+
|
|
50
|
+
# ── Stage 1: Build ─────────────────────────────
|
|
51
|
+
FROM node:22-slim AS builder
|
|
52
|
+
WORKDIR /app
|
|
53
|
+
COPY package.json pnpm-lock.yaml ./
|
|
54
|
+
RUN corepack enable && pnpm install --frozen-lockfile
|
|
55
|
+
COPY . .
|
|
56
|
+
RUN pnpm run build
|
|
57
|
+
|
|
58
|
+
# ── Stage 2: Runtime ───────────────────────────
|
|
59
|
+
FROM node:22-slim AS runtime
|
|
60
|
+
WORKDIR /app
|
|
61
|
+
ENV NODE_ENV=production
|
|
62
|
+
|
|
63
|
+
# Create non-root user
|
|
64
|
+
RUN groupadd -r appgroup && useradd -r -g appgroup appuser
|
|
65
|
+
|
|
66
|
+
# Copy ONLY production artifacts
|
|
67
|
+
COPY --from=builder /app/dist ./dist
|
|
68
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
69
|
+
COPY --from=builder /app/package.json ./
|
|
70
|
+
|
|
71
|
+
USER appuser
|
|
72
|
+
EXPOSE 3000
|
|
73
|
+
CMD ["node", "dist/index.js"]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Key Rules
|
|
77
|
+
|
|
78
|
+
- **Name every stage**: `FROM ... AS builder` — makes builds readable and targetable
|
|
79
|
+
- **Copy only artifacts**: Use `COPY --from=builder` to cherry-pick built files
|
|
80
|
+
- **Never install dev dependencies in the runtime stage**
|
|
81
|
+
- **The runtime stage should have ZERO build tools** (no compilers, no git, no curl)
|
|
82
|
+
|
|
83
|
+
## 3. Security Hardening
|
|
84
|
+
|
|
85
|
+
### Non-Root Execution (Mandatory)
|
|
86
|
+
|
|
87
|
+
```dockerfile
|
|
88
|
+
# Create a system user with no home directory, no login shell
|
|
89
|
+
RUN groupadd -r appgroup && useradd -r -g appgroup -s /usr/sbin/nologin appuser
|
|
90
|
+
|
|
91
|
+
# Switch to the non-root user BEFORE CMD
|
|
92
|
+
USER appuser
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- **NEVER** run containers as root in production
|
|
96
|
+
- **NEVER** use `--privileged` flag unless absolutely required
|
|
97
|
+
- **Set `USER` as late as possible** — after all `RUN` commands that need root
|
|
98
|
+
|
|
99
|
+
### Secret Handling
|
|
100
|
+
|
|
101
|
+
```dockerfile
|
|
102
|
+
# ✅ Good: BuildKit secret mount (never stored in layers)
|
|
103
|
+
RUN --mount=type=secret,id=npm_token \
|
|
104
|
+
NPM_TOKEN=$(cat /run/secrets/npm_token) \
|
|
105
|
+
npm config set //registry.npmjs.org/:_authToken=$NPM_TOKEN
|
|
106
|
+
|
|
107
|
+
# ❌ Bad: ARG/ENV secrets (visible in image history)
|
|
108
|
+
ARG NPM_TOKEN
|
|
109
|
+
ENV NPM_TOKEN=$NPM_TOKEN
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- **NEVER** use `ARG` or `ENV` for secrets — they are baked into image layers
|
|
113
|
+
- **NEVER** `COPY` `.env` files into the image
|
|
114
|
+
- Use `--mount=type=secret` (BuildKit) for build-time secrets
|
|
115
|
+
- Use Docker Compose `secrets:` or orchestrator secrets for runtime
|
|
116
|
+
|
|
117
|
+
### Vulnerability Scanning
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
docker scout cves <image> # Docker Scout
|
|
121
|
+
trivy image <image> # Trivy (open source)
|
|
122
|
+
grype <image> # Grype (Anchore)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- Run scanning in CI — **hard-fail** on HIGH/CRITICAL vulnerabilities
|
|
126
|
+
- Never use `continue-on-error: true` for security gates
|
|
127
|
+
|
|
128
|
+
## 4. Layer Optimization
|
|
129
|
+
|
|
130
|
+
### Instruction Ordering
|
|
131
|
+
|
|
132
|
+
Docker caches each layer. Order instructions from **least-changing to most-changing**:
|
|
133
|
+
|
|
134
|
+
```dockerfile
|
|
135
|
+
# 1. Base image (rarely changes)
|
|
136
|
+
FROM node:22-slim
|
|
137
|
+
|
|
138
|
+
# 2. System deps (changes infrequently)
|
|
139
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
140
|
+
dumb-init \
|
|
141
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
142
|
+
|
|
143
|
+
# 3. Application deps (changes when lock file changes)
|
|
144
|
+
COPY package.json pnpm-lock.yaml ./
|
|
145
|
+
RUN pnpm install --frozen-lockfile
|
|
146
|
+
|
|
147
|
+
# 4. Application code (changes most frequently)
|
|
148
|
+
COPY . .
|
|
149
|
+
RUN pnpm build
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Cache Mounts (BuildKit)
|
|
153
|
+
|
|
154
|
+
```dockerfile
|
|
155
|
+
# Cache package manager downloads between builds
|
|
156
|
+
RUN --mount=type=cache,target=/root/.cache/pip \
|
|
157
|
+
pip install -r requirements.txt
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### `.dockerignore` (Required)
|
|
161
|
+
|
|
162
|
+
Create a `.dockerignore` in every project with a Dockerfile:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
.git
|
|
166
|
+
.github
|
|
167
|
+
node_modules
|
|
168
|
+
dist
|
|
169
|
+
*.md
|
|
170
|
+
.env*
|
|
171
|
+
.vscode
|
|
172
|
+
.idea
|
|
173
|
+
tmp/
|
|
174
|
+
coverage/
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
- **ALWAYS** exclude `.git` — it can be hundreds of MB
|
|
178
|
+
- **ALWAYS** exclude `node_modules` — reinstall inside the container
|
|
179
|
+
- **ALWAYS** exclude `.env*` — prevents secret leaks
|
|
180
|
+
|
|
181
|
+
## 5. Docker Compose v2
|
|
182
|
+
|
|
183
|
+
### Structure
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
# docker-compose.yml
|
|
187
|
+
services:
|
|
188
|
+
app:
|
|
189
|
+
build:
|
|
190
|
+
context: .
|
|
191
|
+
dockerfile: Dockerfile
|
|
192
|
+
target: runtime # Target a specific stage
|
|
193
|
+
ports:
|
|
194
|
+
- '3000:3000'
|
|
195
|
+
environment:
|
|
196
|
+
NODE_ENV: production
|
|
197
|
+
depends_on:
|
|
198
|
+
db:
|
|
199
|
+
condition: service_healthy
|
|
200
|
+
restart: unless-stopped
|
|
201
|
+
|
|
202
|
+
db:
|
|
203
|
+
image: postgres:17-alpine
|
|
204
|
+
volumes:
|
|
205
|
+
- pgdata:/var/lib/postgresql/data
|
|
206
|
+
environment:
|
|
207
|
+
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
|
|
208
|
+
secrets:
|
|
209
|
+
- db_password
|
|
210
|
+
healthcheck:
|
|
211
|
+
test: ['CMD-SHELL', 'pg_isready -U postgres']
|
|
212
|
+
interval: 10s
|
|
213
|
+
timeout: 5s
|
|
214
|
+
retries: 5
|
|
215
|
+
|
|
216
|
+
volumes:
|
|
217
|
+
pgdata:
|
|
218
|
+
|
|
219
|
+
secrets:
|
|
220
|
+
db_password:
|
|
221
|
+
file: ./secrets/db_password.txt
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Best Practices
|
|
225
|
+
|
|
226
|
+
- **Use `depends_on` with health checks** — not just service start order
|
|
227
|
+
- **Use named volumes** for persistent data — never bind-mount the entire project in production
|
|
228
|
+
- **Use environment files** (`env_file:`) for non-secret config
|
|
229
|
+
- **Use `secrets:`** for credentials — they are mounted as files, not env vars
|
|
230
|
+
- **Pin image versions** — `postgres:17-alpine`, not `postgres:latest`
|
|
231
|
+
|
|
232
|
+
## 6. CI/CD Integration
|
|
233
|
+
|
|
234
|
+
### GitHub Actions Pattern
|
|
235
|
+
|
|
236
|
+
```yaml
|
|
237
|
+
- name: Build and push
|
|
238
|
+
uses: docker/build-push-action@<sha>
|
|
239
|
+
with:
|
|
240
|
+
context: .
|
|
241
|
+
push: true
|
|
242
|
+
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
|
|
243
|
+
cache-from: type=gha
|
|
244
|
+
cache-to: type=gha,mode=max
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
- **Use GitHub Actions cache** (`type=gha`) for CI builds
|
|
248
|
+
- **Tag with commit SHA** — never `:latest` for production
|
|
249
|
+
- **Scan before push** — run vulnerability scanning as a build step
|
|
250
|
+
|
|
251
|
+
## 7. Anti-Patterns (Never Do These)
|
|
252
|
+
|
|
253
|
+
| Anti-Pattern | Why It's Wrong | Do This Instead |
|
|
254
|
+
| -------------------------- | --------------------------------------- | ----------------------------------------------- |
|
|
255
|
+
| `FROM ubuntu:latest` | Unpinned, large, unpredictable | Pin version, use `-slim` |
|
|
256
|
+
| `RUN apt-get update` alone | Cache goes stale across builds | Combine with `install` in one `RUN` |
|
|
257
|
+
| `ADD` for local files | Unpredictable (auto-extracts) | Use `COPY` explicitly |
|
|
258
|
+
| Multiple `RUN apt-get` | Creates unnecessary layers | Chain with `&&` in one `RUN` |
|
|
259
|
+
| `COPY . .` before deps | Breaks layer cache on every code change | Copy lock file first, install, then copy source |
|
|
260
|
+
| Running as root | Security vulnerability | Create and switch to `appuser` |
|
|
261
|
+
| Secrets in `ENV`/`ARG` | Visible in image history | Use `--mount=type=secret` |
|
|
262
|
+
| No `.dockerignore` | Bloated context, potential secret leaks | Always create one |
|