๐Ÿ“… let's chat! explore the endless possibilities creating industries that don't exist. click here

evernote-multi-env-setup

Configure multi-environment setup for Evernote integrations. Use when setting up dev, staging, and production environments, or managing environment-specific configurations. Trigger with phrases like "evernote environments", "evernote staging", "evernote dev setup", "multiple environments evernote". allowed-tools: Read, Write, Edit, Bash(npm:*), Grep version: 1.0.0 license: MIT author: Jeremy Longshore <jeremy@intentsolutions.io>

Allowed Tools

No tools specified

Provided by Plugin

evernote-pack

Claude Code skill pack for Evernote (24 skills)

saas packs v1.0.0
View Plugin

Installation

This skill is included in the evernote-pack plugin:

/plugin install evernote-pack@claude-code-plugins-plus

Click to copy

Instructions

# Evernote Multi-Environment Setup ## Overview Configure separate development, staging, and production environments for Evernote integrations with proper isolation and configuration management. ## Prerequisites - Multiple Evernote API keys (sandbox and production) - Environment management infrastructure - CI/CD pipeline ## Environment Strategy | Environment | Evernote Mode | Purpose | Users | |-------------|---------------|---------|-------| | Development | Sandbox | Local development | Developers | | Staging | Sandbox | Integration testing | QA team | | Production | Production | Live users | Customers | ## Instructions ### Step 1: Environment Configuration Files ```bash # Project structure project/ โ”œโ”€โ”€ config/ โ”‚ โ”œโ”€โ”€ default.js # Shared defaults โ”‚ โ”œโ”€โ”€ development.js # Dev overrides โ”‚ โ”œโ”€โ”€ staging.js # Staging overrides โ”‚ โ””โ”€โ”€ production.js # Production overrides โ”œโ”€โ”€ .env.development โ”œโ”€โ”€ .env.staging โ”œโ”€โ”€ .env.production โ””โ”€โ”€ .env.example ``` ```javascript // config/default.js module.exports = { evernote: { requestTimeout: 30000, connectionTimeout: 10000, maxRetries: 3 }, cache: { ttl: 300, prefix: 'evernote:' }, logging: { redactTokens: true } }; ``` ```javascript // config/development.js module.exports = { evernote: { sandbox: true, serviceHost: 'sandbox.evernote.com', // More lenient for debugging requestTimeout: 60000, maxRetries: 1 }, cache: { ttl: 60, // Short TTL for development prefix: 'evernote:dev:' }, logging: { level: 'debug' } }; ``` ```javascript // config/staging.js module.exports = { evernote: { sandbox: true, // Still using sandbox for staging serviceHost: 'sandbox.evernote.com', requestTimeout: 30000, maxRetries: 2 }, cache: { ttl: 180, prefix: 'evernote:staging:' }, logging: { level: 'info' } }; ``` ```javascript // config/production.js module.exports = { evernote: { sandbox: false, // Production mode serviceHost: 'www.evernote.com', requestTimeout: 30000, maxRetries: 3 }, cache: { ttl: 300, prefix: 'evernote:prod:' }, logging: { level: 'warn' } }; ``` ### Step 2: Environment Variables ```bash # .env.example NODE_ENV=development # Evernote EVERNOTE_CONSUMER_KEY= EVERNOTE_CONSUMER_SECRET= EVERNOTE_SANDBOX=true # App APP_URL=http://localhost:3000 SESSION_SECRET=change-this-secret # Database DATABASE_URL= # Redis REDIS_URL= ``` ```bash # .env.development NODE_ENV=development EVERNOTE_CONSUMER_KEY=your-sandbox-key EVERNOTE_CONSUMER_SECRET=your-sandbox-secret EVERNOTE_SANDBOX=true APP_URL=http://localhost:3000 SESSION_SECRET=dev-secret-not-secure DATABASE_URL=postgresql://localhost:5432/evernote_dev REDIS_URL=redis://localhost:6379/0 ``` ```bash # .env.staging NODE_ENV=staging EVERNOTE_CONSUMER_KEY=your-sandbox-key EVERNOTE_CONSUMER_SECRET=your-sandbox-secret EVERNOTE_SANDBOX=true APP_URL=https://staging.yourapp.com # Secret managed externally (Vault, AWS Secrets, etc.) # DATABASE_URL managed externally # REDIS_URL managed externally ``` ```bash # .env.production NODE_ENV=production # ALL SECRETS MANAGED EXTERNALLY EVERNOTE_SANDBOX=false APP_URL=https://yourapp.com ``` ### Step 3: Configuration Loader ```javascript // config/index.js const path = require('path'); const deepMerge = require('lodash.merge'); class ConfigLoader { constructor() { this.env = process.env.NODE_ENV || 'development'; this.config = this.loadConfig(); } loadConfig() { // Load default config const defaultConfig = require('./default'); // Load environment-specific config let envConfig = {}; try { envConfig = require(`./${this.env}`); } catch (error) { console.warn(`No config file for environment: ${this.env}`); } // Merge configs const merged = deepMerge({}, defaultConfig, envConfig); // Override with environment variables return this.applyEnvOverrides(merged); } applyEnvOverrides(config) { // Evernote overrides if (process.env.EVERNOTE_CONSUMER_KEY) { config.evernote.consumerKey = process.env.EVERNOTE_CONSUMER_KEY; } if (process.env.EVERNOTE_CONSUMER_SECRET) { config.evernote.consumerSecret = process.env.EVERNOTE_CONSUMER_SECRET; } if (process.env.EVERNOTE_SANDBOX !== undefined) { config.evernote.sandbox = process.env.EVERNOTE_SANDBOX === 'true'; } // App overrides if (process.env.APP_URL) { config.app = config.app || {}; config.app.url = process.env.APP_URL; } // Database overrides if (process.env.DATABASE_URL) { config.database = config.database || {}; config.database.url = process.env.DATABASE_URL; } // Redis overrides if (process.env.REDIS_URL) { config.redis = config.redis || {}; config.redis.url = process.env.REDIS_URL; } return config; } get(key) { const keys = key.split('.'); let value = this.config; for (const k of keys) { if (value === undefined) return undefined; value = value[k]; } return value; } getAll() { return this.config; } isProduction() { return this.env === 'production'; } isDevelopment() { return this.env === 'development'; } isStaging() { return this.env === 'staging'; } } module.exports = new ConfigLoader(); ``` ### Step 4: Environment-Aware Client Factory ```javascript // services/evernote-factory.js const Evernote = require('evernote'); const config = require('../config'); class EvernoteClientFactory { static createOAuthClient() { return new Evernote.Client({ consumerKey: config.get('evernote.consumerKey'), consumerSecret: config.get('evernote.consumerSecret'), sandbox: config.get('evernote.sandbox'), china: false }); } static createAuthenticatedClient(accessToken) { return new Evernote.Client({ token: accessToken, sandbox: config.get('evernote.sandbox') }); } static getEnvironmentInfo() { return { environment: process.env.NODE_ENV, sandbox: config.get('evernote.sandbox'), serviceHost: config.get('evernote.sandbox') ? 'sandbox.evernote.com' : 'www.evernote.com' }; } static validateEnvironment() { const errors = []; if (!config.get('evernote.consumerKey')) { errors.push('Missing EVERNOTE_CONSUMER_KEY'); } if (!config.get('evernote.consumerSecret')) { errors.push('Missing EVERNOTE_CONSUMER_SECRET'); } if (config.isProduction() && config.get('evernote.sandbox')) { errors.push('Production environment cannot use sandbox mode'); } return { valid: errors.length === 0, errors }; } } module.exports = EvernoteClientFactory; ``` ### Step 5: Docker Compose for Local Development ```yaml # docker-compose.yml version: '3.8' services: app: build: context: . dockerfile: Dockerfile.dev volumes: - .:/app - /app/node_modules ports: - "3000:3000" environment: - NODE_ENV=development env_file: - .env.development depends_on: - postgres - redis postgres: image: postgres:15-alpine volumes: - postgres_data:/var/lib/postgresql/data environment: POSTGRES_DB: evernote_dev POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres ports: - "5432:5432" redis: image: redis:7-alpine ports: - "6379:6379" volumes: postgres_data: ``` ### Step 6: Environment-Specific Middleware ```javascript // middleware/environment.js const config = require('../config'); function environmentMiddleware(req, res, next) { // Add environment info to request req.environment = { name: process.env.NODE_ENV, sandbox: config.get('evernote.sandbox'), isProduction: config.isProduction() }; // Development-only features if (config.isDevelopment()) { // Add debug headers res.setHeader('X-Environment', 'development'); res.setHeader('X-Evernote-Mode', 'sandbox'); } // Production safety checks if (config.isProduction()) { // Ensure HTTPS if (req.protocol !== 'https') { return res.redirect(301, `https://${req.hostname}${req.url}`); } } next(); } function requireProduction(req, res, next) { if (!config.isProduction()) { return res.status(403).json({ error: 'This endpoint is only available in production' }); } next(); } function blockInProduction(req, res, next) { if (config.isProduction()) { return res.status(403).json({ error: 'This endpoint is not available in production' }); } next(); } module.exports = { environmentMiddleware, requireProduction, blockInProduction }; ``` ### Step 7: CI/CD Environment Configuration ```yaml # .github/workflows/deploy.yml name: Deploy on: push: branches: [main, develop] jobs: deploy: runs-on: ubuntu-latest strategy: matrix: include: - branch: develop environment: staging evernote_sandbox: 'true' - branch: main environment: production evernote_sandbox: 'false' steps: - uses: actions/checkout@v4 - name: Set environment if: github.ref == format('refs/heads/{0}', matrix.branch) run: echo "DEPLOY_ENV=${{ matrix.environment }}" >> $GITHUB_ENV - name: Deploy to ${{ matrix.environment }} if: env.DEPLOY_ENV != '' uses: ./.github/actions/deploy with: environment: ${{ matrix.environment }} env: EVERNOTE_CONSUMER_KEY: ${{ secrets[format('EVERNOTE_CONSUMER_KEY_{0}', matrix.environment)] }} EVERNOTE_CONSUMER_SECRET: ${{ secrets[format('EVERNOTE_CONSUMER_SECRET_{0}', matrix.environment)] }} EVERNOTE_SANDBOX: ${{ matrix.evernote_sandbox }} ``` ### Step 8: Environment Health Check ```javascript // routes/health.js const config = require('../config'); const EvernoteClientFactory = require('../services/evernote-factory'); router.get('/health/environment', async (req, res) => { const envInfo = EvernoteClientFactory.getEnvironmentInfo(); const validation = EvernoteClientFactory.validateEnvironment(); res.json({ status: validation.valid ? 'ok' : 'error', environment: { ...envInfo, nodeEnv: process.env.NODE_ENV, version: process.env.APP_VERSION || 'unknown' }, validation, checks: { database: await checkDatabase(), redis: await checkRedis(), evernote: await checkEvernoteConnectivity() } }); }); async function checkEvernoteConnectivity() { try { // Simple connectivity check - doesn't require auth const https = require('https'); const host = config.get('evernote.sandbox') ? 'sandbox.evernote.com' : 'www.evernote.com'; return new Promise((resolve) => { const req = https.get(`https://${host}`, { timeout: 5000 }, (res) => { resolve({ status: 'ok', host }); }); req.on('error', () => { resolve({ status: 'error', host, message: 'Connection failed' }); }); req.on('timeout', () => { req.destroy(); resolve({ status: 'error', host, message: 'Timeout' }); }); }); } catch (error) { return { status: 'error', message: error.message }; } } ``` ## Output - Environment-specific configuration files - Configuration loader with environment variable support - Environment-aware client factory - Docker Compose for local development - CI/CD environment configuration - Health check endpoints ## Environment Checklist ```markdown ## Per-Environment Checklist ### Development - [ ] Sandbox credentials configured - [ ] Local database running - [ ] Redis cache running - [ ] Debug logging enabled ### Staging - [ ] Sandbox credentials (separate from dev) - [ ] Staging database provisioned - [ ] Staging Redis provisioned - [ ] Monitoring configured ### Production - [ ] Production API key approved - [ ] Secrets in secure storage - [ ] Production database provisioned - [ ] Production Redis provisioned - [ ] Monitoring and alerting - [ ] Backup procedures ``` ## Resources - [12 Factor App - Config](https://12factor.net/config) - [Evernote Sandbox](https://sandbox.evernote.com) - [Docker Compose](https://docs.docker.com/compose/) ## Next Steps For observability setup, see `evernote-observability`.

Skill file: plugins/saas-packs/evernote-pack/skills/evernote-multi-env-setup/SKILL.md