Add Pennyzo API status checker scripts, report viewer, and documentation

This commit is contained in:
2025-09-25 14:11:36 +05:30
parent df2a2b9412
commit aece15a286
16 changed files with 2291 additions and 6 deletions

5
reports/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
# Ignore all JSON files in this directory (API status reports)
*.json
# But don't ignore any specifically created example files
!example-*.json

31
reports/README.md Normal file
View File

@@ -0,0 +1,31 @@
# Reports Directory
This directory contains API status check reports generated by the API status checker tool.
## Files
- **JSON Reports**: Generated when running the extended API status checker
- **example-report.json**: Sample report showing the expected format
- **report-viewer.html**: HTML tool for visualizing the JSON reports
## Using the Report Viewer
To view a report:
1. Open the `report-viewer.html` file in a web browser
2. Click "Choose Report File" to select a JSON report
3. Review the report details including endpoint statuses
## Report Format
Each report includes:
- Summary statistics (success rate, endpoint counts)
- Detailed endpoint results
- Response times
- Error details
- API response data (when in verbose mode)
## Retention Policy
By default, all JSON reports in this directory are ignored by git. If you want to keep certain reports, consider copying them elsewhere or modifying the `.gitignore` file in this directory.

View File

@@ -0,0 +1,74 @@
{
"title": "Pennyzo API Status Check Report",
"timestamp": "2025-09-25T10:15:30.123Z",
"duration": "1.15 seconds",
"summary": {
"totalEndpoints": 3,
"successful": 2,
"failed": 1,
"successRate": "66.7%"
},
"baseUrl": "https://api.pennyzo.com/api/v1/general",
"results": [
{
"endpoint": "/system/health",
"method": "GET",
"status": "SUCCESS",
"statusCode": 200,
"responseTime": 342,
"timestamp": "2025-09-25T10:15:30.123Z",
"error": null,
"data": {
"status": "operational",
"service": "Pennyzo General API",
"version": "1.0.0",
"environment": "production",
"message": "Service is healthy"
}
},
{
"endpoint": "/registration/company/identity-rules",
"method": "GET",
"status": "SUCCESS",
"statusCode": 200,
"responseTime": 285,
"timestamp": "2025-09-25T10:15:30.456Z",
"error": null,
"data": {
"rules": [
{
"company_type": "PRIVATE_LIMITED",
"required_fields": ["cin_number"]
},
{
"company_type": "LLP",
"required_fields": ["llp_number"]
},
{
"company_type": "PROPRIETORSHIP",
"required_fields": ["pan_number"]
}
]
}
},
{
"endpoint": "/auth/login",
"method": "POST",
"status": "FAILED",
"statusCode": 401,
"responseTime": 520,
"timestamp": "2025-09-25T10:15:30.789Z",
"error": {
"message": "Request failed with status code 401",
"details": {
"error": {
"type": "unauthorized",
"code": 401,
"message": "Invalid credentials"
}
}
},
"data": null
}
]
}

378
reports/report-viewer.html Normal file
View File

