Claude-skill-registry evernote-prod-checklist
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/evernote-prod-checklist" ~/.claude/skills/majiayu000-claude-skill-registry-evernote-prod-checklist && rm -rf "$T"
manifest:
skills/data/evernote-prod-checklist/SKILL.mdsource content
Evernote Production Checklist
Overview
Comprehensive checklist for deploying Evernote integrations to production, covering API keys, security, performance, monitoring, and compliance.
Prerequisites
- Completed development and testing
- Production API key approved
- Production infrastructure ready
Pre-Production Checklist
1. API Key Configuration
## API Key Requirements - [ ] Production API key requested and approved - [ ] Consumer key and secret stored in secret manager - [ ] Sandbox mode disabled for production - [ ] API key permissions match application needs - [ ] Rate limit boost requested (if needed for initial sync) ## Key Management - [ ] Different keys for dev/staging/production - [ ] Key rotation procedure documented - [ ] Emergency key revocation process defined
2. Environment Configuration
// config/production.js module.exports = { evernote: { // NEVER use sandbox in production sandbox: false, // Production endpoints serviceHost: 'www.evernote.com', // Timeouts requestTimeout: 30000, // 30 seconds connectionTimeout: 10000, // 10 seconds // Rate limiting maxRequestsPerMinute: 50, retryAttempts: 3, retryDelay: 1000 }, session: { secure: true, httpOnly: true, sameSite: 'strict', maxAge: 24 * 60 * 60 * 1000 // 24 hours }, logging: { level: 'info', redactTokens: true } };
3. Security Checklist
## Authentication & Authorization - [ ] OAuth 1.0a implemented correctly - [ ] CSRF protection on OAuth flow - [ ] OAuth state validation - [ ] Token expiration handling - [ ] Token refresh workflow (re-auth before expiry) ## Data Protection - [ ] Tokens encrypted at rest - [ ] HTTPS enforced (no HTTP fallback) - [ ] TLS 1.2+ required - [ ] Sensitive data redacted from logs - [ ] PII handling compliant with privacy policy ## Input Validation - [ ] All user inputs validated - [ ] ENML content sanitized - [ ] File upload restrictions enforced - [ ] SQL injection prevention (if using database) - [ ] XSS prevention in rendered content
4. Error Handling
// middleware/error-handler.js const logger = require('../utils/secure-logger'); function productionErrorHandler(err, req, res, next) { // Log full error internally logger.error('Unhandled error', { error: err.message, stack: err.stack, path: req.path, method: req.method, userId: req.session?.userId }); // Generic response to user const statusCode = err.statusCode || 500; // Never expose internal details res.status(statusCode).json({ error: statusCode === 500 ? 'An unexpected error occurred' : err.userMessage || 'Request failed', requestId: req.id // For support reference }); } module.exports = productionErrorHandler;
5. Rate Limit Handling
// Production rate limit configuration const rateLimitConfig = { // Conservative defaults maxRetries: 3, baseDelay: 1000, maxDelay: 60000, // Batch processing limits batchSize: 10, batchDelay: 500, // Circuit breaker failureThreshold: 5, recoveryTime: 60000 }; // Circuit breaker implementation class CircuitBreaker { constructor(options) { this.failureCount = 0; this.failureThreshold = options.failureThreshold || 5; this.recoveryTime = options.recoveryTime || 60000; this.state = 'CLOSED'; this.lastFailure = null; } async execute(operation) { if (this.state === 'OPEN') { if (Date.now() - this.lastFailure > this.recoveryTime) { this.state = 'HALF_OPEN'; } else { throw new Error('Circuit breaker is OPEN'); } } try { const result = await operation(); this.onSuccess(); return result; } catch (error) { this.onFailure(); throw error; } } onSuccess() { this.failureCount = 0; this.state = 'CLOSED'; } onFailure() { this.failureCount++; this.lastFailure = Date.now(); if (this.failureCount >= this.failureThreshold) { this.state = 'OPEN'; } } }
6. Monitoring & Alerting
// monitoring/metrics.js const prometheus = require('prom-client'); // API call metrics const apiCalls = new prometheus.Counter({ name: 'evernote_api_calls_total', help: 'Total Evernote API calls', labelNames: ['operation', 'status'] }); const apiLatency = new prometheus.Histogram({ name: 'evernote_api_latency_seconds', help: 'Evernote API call latency', labelNames: ['operation'], buckets: [0.1, 0.5, 1, 2, 5, 10] }); const rateLimits = new prometheus.Counter({ name: 'evernote_rate_limits_total', help: 'Total rate limit hits' }); const authErrors = new prometheus.Counter({ name: 'evernote_auth_errors_total', help: 'Total authentication errors', labelNames: ['type'] }); // Alert thresholds (configure in alerting system) const alertRules = ` groups: - name: evernote rules: - alert: HighRateLimitRate expr: rate(evernote_rate_limits_total[5m]) > 0.1 for: 5m labels: severity: warning annotations: summary: High Evernote rate limit rate - alert: HighAuthErrorRate expr: rate(evernote_auth_errors_total[5m]) > 0.05 for: 5m labels: severity: critical annotations: summary: High Evernote authentication error rate - alert: HighAPILatency expr: histogram_quantile(0.95, evernote_api_latency_seconds) > 5 for: 5m labels: severity: warning annotations: summary: High Evernote API latency `;
7. Health Checks
// routes/health.js const express = require('express'); const router = express.Router(); router.get('/health', (req, res) => { res.json({ status: 'ok' }); }); router.get('/health/detailed', async (req, res) => { const checks = { timestamp: new Date().toISOString(), status: 'ok', checks: {} }; // Database check try { await db.query('SELECT 1'); checks.checks.database = { status: 'ok' }; } catch (error) { checks.checks.database = { status: 'error', message: 'Connection failed' }; checks.status = 'degraded'; } // Redis check try { await redis.ping(); checks.checks.redis = { status: 'ok' }; } catch (error) { checks.checks.redis = { status: 'error', message: 'Connection failed' }; checks.status = 'degraded'; } // Evernote API check (use sparingly) checks.checks.evernote = { status: 'ok', note: 'Not actively checked to preserve rate limits' }; const statusCode = checks.status === 'ok' ? 200 : 503; res.status(statusCode).json(checks); }); module.exports = router;
8. Logging Configuration
// logging/production.js const winston = require('winston'); const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), defaultMeta: { service: 'evernote-integration', environment: process.env.NODE_ENV }, transports: [ new winston.transports.Console(), new winston.transports.File({ filename: 'logs/error.log', level: 'error', maxsize: 10485760, // 10MB maxFiles: 5 }), new winston.transports.File({ filename: 'logs/combined.log', maxsize: 10485760, maxFiles: 5 }) ] }); // Never log tokens logger.add(winston.format((info) => { if (info.token) info.token = '[REDACTED]'; if (info.accessToken) info.accessToken = '[REDACTED]'; return info; })()); module.exports = logger;
9. Deployment Verification
// scripts/verify-deployment.js async function verifyDeployment() { console.log('=== Deployment Verification ===\n'); const checks = []; // 1. Environment check checks.push({ name: 'Environment variables', pass: !!(process.env.EVERNOTE_CONSUMER_KEY && process.env.EVERNOTE_CONSUMER_SECRET), critical: true }); // 2. Sandbox mode disabled checks.push({ name: 'Sandbox mode disabled', pass: process.env.EVERNOTE_SANDBOX !== 'true', critical: true }); // 3. HTTPS enabled checks.push({ name: 'HTTPS configured', pass: process.env.APP_URL?.startsWith('https://'), critical: true }); // 4. Session secret set checks.push({ name: 'Session secret configured', pass: !!process.env.SESSION_SECRET && process.env.SESSION_SECRET.length >= 32, critical: true }); // 5. Logging configured checks.push({ name: 'Logging configured', pass: process.env.LOG_LEVEL !== 'debug', critical: false }); // Report let allPassed = true; for (const check of checks) { const status = check.pass ? 'PASS' : 'FAIL'; const critical = check.critical ? '(CRITICAL)' : ''; console.log(`[${status}] ${check.name} ${critical}`); if (!check.pass && check.critical) { allPassed = false; } } console.log('\n' + (allPassed ? 'Deployment verification PASSED' : 'Deployment verification FAILED - fix critical issues')); process.exit(allPassed ? 0 : 1); } verifyDeployment();
Production Readiness Checklist
## Final Checklist Before Go-Live ### API & Authentication - [ ] Production API key configured - [ ] Sandbox mode disabled - [ ] OAuth flow tested end-to-end - [ ] Token storage encrypted - [ ] Token expiration handling tested ### Security - [ ] HTTPS enforced - [ ] CSRF protection verified - [ ] Input validation implemented - [ ] Error messages don't leak sensitive data - [ ] Security headers configured (HSTS, CSP, etc.) ### Performance - [ ] Rate limit handling implemented - [ ] Circuit breaker configured - [ ] Timeouts set appropriately - [ ] Connection pooling enabled - [ ] Caching strategy implemented ### Monitoring - [ ] Health check endpoints working - [ ] Metrics collection configured - [ ] Alerting rules set up - [ ] Log aggregation configured - [ ] Error tracking enabled (Sentry, etc.) ### Operations - [ ] Runbook documented - [ ] Rollback procedure tested - [ ] Backup strategy defined - [ ] On-call rotation established - [ ] Incident response plan documented ### Compliance - [ ] Privacy policy updated - [ ] Terms of service updated - [ ] Data retention policy defined - [ ] GDPR compliance verified (if applicable) - [ ] User consent mechanisms in place
Output
- Production configuration templates
- Security verification checklist
- Monitoring and alerting setup
- Health check endpoints
- Deployment verification script
Resources
Next Steps
For version upgrades, see
evernote-upgrade-migration.