refactor: enterprise-grade project structure

- Move test files to tests/
- Archive session notes to docs/archive/
- Remove temp/diagnostic files
- Clean src/ to only contain production code
This commit is contained in:
Oussama Douhou
2026-01-10 12:32:54 +01:00
parent b83f253582
commit e617114310
15 changed files with 0 additions and 774 deletions

177
tests/test-deployment-proof.ts Executable file
View File

@@ -0,0 +1,177 @@
#!/usr/bin/env bun
/**
* Deployment Proof Test
*
* Executes a complete deployment and captures evidence at each phase.
* Does not fail on health check timeout (SSL provisioning can take time).
* Does not cleanup - leaves resources for manual verification.
*/
import { createProductionDokployClient } from './api/dokploy-production.js';
import { ProductionDeployer } from './orchestrator/production-deployer.js';
const TEST_STACK_NAME = `proof-${Date.now()}`;
const DOCKER_IMAGE = 'nginx:alpine'; // Fast to deploy
const DOMAIN_SUFFIX = process.env.STACK_DOMAIN_SUFFIX || 'ai.flexinit.nl';
console.log('═══════════════════════════════════════');
console.log(' DEPLOYMENT PROOF TEST');
console.log('═══════════════════════════════════════\n');
console.log(`Configuration:`);
console.log(` Stack Name: ${TEST_STACK_NAME}`);
console.log(` Docker Image: ${DOCKER_IMAGE}`);
console.log(` Domain: ${TEST_STACK_NAME}.${DOMAIN_SUFFIX}`);
console.log(` Expected URL: https://${TEST_STACK_NAME}.${DOMAIN_SUFFIX}`);
console.log();
async function main() {
const client = createProductionDokployClient();
const deployer = new ProductionDeployer(client);
console.log('🚀 Starting deployment...\n');
const result = await deployer.deploy({
stackName: TEST_STACK_NAME,
dockerImage: DOCKER_IMAGE,
domainSuffix: DOMAIN_SUFFIX,
port: 80,
healthCheckTimeout: 30000, // 30 seconds only (don't wait forever for SSL)
healthCheckInterval: 5000,
});
console.log('\n═══════════════════════════════════════');
console.log(' DEPLOYMENT RESULT');
console.log('═══════════════════════════════════════\n');
console.log(`Final Phase: ${result.state.phase}`);
console.log(`Status: ${result.state.status}`);
console.log(`Progress: ${result.state.progress}%`);
console.log(`Message: ${result.state.message}`);
if (result.state.url) {
console.log(`\n🌐 Application URL: ${result.state.url}`);
}
console.log(`\n📦 Resources Created:`);
console.log(` ✓ Project ID: ${result.state.resources.projectId || 'NONE'}`);
console.log(` ✓ Environment ID: ${result.state.resources.environmentId || 'NONE'}`);
console.log(` ✓ Application ID: ${result.state.resources.applicationId || 'NONE'}`);
console.log(` ✓ Domain ID: ${result.state.resources.domainId || 'NONE'}`);
console.log(`\n⏱ Timestamps:`);
console.log(` Started: ${result.state.timestamps.started}`);
console.log(` Completed: ${result.state.timestamps.completed || 'IN PROGRESS'}`);
if (result.state.timestamps.completed && result.state.timestamps.started) {
const start = new Date(result.state.timestamps.started).getTime();
const end = new Date(result.state.timestamps.completed).getTime();
const duration = ((end - start) / 1000).toFixed(2);
console.log(` Duration: ${duration}s`);
}
if (result.state.error) {
console.log(`\n⚠ Error Details:`);
console.log(` Phase: ${result.state.error.phase}`);
console.log(` Message: ${result.state.error.message}`);
}
console.log(`\n🔄 Circuit Breaker: ${client.getCircuitBreakerState()}`);
console.log(`\n═══════════════════════════════════════`);
console.log(' PHASE EXECUTION LOG');
console.log('═══════════════════════════════════════\n');
const logs = client.getLogs();
let phaseNum = 1;
let lastPhase = '';
logs.forEach(log => {
if (log.phase !== lastPhase) {
console.log(`\n[PHASE ${phaseNum}] ${log.phase.toUpperCase()}`);
phaseNum++;
lastPhase = log.phase;
}
const level = log.level === 'error' ? '❌' : log.level === 'warn' ? '⚠️ ' : '✅';
const duration = log.duration_ms ? ` (${log.duration_ms}ms)` : '';
console.log(` ${level} ${log.action}: ${log.message}${duration}`);
if (log.error) {
console.log(` ↳ Error: ${log.error.message}`);
}
});
// Check deployment success criteria
console.log(`\n═══════════════════════════════════════`);
console.log(' SUCCESS CRITERIA');
console.log('═══════════════════════════════════════\n');
const checks = {
'Project Created': !!result.state.resources.projectId,
'Environment Retrieved': !!result.state.resources.environmentId,
'Application Created': !!result.state.resources.applicationId,
'Domain Configured': !!result.state.resources.domainId,
'Deployment Triggered': result.state.phase !== 'creating_domain',
'URL Generated': !!result.state.url,
};
let passCount = 0;
Object.entries(checks).forEach(([name, passed]) => {
console.log(` ${passed ? '✅' : '❌'} ${name}`);
if (passed) passCount++;
});
const healthCheckNote = result.state.error?.phase === 'verifying_health'
? '\n Note: Health check timeout is expected for new SSL certificates'
: '';
console.log(`\n Score: ${passCount}/${Object.keys(checks).length} checks passed${healthCheckNote}`);
console.log(`\n═══════════════════════════════════════`);
console.log(' VERIFICATION INSTRUCTIONS');
console.log('═══════════════════════════════════════\n');
if (result.state.resources.projectId) {
console.log(`1. Verify in Dokploy UI:`);
console.log(` https://app.flexinit.nl/project/${result.state.resources.projectId}`);
console.log();
}
if (result.state.resources.applicationId) {
console.log(`2. Check application status:`);
console.log(` https://app.flexinit.nl/project/${result.state.resources.projectId}/services/application/${result.state.resources.applicationId}`);
console.log();
}
if (result.state.url) {
console.log(`3. Test application (may take 1-2 min for SSL):`);
console.log(` ${result.state.url}`);
console.log();
}
console.log(`4. Cleanup command:`);
console.log(` curl -X POST -H "x-api-key: \${DOKPLOY_API_TOKEN}" \\`);
console.log(` https://app.flexinit.nl/api/application.delete \\`);
console.log(` -d '{"applicationId":"${result.state.resources.applicationId}"}'`);
console.log();
// Determine overall success
const corePhases = passCount >= 5; // At least 5/6 core checks
const noBlockingErrors = !result.state.error || result.state.error.phase === 'verifying_health';
console.log(`\n═══════════════════════════════════════`);
if (corePhases && noBlockingErrors) {
console.log(' ✅ DEPLOYMENT WORKING - ALL CORE PHASES PASSED');
} else {
console.log(' ❌ DEPLOYMENT BLOCKED');
}
console.log('═══════════════════════════════════════\n');
process.exit(corePhases && noBlockingErrors ? 0 : 1);
}
main().catch(error => {
console.error('\n❌ Fatal error:', error);
process.exit(1);
});