@@ -0,0 +1,378 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pennyzo API Status Report Viewer</title>
<style>
:root {
--deep-navy: #05174d;
--brass: #d4af37;
--off-white: #f5f5f5;
--light-gray: #e0e0e0;
--success: #28a745;
--danger: #dc3545;
--warning: #ffc107;
--info: #17a2b8;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 0;
background-color: var(--off-white);
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
background-color: var(--deep-navy);
color: white;
padding: 20px;
text-align: center;
border-bottom: 4px solid var(--brass);
}
h1 {
margin: 0;
font-size: 2em;
}
.report-selector {
margin: 20px 0;
padding: 15px;
background-color: white;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.summary-card {
background-color: white;
border-radius: 5px;
padding: 15px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
text-align: center;
}
.summary-card h3 {
margin-top: 0;
color: var(--deep-navy);
}
.summary-card .value {
font-size: 2em;
font-weight: bold;
}
.success-rate {
color: var(--success);
}
.table-container {
overflow-x: auto;
margin-top: 20px;
}
table {
width: 100%;
border-collapse: collapse;
background-color: white;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
th, td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid var(--light-gray);
}
th {
background-color: var(--deep-navy);
color: white;
position: sticky;
top: 0;
}
tr:hover {
background-color: var(--light-gray);
}
.status {
padding: 5px 10px;
border-radius: 3px;
font-weight: bold;
}
.status-success {
background-color: var(--success);
color: white;
}
.status-failed {
background-color: var(--danger);
color: white;
}
.method {
font-weight: bold;
}
.method-GET {
color: var(--info);
}
.method-POST {
color: var(--warning);
}
.method-PUT {
color: var(--deep-navy);
}
.method-DELETE {
color: var(--danger);
}
.details-row {
display: none;
background-color: #f9f9f9;
}
.details-cell {
padding: 15px;
}
.details-container {
white-space: pre-wrap;
font-family: monospace;
background-color: #f5f5f5;
padding: 10px;
border-radius: 5px;
overflow-x: auto;
max-height: 300px;
overflow-y: auto;
}
.expandable {
cursor: pointer;
}
.expandable::after {
content: '▼';
margin-left: 5px;
font-size: 0.8em;
}
footer {
margin-top: 30px;
text-align: center;
padding: 10px;
color: #666;
}
#file-input {
display: none;
}
.file-upload-btn {
background-color: var(--deep-navy);
color: white;
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
margin-right: 10px;
}
.file-name {
margin-left: 10px;
font-style: italic;
}
.no-report {
padding: 50px;
text-align: center;
background-color: white;
border-radius: 5px;
margin-top: 20px;
}
</style>
</head>
<body>
<header>
<h1>Pennyzo API Status Report Viewer</h1>
</header>
<div class="container">
<div class="report-selector">
<h2>Select Report</h2>
<input type="file" id="file-input" accept=".json">
<button class="file-upload-btn" onclick="document.getElementById('file-input').click()">
Choose Report File
</button>
<span class="file-name" id="file-name"></span>
</div>
<div id="report-content">
<div class="no-report">
<h2>No Report Loaded</h2>
<p>Please select a report JSON file to view its contents.</p>
</div>
</div>
<footer>
<p>Pennyzo API Status Report Viewer | &copy; 2025 Pennyzo</p>
</footer>
</div>
<script>
document.getElementById('file-input').addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
document.getElementById('file-name').textContent = file.name;
const reader = new FileReader();
reader.onload = function(e) {
try {
const report = JSON.parse(e.target.result);
renderReport(report);
} catch (error) {
alert('Error parsing JSON file: ' + error.message);
}
};
reader.readAsText(file);
}
});
function renderReport(report) {
const reportContent = document.getElementById('report-content');
// Create HTML for report
let html = `
<h2>${report.title}</h2>
<p><strong>Generated:</strong> ${new Date(report.timestamp).toLocaleString()}</p>
<p><strong>Duration:</strong> ${report.duration}</p>
<p><strong>Base URL:</strong> ${report.baseUrl}</p>
<div class="summary">
<div class="summary-card">
<h3>Total Endpoints</h3>
<div class="value">${report.summary.totalEndpoints}</div>
</div>
<div class="summary-card">
<h3>Successful</h3>
<div class="value" style="color: var(--success)">${report.summary.successful}</div>
</div>
<div class="summary-card">
<h3>Failed</h3>
<div class="value" style="color: var(--danger)">${report.summary.failed}</div>
</div>
<div class="summary-card">
<h3>Success Rate</h3>
<div class="value success-rate">${report.summary.successRate}</div>
</div>
</div>
<h2>Endpoint Results</h2>
<div class="table-container">
<table>
<thead>
<tr>
<th>Endpoint</th>
<th>Method</th>
<th>Status</th>
<th>Status Code</th>
<th>Response Time</th>
<th>Timestamp</th>
</tr>
</thead>
<tbody>
`;
// Add rows for each result
report.results.forEach((result, index) => {
html += `
<tr class="expandable" onclick="toggleDetails(${index})">
<td>${result.endpoint}</td>
<td><span class="method method-${result.method}">${result.method}</span></td>
<td><span class="status status-${result.status.toLowerCase()}">${result.status}</span></td>
<td>${result.statusCode}</td>
<td>${result.responseTime}ms</td>
<td>${new Date(result.timestamp).toLocaleTimeString()}</td>
</tr>
<tr id="details-${index}" class="details-row">
<td colspan="6" class="details-cell">
<div class="details-container">
${renderDetails(result)}
</div>
</td>
</tr>
`;
});
html += `
</tbody>
</table>
</div>
`;
reportContent.innerHTML = html;
}
function renderDetails(result) {
let details = '';
if (result.error) {
details += `<strong>Error Message:</strong> ${result.error.message}\n\n`;
if (result.error.details) {
details += `<strong>Error Details:</strong>\n${JSON.stringify(result.error.details, null, 2)}\n\n`;
}
}
if (result.data) {
details += `<strong>Response Data:</strong>\n${JSON.stringify(result.data, null, 2)}`;
}
return details || 'No additional details available';
}
function toggleDetails(index) {
const detailsRow = document.getElementById(`details-${index}`);
if (detailsRow.style.display === 'table-row') {
detailsRow.style.display = 'none';
} else {
detailsRow.style.display = 'table-row';
}
}
// Load example report on page load
fetch('example-report.json')
.then(response => {
if (!response.ok) {
throw new Error('Example report not found');
}
return response.json();
})
.then(report => {
document.getElementById('file-name').textContent = 'example-report.json (pre-loaded)';
renderReport(report);
})
.catch(error => {
console.log('No example report pre-loaded:', error);
// No need to show an error, we'll just show the default "No Report Loaded" message
});
</script>
</body>
</html>