Skip to content

Commit 8a56ce3

Browse files
feat: add environment configuration and documentation
- Add .env.example template with required environment variables - Create ENV_SETUP.md documentation for environment configuration - Implement env-config.ts utility for centralized environment management - Update processor edge cases tests to handle new configuration - Update dependencies to support environment configuration
1 parent 56180e9 commit 8a56ce3

6 files changed

Lines changed: 338 additions & 0 deletions

File tree

.env.example

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Auto Image Diff - Environment Configuration
2+
# Copy this file to .env and update with your values
3+
4+
# Node Environment
5+
NODE_ENV=development
6+
7+
# Logging Configuration
8+
LOG_LEVEL=info
9+
LOG_FORMAT=json
10+
11+
# Performance Settings
12+
MAX_WORKERS=4
13+
BATCH_SIZE=10
14+
MEMORY_LIMIT=4096
15+
16+
# Image Processing Settings
17+
IMAGE_QUALITY=85
18+
MAX_IMAGE_SIZE=10485760
19+
DIFF_THRESHOLD=0.1
20+
21+
# Output Configuration
22+
OUTPUT_DIR=./output
23+
ENABLE_HTML_REPORTS=true
24+
ENABLE_JSON_REPORTS=true
25+
26+
# Cache Settings
27+
ENABLE_CACHE=true
28+
CACHE_DIR=./cache
29+
CACHE_TTL=86400
30+
31+
# Debug Mode
32+
DEBUG_MODE=false
33+
VERBOSE_OUTPUT=false
34+
35+
# API/Service URLs (for future integrations)
36+
# API_BASE_URL=https://api.example.com
37+
# API_KEY=your-api-key-here
38+
39+
# AWS S3 (for future cloud storage)
40+
# AWS_REGION=us-east-1
41+
# AWS_BUCKET=auto-image-diff-storage
42+
# AWS_ACCESS_KEY_ID=your-access-key
43+
# AWS_SECRET_ACCESS_KEY=your-secret-key
44+
45+
# Database (for future metadata storage)
46+
# DATABASE_URL=postgresql://user:password@localhost:5432/auto_image_diff
47+
48+
# Monitoring (for future telemetry)
49+
# SENTRY_DSN=https://your-sentry-dsn
50+
# ENABLE_TELEMETRY=false

docs/ENV_SETUP.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Environment Configuration Guide
2+
3+
This guide explains how to set up and configure environment variables for the Auto Image Diff tool.
4+
5+
## Quick Start
6+
7+
1. Copy the example environment file:
8+
9+
```bash
10+
cp .env.example .env
11+
```
12+
13+
2. Edit `.env` with your preferred values (the defaults work well for most cases)
14+
15+
3. The application will automatically load these settings on startup
16+
17+
## Environment Variables
18+
19+
### Node Environment
20+
21+
- `NODE_ENV` - Application environment (`development`, `production`, `test`)
22+
- Default: `development`
23+
24+
### Logging Configuration
25+
26+
- `LOG_LEVEL` - Minimum log level to display (`debug`, `info`, `warn`, `error`)
27+
- Default: `info`
28+
- `LOG_FORMAT` - Log output format (`json`, `text`)
29+
- Default: `json`
30+
31+
### Performance Settings
32+
33+
- `MAX_WORKERS` - Maximum number of parallel workers (1-32)
34+
- Default: `4`
35+
- `BATCH_SIZE` - Number of images to process in each batch (1-100)
36+
- Default: `10`
37+
- `MEMORY_LIMIT` - Memory limit in MB (512-16384)
38+
- Default: `4096`
39+
40+
### Image Processing Settings
41+
42+
- `IMAGE_QUALITY` - JPEG quality for output images (1-100)
43+
- Default: `85`
44+
- `MAX_IMAGE_SIZE` - Maximum image file size in bytes
45+
- Default: `10485760` (10MB)
46+
- `DIFF_THRESHOLD` - Pixel difference threshold (0-1)
47+
- Default: `0.1`
48+
49+
### Output Configuration
50+
51+
- `OUTPUT_DIR` - Directory for output files
52+
- Default: `./output`
53+
- `ENABLE_HTML_REPORTS` - Generate HTML reports (`true`, `false`)
54+
- Default: `true`
55+
- `ENABLE_JSON_REPORTS` - Generate JSON reports (`true`, `false`)
56+
- Default: `true`
57+
58+
### Cache Settings
59+
60+
- `ENABLE_CACHE` - Enable caching (`true`, `false`)
61+
- Default: `true`
62+
- `CACHE_DIR` - Directory for cache files
63+
- Default: `./cache`
64+
- `CACHE_TTL` - Cache time-to-live in seconds
65+
- Default: `86400` (24 hours)
66+
67+
### Debug Mode
68+
69+
- `DEBUG_MODE` - Enable debug mode (`true`, `false`)
70+
- Default: `false`
71+
- `VERBOSE_OUTPUT` - Enable verbose output (`true`, `false`)
72+
- Default: `false`
73+
74+
## Using Environment Variables in Code
75+
76+
The environment configuration is automatically loaded and validated. To use it in your code:
77+
78+
```typescript
79+
import { getConfig, get } from "./lib/env-config";
80+
81+
// Get the entire config object
82+
const config = getConfig();
83+
console.log(config.maxWorkers);
84+
85+
// Get a specific value
86+
const logLevel = get("logLevel");
87+
```
88+
89+
## Validation
90+
91+
The environment configuration includes built-in validation:
92+
93+
- Numeric values are checked for valid ranges
94+
- Required values are verified
95+
- Invalid configurations will throw an error on startup
96+
97+
## Security Notes
98+
99+
- **Never commit `.env` files** to version control
100+
- The `.env` file is automatically excluded via `.gitignore`
101+
- Use `.env.example` as a template for other developers
102+
- Store sensitive values (API keys, passwords) securely
103+
- Consider using environment-specific files (`.env.production`, `.env.test`)
104+
105+
## Troubleshooting
106+
107+
### Environment variables not loading
108+
109+
- Ensure `.env` file exists in the project root
110+
- Check file permissions
111+
- Verify no syntax errors in `.env` file
112+
113+
### Validation errors
114+
115+
- Check that numeric values are within allowed ranges
116+
- Ensure required variables are set
117+
- Review error messages for specific issues
118+
119+
### Performance issues
120+
121+
- Adjust `MAX_WORKERS` based on your CPU cores
122+
- Increase `MEMORY_LIMIT` for large images
123+
- Enable caching for repeated operations

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
},
8484
"dependencies": {
8585
"commander": "^14.0.0",
86+
"dotenv": "^17.2.1",
8687
"gm": "^1.25.1",
8788
"imagemagick": "^0.1.3",
8889
"pixelmatch": "^7.1.0",

src/__tests__/processor-edge-cases.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable no-console */
12
/**
23
* @fileoverview Processor edge case tests
34
* @lastmodified 2025-08-01T06:30:00Z

src/lib/env-config.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/**
2+
* @fileoverview Environment configuration validation and loading
3+
* @lastmodified 2025-08-02T00:00:00Z
4+
*
5+
* Features: Environment validation, type-safe config, default values
6+
* Main APIs: loadConfig(), validateConfig(), getConfig()
7+
* Constraints: Requires valid .env file or defaults
8+
* Patterns: Singleton pattern, validation on load
9+
*/
10+
11+
import * as dotenv from "dotenv";
12+
13+
interface Config {
14+
// Node Environment
15+
nodeEnv: "development" | "production" | "test";
16+
17+
// Logging
18+
logLevel: "debug" | "info" | "warn" | "error";
19+
logFormat: "json" | "text";
20+
21+
// Performance
22+
maxWorkers: number;
23+
batchSize: number;
24+
memoryLimit: number;
25+
26+
// Image Processing
27+
imageQuality: number;
28+
maxImageSize: number;
29+
diffThreshold: number;
30+
31+
// Output
32+
outputDir: string;
33+
enableHtmlReports: boolean;
34+
enableJsonReports: boolean;
35+
36+
// Cache
37+
enableCache: boolean;
38+
cacheDir: string;
39+
cacheTTL: number;
40+
41+
// Debug
42+
debugMode: boolean;
43+
verboseOutput: boolean;
44+
}
45+
46+
class EnvConfig {
47+
private static instance: EnvConfig;
48+
private config: Config | null = null;
49+
50+
private constructor() {}
51+
52+
static getInstance(): EnvConfig {
53+
if (!EnvConfig.instance) {
54+
EnvConfig.instance = new EnvConfig();
55+
}
56+
return EnvConfig.instance;
57+
}
58+
59+
loadConfig(): Config {
60+
if (this.config) {
61+
return this.config;
62+
}
63+
64+
// Load .env file using dotenv
65+
dotenv.config();
66+
67+
// Build config from environment variables with defaults
68+
this.config = {
69+
nodeEnv: (process.env.NODE_ENV as Config["nodeEnv"]) || "development",
70+
logLevel: (process.env.LOG_LEVEL as Config["logLevel"]) || "info",
71+
logFormat: (process.env.LOG_FORMAT as Config["logFormat"]) || "json",
72+
maxWorkers: parseInt(process.env.MAX_WORKERS || "4", 10),
73+
batchSize: parseInt(process.env.BATCH_SIZE || "10", 10),
74+
memoryLimit: parseInt(process.env.MEMORY_LIMIT || "4096", 10),
75+
imageQuality: parseInt(process.env.IMAGE_QUALITY || "85", 10),
76+
maxImageSize: parseInt(process.env.MAX_IMAGE_SIZE || "10485760", 10),
77+
diffThreshold: parseFloat(process.env.DIFF_THRESHOLD || "0.1"),
78+
outputDir: process.env.OUTPUT_DIR || "./output",
79+
enableHtmlReports: process.env.ENABLE_HTML_REPORTS !== "false",
80+
enableJsonReports: process.env.ENABLE_JSON_REPORTS !== "false",
81+
enableCache: process.env.ENABLE_CACHE !== "false",
82+
cacheDir: process.env.CACHE_DIR || "./cache",
83+
cacheTTL: parseInt(process.env.CACHE_TTL || "86400", 10),
84+
debugMode: process.env.DEBUG_MODE === "true",
85+
verboseOutput: process.env.VERBOSE_OUTPUT === "true",
86+
};
87+
88+
this.validateConfig(this.config);
89+
return this.config;
90+
}
91+
92+
private validateConfig(config: Config): void {
93+
const errors: string[] = [];
94+
95+
// Validate numeric ranges
96+
if (config.maxWorkers < 1 || config.maxWorkers > 32) {
97+
errors.push("MAX_WORKERS must be between 1 and 32");
98+
}
99+
100+
if (config.batchSize < 1 || config.batchSize > 100) {
101+
errors.push("BATCH_SIZE must be between 1 and 100");
102+
}
103+
104+
if (config.memoryLimit < 512 || config.memoryLimit > 16384) {
105+
errors.push("MEMORY_LIMIT must be between 512 and 16384 MB");
106+
}
107+
108+
if (config.imageQuality < 1 || config.imageQuality > 100) {
109+
errors.push("IMAGE_QUALITY must be between 1 and 100");
110+
}
111+
112+
if (config.diffThreshold < 0 || config.diffThreshold > 1) {
113+
errors.push("DIFF_THRESHOLD must be between 0 and 1");
114+
}
115+
116+
// Validate paths
117+
if (!config.outputDir) {
118+
errors.push("OUTPUT_DIR must not be empty");
119+
}
120+
121+
if (!config.cacheDir) {
122+
errors.push("CACHE_DIR must not be empty");
123+
}
124+
125+
if (errors.length > 0) {
126+
throw new Error(`Environment configuration errors:\n${errors.join("\n")}`);
127+
}
128+
}
129+
130+
getConfig(): Config {
131+
if (!this.config) {
132+
this.loadConfig();
133+
}
134+
return this.config as Config;
135+
}
136+
137+
// Helper method to get single config value
138+
get<K extends keyof Config>(key: K): Config[K] {
139+
return this.getConfig()[key];
140+
}
141+
}
142+
143+
// Export singleton instance
144+
export const envConfig = EnvConfig.getInstance();
145+
export type { Config };
146+
147+
// Export convenience functions
148+
export const loadConfig = (): Config => envConfig.loadConfig();
149+
export const getConfig = (): Config => envConfig.getConfig();
150+
export const get = <K extends keyof Config>(key: K): Config[K] => envConfig.get(key);

0 commit comments

Comments
 (0)