flexbiz-server
Version:
Flexible Server
572 lines (543 loc) • 47 kB
JavaScript
const types=[{code:"String",ten:"String"},{code:"Number",ten:"Number"},{code:"Boolean",ten:"Boolean"},{code:"Date",ten:"Date"},{code:"DateTime",ten:"DateTime",type_data:"Date"},{code:"Time",ten:"Time",type_data:"Date"},{code:"Array",ten:"Array"},{code:"Mixed",ten:"Mixed",type_data:"Json"},{code:"File",ten:"Excel",type_data:"String"},{code:"Pdf",ten:"PDF",type_data:"String"},{code:"Image",ten:"Image",type_data:"String"}],buildJsonSchema=async function($entries_fields_validFields$$,$depth$$=0){if($depth$$>
5)return{};$entries_fields_validFields$$=$entries_fields_validFields$$.filter($f$$=>["ten_vt","ten_kh","ten_kho"].indexOf($f$$.name)>=0||$f$$.not_input!="true"&&$f$$.not_input!=1&&$f$$.type!="Button"&&$f$$.type!="Link"&&types.find($t$$=>$t$$.code==$f$$.type));$entries_fields_validFields$$=await Promise.all($entries_fields_validFields$$.map(async $f$$=>{var $fieldType_typeInfo$$=types.find($t$$=>$t$$.code==$f$$.type);$fieldType_typeInfo$$=$fieldType_typeInfo$$?$fieldType_typeInfo$$.type_data||$fieldType_typeInfo$$.code:
$f$$.type;let $fieldDef$$={type:$fieldType_typeInfo$$,required:$f$$.required==1||$f$$.required=="true"?!0:void 0,maxlength:$f$$.maxlength?Number($f$$.maxlength):void 0,ref:$f$$.ref_model||void 0,description:$f$$.api_description||$f$$.header||void 0};Object.keys($fieldDef$$).forEach($key$$=>$fieldDef$$[$key$$]===void 0&&delete $fieldDef$$[$key$$]);let $detailCode$$=$f$$.form||"";if($detailCode$$&&$detailCode$$!=="0")try{const $subList$$=await global.getModel("listinfo").findOne({code:$detailCode$$}).lean();
if($subList$$&&$subList$$.fields){let $subSchema$$=await buildJsonSchema($subList$$.fields,$depth$$+1);$fieldType_typeInfo$$==="Array"||$f$$.type==="Array"?$fieldDef$$.type=[$subSchema$$]:$fieldType_typeInfo$$==="Json"||$fieldType_typeInfo$$==="Mixed"||$f$$.type==="Mixed"?$fieldDef$$.type=$subSchema$$:$fieldDef$$.sub_schema=$subSchema$$}}catch($e$$){console.error($e$$)}return[$f$$.name,$fieldDef$$]}));return Object.fromEntries($entries_fields_validFields$$)},renderSchema=async function($fields$jscomp$1_rows_validFields$$,
$id_app$$,$import_yn$$=0,$depth$$=0){let $server_url$$=configs.api_url||configs.domain;if($depth$$>5)return"";var $cleanJson_jsonStr$$=await buildJsonSchema($fields$jscomp$1_rows_validFields$$);$cleanJson_jsonStr$$=JSON.stringify($cleanJson_jsonStr$$,null,2).replace(/</g,"\\u003c").replace(/>/g,"\\u003e");const $tableId$$="schema_"+Math.random().toString(36).substr(2,9);$fields$jscomp$1_rows_validFields$$=$fields$jscomp$1_rows_validFields$$.filter($f$$=>["ten_vt","ten_kh","ten_kho"].indexOf($f$$.name)>=
0||$f$$.not_input!="true"&&$f$$.not_input!=1&&$f$$.type!="Button"&&$f$$.type!="Link"&&types.find($t$$=>$t$$.code==$f$$.type));$fields$jscomp$1_rows_validFields$$=await Promise.all($fields$jscomp$1_rows_validFields$$.map(async $field$$=>{var $h_type$$=types.find($t$$=>$t$$.code==$field$$.type),$formattedJson_isJson_ref_model_html$$="",$description_detailCode$$=$field$$.ref_model||"";if($description_detailCode$$){$formattedJson_isJson_ref_model_html$$=typeof $description_detailCode$$==="string"&&($description_detailCode$$.trim().startsWith("{")||
$description_detailCode$$.trim().startsWith("["));const $hasComma$$=typeof $description_detailCode$$==="string"&&$description_detailCode$$.indexOf(",")>=0;if($formattedJson_isJson_ref_model_html$$||$hasComma$$){$formattedJson_isJson_ref_model_html$$=$description_detailCode$$;try{var $jsonObj$$=typeof $description_detailCode$$==="string"?JSON.parse($description_detailCode$$):$description_detailCode$$;$formattedJson_isJson_ref_model_html$$=JSON.stringify($jsonObj$$,null,2)}catch($e$$){console.error($e$$)}$formattedJson_isJson_ref_model_html$$=
`
<div style="margin-top:8px">
<span style="color:#7f8c8d; font-size:0.85em">C\u1ea5u tr\u00fac tham chi\u1ebfu (JSON):</span>
<pre style="background:#f4f4f4; padding:8px; border-radius:4px; font-size:11px; color:#2c3e50; border:1px solid #ddd; overflow-x:auto; max-width:350px; margin-top:4px;">${$formattedJson_isJson_ref_model_html$$}</pre>
</div>`}else $jsonObj$$=`${$server_url$$}/api-docs-input/${$description_detailCode$$}`,$id_app$$&&($jsonObj$$=$jsonObj$$+"?id_app="+$id_app$$),$formattedJson_isJson_ref_model_html$$=`
<div style="margin-top:8px">
<span style="color:#7f8c8d; font-size:0.85em">Tham chi\u1ebfu:</span>
<a href='${$jsonObj$$}' target='_blank' style='color:#3498db; text-decoration:none; font-weight:bold; border-bottom:1px dashed #3498db;'>${$description_detailCode$$}</a>
</div>`}$description_detailCode$$=$field$$.api_description||$field$$.header;["ten_vt","ten_kh","ten_kho"].indexOf($field$$.name)>=0&&($description_detailCode$$=`${$description_detailCode$$}. N\u1ebfu \u0111\u1ed1i t\u01b0\u1ee3ng n\u00e0y kh\u00f4ng t\u1ed3n t\u1ea1i trong danh m\u1ee5c th\u00ec h\u1ec7 th\u1ed1ng s\u1ebd s\u1eed d\u1ee5ng th\u00f4ng tin n\u00e0y \u0111\u1ec3 t\u1ea1o`);$h_type$$=`
<tr style="background:#fff">
<td style="font-weight:bold; color:#e67e22; vertical-align:top; padding:10px;">${$field$$.name}</td>
<td style="vertical-align:top; padding:10px;"><code>${$h_type$$.type_data||$h_type$$.code}</code></td>
<td style="text-align:center; vertical-align:top; padding:10px;">${$field$$.required==1||$field$$.required=="true"?"<b style='color:red'>Yes</b>":"No"}</td>
<td style="text-align:center; vertical-align:top; padding:10px;">${$field$$.type=="String"?$field$$.maxlength||4E3:"-"}</td>
<td style="vertical-align:top; padding:10px;">
<div style="font-weight:500">${$description_detailCode$$}</div>
${$field$$.help_text?`<div style='font-size:0.9em;color:#666;font-style:italic;margin-top:4px'>* ${$field$$.help_text}</div>`:""}
${$formattedJson_isJson_ref_model_html$$}
</td>
</tr>`;if(($description_detailCode$$=$field$$.form||"")&&$description_detailCode$$!=="0")try{const $subList$$=await global.getModel("listinfo").findOne({code:$description_detailCode$$}).lean();if($subList$$&&$subList$$.fields){const $subTable$$=await renderSchema($subList$$.fields,$id_app$$,$import_yn$$,$depth$$+1);$h_type$$+=`
<tr>
<td colspan="5" style="padding: 0 0 15px 40px; border-top:none; background:#fcfcfc;">
<div style="border-left:3px solid #3498db; padding-left:15px; margin-top:10px">
<div style="margin-bottom:8px; font-weight:bold; color:#3498db">\u21b3 C\u1ea5u tr\u00fac chi ti\u1ebft [${$description_detailCode$$}]:</div>
${$subTable$$}
</div>
</td>
</tr>`}}catch($e$$){console.error($e$$)}return $h_type$$}));return`
<div style="position: relative; margin-bottom: 10px;">
<div style="display: flex; justify-content: flex-end; margin-bottom: 8px;">
<button onclick="var t=document.getElementById('${$tableId$$}'); t.select(); document.execCommand('copy'); var b=this; var o=b.innerHTML; b.innerHTML='\u2705 \u0110\u00e3 Copy Mongoose Schema!'; b.style.background='#27ae60'; setTimeout(function(){b.innerHTML=o; b.style.background='#2c3e50';},2000);"
style="background: #2c3e50; color: #fff; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 12px; transition: 0.2s; font-weight: bold; box-shadow: 0 1px 2px rgba(0,0,0,0.2);">
\ud83d\udccb Copy Schema JSON
</button>
</div>
<textarea id="${$tableId$$}" style="position:absolute; left:-9999px; top:0;" aria-hidden="true">${$cleanJson_jsonStr$$}</textarea>
<table style="width:100%; border-collapse:collapse; font-size:13px; background:#fff" border="1" bordercolor="#ddd">
<tr style="background:#f2f2f2; text-align:left">
<th style="padding:10px; width:150px">Tr\u01b0\u1eddng (Field)</th>
<th style="padding:10px; width:100px">Ki\u1ec3u</th>
<th style="padding:10px; width:70px; text-align:center">B\u1eaft bu\u1ed9c</th>
<th style="padding:10px; width:70px; text-align:center">Max</th>
<th style="padding:10px">M\u00f4 t\u1ea3 / Tham chi\u1ebfu</th>
</tr>
${$fields$jscomp$1_rows_validFields$$.join("")}
</table>
</div>`},apiDocs=async function($code$$,$id_app$$){var $endpointsHtml_server_url$$=configs.api_url||configs.domain;$code$$=await global.getModel("listinfo").findOne({$or:[{code:$code$$},{api_code:$code$$}]}).lean();if(!$code$$)return"Kh\u00f4ng t\u00ecm th\u1ea5y t\u00e0i li\u1ec7u API.";var $authLink_controller$$=global.controllers[($code$$.api_code||$code$$.code).toUpperCase()];if(!$authLink_controller$$)return"API Controller ch\u01b0a s\u1eb5n s\u00e0ng.";let $route_name$$=$authLink_controller$$.route_name.replace(":id_app",
$id_app$$||"{id_app}");$authLink_controller$$=`${$endpointsHtml_server_url$$}/api-docs-auth`;let $idAppNote$$=$route_name$$.indexOf("id_app")>=0?'<li style="color:#8e44ad; margin-top:4px;"><b>id_app:</b> ID c\u1ee7a c\u00f4ng ty/chi nh\u00e1nh \u0111ang thao t\u00e1c (n\u1eb1m trong URL)</li>':"";$endpointsHtml_server_url$$=`
<h3>1. Danh s\u00e1ch c\u00e1c Endpoint</h3>
<table style="width:100%; border-collapse:collapse; margin-bottom:30px" border="1" bordercolor="#ddd">
<tr style="background:#eee">
<th style="padding:10px; width:180px;">Ch\u1ee9c n\u0103ng</th>
<th style="padding:10px; width:80px;">Method</th>
<th style="padding:10px">Chi ti\u1ebft C\u1ea5u h\u00ecnh (URL, Headers, Params, Body)</th>
</tr>
<tr style="background: #f0f7ff;">
<td style="padding:10px; font-weight:bold; color:#2980b9">Truy xu\u1ea5t d\u1eef li\u1ec7u<br/>(Search)</td>
<td style="padding:10px; text-align:center"><b>POST</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api/search${$route_name$$}</code>
<div style="margin-top:10px; font-size:13px;">
<ul style="padding-left:20px; margin:0 0 10px 0;">
${$idAppNote$$}
</ul>
<div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div>
<ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;">
<li><b>listinfo-code:</b> <code>${$code$$.code}</code></li>
</ul>
<div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div>
<ul style="margin:0; padding-left:20px;">
<li><b>page:</b> <code>Number</code>. Trang c\u1ea7n truy xu\u1ea5t (M\u1eb7c \u0111\u1ecbnh 1).</li>
<li><b>limit:</b> <code>Number</code>. S\u1ed1 d\u00f2ng tr\u00ean m\u1ed9t trang (M\u1eb7c \u0111\u1ecbnh 20).</li>
<li><b>fields:</b> <code>String</code>. C\u00e1c tr\u01b0\u1eddng c\u1ea7n l\u1ea5y, c\u00e1ch nhau d\u1ea5u ph\u1ea9y (M\u1eb7c \u0111\u1ecbnh l\u1ea5y t\u1ea5t c\u1ea3).</li>
<li><b>count:</b> <code>Number</code>. Gi\u00e1 tr\u1ecb 0 ho\u1eb7c 1. N\u1ebfu = 1 s\u1ebd tr\u1ea3 v\u1ec1 t\u1ed5ng s\u1ed1 k\u1ebft qu\u1ea3 \u0111\u1ebfm \u0111\u01b0\u1ee3c.</li>
<li style="background: #e8f4f8; padding: 5px; border-radius: 3px; margin: 5px 0;">
<b>pagination:</b> <code>Number</code>. Gi\u00e1 tr\u1ecb <code>1</code> ho\u1eb7c <code>0</code>.
N\u1ebfu truy\u1ec1n <code>1</code>, API s\u1ebd tr\u1ea3 v\u1ec1 d\u1eef li\u1ec7u d\u1ea1ng Object c\u00f3 th\u00f4ng tin ph\u00e2n trang:
<br/>
<code style="display:inline-block; margin-top:4px; background:#fff;">{ data: [d\u1eef li\u1ec7u trang hi\u1ec7n t\u1ea1i], pagination: { limit,total, page, totalPages } }</code>
</li>
<li><b>q:</b> <code>Json</code>. \u0110i\u1ec1u ki\u1ec7n l\u1ecdc (MongoDB Query). Tham kh\u1ea3o c\u1ea5u tr\u00fac t\u1ea1i b\u1ea3ng Schema.</li>
</ul>
</div>
</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold">L\u1ea5y chi ti\u1ebft 01 b\u1ea3n ghi<br/>(Get By ID)</td>
<td style="padding:10px; text-align:center"><b>GET</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/:_id</code>
<div style="margin-top:10px; font-size:13px;">
<ul style="margin:0; padding-left:20px;">
${$idAppNote$$}
<li><b>_id:</b> ID c\u1ee7a b\u1ea3n ghi c\u1ea7n l\u1ea5y d\u1eef li\u1ec7u (n\u1eb1m trong URL)</li>
</ul>
</div>
</td>
</tr>
${$code$$.not_add?"":`
<tr>
<td style="padding:10px; font-weight:bold">Th\u00eam m\u1edbi<br/>(Create)</td>
<td style="padding:10px; text-align:center"><b>POST</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}</code>
<div style="margin-top:10px; font-size:13px;">
<ul style="margin:0 0 10px 0; padding-left:20px;">${$idAppNote$$}</ul>
<div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div>
<ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;">
<li><b>listinfo-code:</b> <code>${$code$$.code}</code></li>
</ul>
<div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div>
<ul style="margin:0; padding-left:20px;">
<li>M\u1ed9t Object ch\u1ee9a d\u1eef li\u1ec7u c\u1ee7a b\u1ea3n ghi m\u1edbi. Tham kh\u1ea3o c\u1ea5u tr\u00fac t\u1ea1i b\u1ea3ng Schema.</li>
</ul>
</div>
</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold">Import d\u1eef li\u1ec7u<br/>(JSON Array)</td>
<td style="padding:10px; text-align:center"><b>POST</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/import/json</code>
<div style="margin-top:10px; font-size:13px;">
<ul style="margin:0 0 10px 0; padding-left:20px;">${$idAppNote$$}</ul>
<div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div>
<ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;">
<li><b>listinfo-code:</b> <code>${$code$$.code}</code></li>
</ul>
<div style="color:#16a085; font-weight:bold; margin-bottom:3px;">Query Parameters:</div>
<ul style="margin:0 0 10px 0; padding-left:20px; background:#e8f8f5; padding:5px 20px; border-radius:4px;">
<li><b>update:</b> <code>true</code> ho\u1eb7c <code>false</code>. C\u00f3 c\u1eadp nh\u1eadt gi\u00e1 tr\u1ecb m\u1edbi n\u1ebfu \u0111\u1ed1i t\u01b0\u1ee3ng \u0111\u00e3 t\u1ed3n t\u1ea1i hay kh\u00f4ng?</li>
</ul>
<div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div>
<ul style="margin:0; padding-left:20px;">
<li>L\u00e0 m\u1ed9t <b>m\u1ea3ng (Array)</b> ch\u1ee9a danh s\u00e1ch c\u00e1c b\u1ea3n ghi c\u1ea7n import.</li>
</ul>
</div>
</td>
</tr>`}
${$code$$.not_update?"":`
<tr>
<td style="padding:10px; font-weight:bold">C\u1eadp nh\u1eadt d\u1eef li\u1ec7u<br/>(Update)</td>
<td style="padding:10px; text-align:center"><b>PUT</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/:_id</code>
<div style="margin-top:10px; font-size:13px;">
<ul style="margin:0 0 10px 0; padding-left:20px;">
${$idAppNote$$}
<li><b>_id:</b> ID c\u1ee7a b\u1ea3n ghi c\u1ea7n c\u1eadp nh\u1eadt (n\u1eb1m trong URL)</li>
</ul>
<div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div>
<ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;">
<li><b>listinfo-code:</b> <code>${$code$$.code}</code></li>
</ul>
<div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div>
<ul style="margin:0; padding-left:20px;">
<li>C\u00e1c tr\u01b0\u1eddng d\u1eef li\u1ec7u c\u1ea7n thay \u0111\u1ed5i. C\u00f3 th\u1ec3 c\u1eadp nh\u1eadt 1 ho\u1eb7c nhi\u1ec1u tr\u01b0\u1eddng c\u00f9ng l\u00fac.</li>
</ul>
</div>
</td>
</tr>`}
${$code$$.not_delete?"":`
<tr>
<td style="padding:10px; font-weight:bold; color:#c0392b">Xo\u00e1 d\u1eef li\u1ec7u<br/>(Delete By ID)</td>
<td style="padding:10px; text-align:center"><b>DELETE</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/:_id</code>
<div style="margin-top:10px; font-size:13px;">
<ul style="margin:0; padding-left:20px;">
${$idAppNote$$}
<li><b>_id:</b> ID c\u1ee7a b\u1ea3n ghi c\u1ea7n xo\u00e1 (n\u1eb1m trong URL)</li>
</ul>
<div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers ri\u00eang:</div>
<ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;">
<li><b>listinfo-code:</b> <code>${$code$$.code}</code></li>
</ul>
</div>
</td>
</tr>
<tr style="background-color: #fff5f5;">
<td style="padding:10px; font-weight:bold; color:#c0392b">Xo\u00e1 h\u00e0ng lo\u1ea1t<br/>(Delete Many)</td>
<td style="padding:10px; text-align:center"><b>POST</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#fdeced; color:#000; padding:4px 8px;">${$endpointsHtml_server_url$$}/api${$route_name$$}/action/delete</code>
<div style="margin-top:10px; font-size:13px;">
<ul style="margin:0 0 10px 0; padding-left:20px;">${$idAppNote$$}</ul>
<div style="color:#c0392b; font-weight:bold; margin-bottom:3px;">Body (JSON):</div>
<ul style="margin:0; padding-left:20px;">
<li><b>condition:</b> <code>Json</code>. \u0110i\u1ec1u ki\u1ec7n xo\u00e1 d\u1eef li\u1ec7u (MongoDB Query).</li>
</ul>
</div>
</td>
</tr>`}
</table>
`;$id_app$$=await renderSchema($code$$.fields,$id_app$$);return`
<html lang="vi">
<head>
<meta charset="utf-8">
<title>T\u00e0i li\u1ec7u API - ${$code$$.title}</title>
<style>
body { font-family: 'Segoe UI', Tahoma, sans-serif; line-height: 1.5; color: #333; padding: 30px; max-width: 1200px; margin: 0 auto; background: #fafafa; }
h2 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 15px; margin-top:0; }
h3 { color: #2980b9; margin-top: 40px; font-size: 1.2em; text-transform: uppercase; }
code { font-family: 'Consolas', monospace; color: #c7254e; }
.auth-box { background:#fff; padding:15px 20px; border-left: 5px solid #3498db; border-radius:4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 30px; }
.schema-wrapper { background:#fff; padding:15px; border:1px solid #ddd; border-radius:6px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); overflow-x: auto;}
</style>
</head>
<body>
<h2>T\u00c0I LI\u1ec6U API: ${$code$$.title}</h2>
<div class="auth-box">
<strong style="font-size:1.1em;">Th\u00f4ng tin Headers d\u00f9ng chung cho T\u1ea4T C\u1ea2 request:</strong>
<ul style="margin-top:10px; list-style: none; padding-left: 0;">
<li style="margin-bottom:8px;">\ud83d\udd11 <b>access-token:</b> Token x\u00e1c th\u1ef1c. <a href="${$authLink_controller$$}" target="_blank" style="color:#3498db; text-decoration:none; font-weight:bold;">Xem h\u01b0\u1edbng d\u1eabn l\u1ea5y Token →</a></li>
<li>\ud83d\udcc4 <b>Content-Type:</b> <code>application/json</code></li>
</ul>
</div>
${$endpointsHtml_server_url$$}
<h3>2. B\u1ea3n \u0111\u1ed3 D\u1eef li\u1ec7u (Schema)</h3>
<p style="color:#555; font-size:0.95em;">
C\u1ea5u tr\u00fac d\u01b0\u1edbi \u0111\u00e2y li\u1ec7t k\u00ea to\u00e0n b\u1ed9 c\u00e1c tr\u01b0\u1eddng (fields) c\u1ee7a \u0111\u1ed1i t\u01b0\u1ee3ng. B\u1ea1n s\u1ebd d\u00f9ng c\u00e1c tr\u01b0\u1eddng n\u00e0y \u0111\u1ec3 g\u1eedi trong <b>Body</b> khi Th\u00eam/S\u1eeda, ho\u1eb7c d\u00f9ng \u0111\u1ec3 t\u1ea1o \u0111i\u1ec1u ki\u1ec7n l\u1ecdc trong tr\u01b0\u1eddng <code>q</code> (khi Search) v\u00e0 <code>condition</code> (khi Xo\u00e1 h\u00e0ng lo\u1ea1t).
</p>
<div class="schema-wrapper">
${$id_app$$}
</div>
</body>
</html>
`},renderReportColumns=function($columns$$){return $columns$$&&$columns$$.length!==0?`
<table style="width:100%; border-collapse:collapse; font-size:13px; background:#fff" border="1" bordercolor="#ddd">
<tr style="background:#f2f2f2; text-align:left">
<th style="padding:10px; width:250px">T\u00ean tr\u01b0\u1eddng tr\u1ea3 v\u1ec1 (Field)</th>
<th style="padding:10px; width:150px">Ki\u1ec3u d\u1eef li\u1ec7u (Datatype)</th>
<th style="padding:10px">Ti\u00eau \u0111\u1ec1 c\u1ed9t (Header)</th>
</tr>
${[...$columns$$].sort(($a$$,$b$$)=>($a$$.stt||0)-($b$$.stt||0)).map($col$$=>{let $typeColor$$="#c7254e";$col$$.datatype==="Number"&&($typeColor$$="#2980b9");if($col$$.datatype==="Date"||$col$$.datatype==="DateTime")$typeColor$$="#27ae60";return`
<tr style="background:#fff">
<td style="font-weight:bold; color:#e67e22; padding:10px;">${$col$$.field||""}</td>
<td style="padding:10px;"><code style="color:${$typeColor$$}; background:#f9f2f4; padding:2px 4px; border-radius:3px;">${$col$$.datatype||"String"}</code></td>
<td style="padding:10px; font-weight:500;">${$col$$.header||""}</td>
</tr>`}).join("")}
</table>`:""},apiReport=async function($code$$,$id_app$jscomp$2_schemaHtml$$){var $endpointsHtml$jscomp$1_server_url$$=configs.api_url||configs.domain;$code$$=await global.getModel("reportinfo").findOne({code:$code$$}).lean();if(!$code$$)return"Kh\u00f4ng t\u00ecm th\u1ea5y t\u00e0i li\u1ec7u cho b\u00e1o c\u00e1o n\u00e0y.";var $columnsHtml_listinfo$$;$code$$.form_condition_info&&($columnsHtml_listinfo$$=await global.getModel("listinfo").findOne({code:$code$$.form_condition_info}).lean());$columnsHtml_listinfo$$=
$columnsHtml_listinfo$$||{fields:[]};var $authLink$jscomp$1_controller$$=global.report_controllers[($code$$.api_code||$code$$.code).toUpperCase()];if(!$authLink$jscomp$1_controller$$)return"Report Controller ch\u01b0a s\u1eb5n s\u00e0ng.";let $route_name$$=`${$authLink$jscomp$1_controller$$.base_path}${$authLink$jscomp$1_controller$$.module}`.replace(":id_app",$id_app$jscomp$2_schemaHtml$$||"{id_app}");$authLink$jscomp$1_controller$$=`${$endpointsHtml$jscomp$1_server_url$$}/api-docs-auth`;let $idAppNote$$=
$route_name$$.indexOf("id_app")>=0?'<li style="color:#8e44ad; margin-top:4px;"><b>id_app:</b> ID c\u1ee7a c\u00f4ng ty/chi nh\u00e1nh \u0111ang thao t\u00e1c (n\u1eb1m trong URL)</li>':"";$endpointsHtml$jscomp$1_server_url$$=`
<h3>1. Th\u00f4ng tin Endpoint B\u00e1o c\u00e1o</h3>
<table style="width:100%; border-collapse:collapse; margin-bottom:30px" border="1" bordercolor="#ddd">
<tr style="background:#eee">
<th style="padding:10px; width:180px;">Ch\u1ee9c n\u0103ng</th>
<th style="padding:10px; width:80px;">Method</th>
<th style="padding:10px">Chi ti\u1ebft C\u1ea5u h\u00ecnh (URL, Headers, Body)</th>
</tr>
<tr style="background: #fdfaf0;">
<td style="padding:10px; font-weight:bold; color:#d35400">Xu\u1ea5t b\u00e1o c\u00e1o<br/>(Generate Report)</td>
<td style="padding:10px; text-align:center"><b>POST</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#fbeee6; color:#000; padding:4px 8px;">${$endpointsHtml$jscomp$1_server_url$$}/api${$route_name$$}</code>
<div style="margin-top:10px; font-size:13px;">
<ul style="padding-left:20px; margin:0 0 10px 0;">
${$idAppNote$$}
</ul>
<div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON) - \u0110i\u1ec1u ki\u1ec7n l\u1ecdc:</div>
<ul style="margin:0; padding-left:20px;">
<li>G\u1eedi m\u1ed9t Object ch\u1ee9a c\u00e1c tham s\u1ed1 l\u1ecdc. Xem c\u1ea5u tr\u00fac t\u1ea1i <b>M\u1ee5c 2</b>.</li>
</ul>
<div style="color:#16a085; font-weight:bold; margin-top:8px; margin-bottom:3px;">D\u1eef li\u1ec7u tr\u1ea3 v\u1ec1 (Response):</div>
<ul style="margin:0; padding-left:20px;">
<li>M\u1ed9t m\u1ea3ng JSON (Array) ch\u1ee9a c\u00e1c d\u00f2ng d\u1eef li\u1ec7u. Xem c\u1ea5u tr\u00fac c\u00e1c c\u1ed9t t\u1ea1i <b>M\u1ee5c 3</b>.</li>
</ul>
</div>
</td>
</tr>
</table>
`;$id_app$jscomp$2_schemaHtml$$=$columnsHtml_listinfo$$.fields&&$columnsHtml_listinfo$$.fields.length>0?await renderSchema($columnsHtml_listinfo$$.fields,$id_app$jscomp$2_schemaHtml$$):'<div style="padding: 15px; background: #f9f9f9; color: #666; font-style: italic; border-left: 3px solid #ccc;">B\u00e1o c\u00e1o n\u00e0y kh\u00f4ng y\u00eau c\u1ea7u tham s\u1ed1 l\u1ecdc (G\u1eedi Body l\u00e0 m\u1ed9t Object r\u1ed7ng <code>{}</code>).</div>';$columnsHtml_listinfo$$=$code$$.columns&&$code$$.columns.length>
0?renderReportColumns($code$$.columns):'<div style="padding: 15px; background: #fdfaf0; color: #d35400; font-style: italic; border-left: 3px solid #e67e22;">Ch\u01b0a c\u00f3 c\u1ea5u h\u00ecnh chi ti\u1ebft c\u00e1c c\u1ed9t tr\u1ea3 v\u1ec1 cho b\u00e1o c\u00e1o n\u00e0y.</div>';return`
<html lang="vi">
<head>
<meta charset="utf-8">
<title>T\u00e0i li\u1ec7u API Report - ${$code$$.title}</title>
<style>
body { font-family: 'Segoe UI', Tahoma, sans-serif; line-height: 1.5; color: #333; padding: 30px; max-width: 1200px; margin: 0 auto; background: #fafafa; }
h2 { color: #2c3e50; border-bottom: 3px solid #e67e22; padding-bottom: 15px; margin-top:0; }
h3 { color: #d35400; margin-top: 40px; font-size: 1.2em; text-transform: uppercase; }
code { font-family: 'Consolas', monospace; }
.auth-box { background:#fff; padding:15px 20px; border-left: 5px solid #e67e22; border-radius:4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 30px; }
.schema-wrapper { background:#fff; padding:15px; border:1px solid #ddd; border-radius:6px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); overflow-x: auto; margin-bottom: 20px;}
</style>
</head>
<body>
<h2>API REPORT: ${$code$$.title}</h2>
<div class="auth-box">
<strong style="font-size:1.1em;">Th\u00f4ng tin Headers b\u1eaft bu\u1ed9c cho Request:</strong>
<ul style="margin-top:10px; list-style: none; padding-left: 0;">
<li style="margin-bottom:8px;">\ud83d\udd11 <b>access-token:</b> Token x\u00e1c th\u1ef1c. <a href="${$authLink$jscomp$1_controller$$}" target="_blank" style="color:#d35400; text-decoration:none; font-weight:bold;">Xem h\u01b0\u1edbng d\u1eabn l\u1ea5y Token →</a></li>
<li>\ud83d\udcc4 <b>Content-Type:</b> <code>application/json</code></li>
</ul>
</div>
${$endpointsHtml$jscomp$1_server_url$$}
<h3>2. B\u1ea3n \u0111\u1ed3 D\u1eef ki\u1ec7n L\u1ecdc (Body Request)</h3>
<p style="color:#555; font-size:0.95em;">
G\u1eedi Object JSON ch\u1ee9a c\u00e1c tr\u01b0\u1eddng n\u00e0y l\u00ean API \u0111\u1ec3 l\u00e0m <b>\u0111i\u1ec1u ki\u1ec7n l\u1ecdc</b> cho b\u00e1o c\u00e1o.
</p>
<div class="schema-wrapper">
${$id_app$jscomp$2_schemaHtml$$}
</div>
<h3>3. C\u1ea5u tr\u00fac D\u1eef li\u1ec7u Tr\u1ea3 v\u1ec1 (Response Columns)</h3>
<p style="color:#555; font-size:0.95em;">
D\u1eef li\u1ec7u tr\u1ea3 v\u1ec1 (Response) l\u00e0 m\u1ed9t danh s\u00e1ch (Array) c\u00e1c b\u1ea3n ghi. M\u1ed7i b\u1ea3n ghi (Object) s\u1ebd bao g\u1ed3m c\u00e1c key \u0111\u01b0\u1ee3c \u0111\u1ecbnh ngh\u0129a d\u01b0\u1edbi \u0111\u00e2y:
</p>
<div class="schema-wrapper" style="border-top: 3px solid #16a085; padding: 0; border-radius: 4px; overflow: hidden;">
${$columnsHtml_listinfo$$}
</div>
<div style="margin-top:60px; border-top:1px solid #eee; padding-top:20px; text-align:center; color:#999; font-size:12px">
T\u00e0i li\u1ec7u API Report t\u1ef1 \u0111\u1ed9ng \u0111\u01b0\u1ee3c t\u1ea1o b\u1edfi h\u1ec7 th\u1ed1ng © 2026
</div>
</body>
</html>
`},apiAuth=function(){let $server_url$$=configs.api_url||configs.domain;return`
<html lang="vi">
<head>
<meta charset="utf-8">
<title>T\u00e0i li\u1ec7u API Auth & \u0110\u0103ng k\u00fd</title>
<style>
body { font-family: 'Segoe UI', Tahoma, sans-serif; line-height: 1.5; color: #333; padding: 30px; max-width: 1200px; margin: 0 auto; background: #fafafa; }
h2 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 15px; margin-top:0; }
h3 { color: #2980b9; margin-top: 40px; font-size: 1.2em; text-transform: uppercase; }
code { font-family: 'Consolas', monospace; color: #c7254e; background: #f9f2f4; padding: 2px 4px; border-radius: 3px; }
.info-box { background:#fff; padding:15px 20px; border-left: 5px solid #3498db; border-radius:4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 30px; }
</style>
</head>
<body>
<h2>API H\u1ec6 TH\u1ed0NG: X\u00c1C TH\u1ef0C & NG\u01af\u1edcI D\u00d9NG</h2>
<div class="info-box">
<p style="margin:0; color: #555;">T\u00e0i li\u1ec7u n\u00e0y h\u01b0\u1edbng d\u1eabn c\u00e1ch l\u1ea5y <b>access-token</b> th\u00f4ng qua API \u0110\u0103ng nh\u1eadp, c\u00e1ch qu\u1ea3n l\u00fd phi\u00ean l\u00e0m vi\u1ec7c (\u0110\u0103ng xu\u1ea5t, \u0110\u1ed5i m\u1eadt kh\u1ea9u) v\u00e0 c\u1ea5u tr\u00fac chi ti\u1ebft c\u1ee7a API \u0110\u0103ng k\u00fd t\u00e0i kho\u1ea3n m\u1edbi.</p>
</div>
${`
<h3>1. X\u00e1c th\u1ef1c & Qu\u1ea3n l\u00fd t\u00e0i kho\u1ea3n (Auth)</h3>
<table style="width:100%; border-collapse:collapse; margin-bottom:30px" border="1" bordercolor="#ddd">
<tr style="background:#eee">
<th style="padding:10px; width:180px;">Ch\u1ee9c n\u0103ng</th>
<th style="padding:10px; width:80px;">Method</th>
<th style="padding:10px">Chi ti\u1ebft C\u1ea5u h\u00ecnh (URL, Headers, Body)</th>
</tr>
<tr style="background: #f0f7ff;">
<td style="padding:10px; font-weight:bold; color:#2980b9">\u0110\u0103ng nh\u1eadp<br/>(Login)</td>
<td style="padding:10px; text-align:center"><b>GET</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#e1f0fa; color:#000; padding:4px 8px;">${$server_url$$}/auth/local</code>
<div style="margin-top:10px; font-size:13px;">
<div style="color:#d35400; font-weight:bold; margin-bottom:3px;">Headers b\u1eaft bu\u1ed9c:</div>
<ul style="margin:0 0 10px 0; padding-left:20px; background:#fff3e0; padding:5px 20px; border-radius:4px;">
<li><b>Authorization:</b> <span style="color:#e67e22; font-weight:bold;">Basic Auth</span> <span style="color:#666;">(M\u00e3 h\u00f3a Base64 c\u1ee7a <code>email:password</code>)</span></li>
</ul>
<div style="color:#16a085; font-weight:bold; margin-bottom:3px;">K\u1ebft qu\u1ea3 tr\u1ea3 v\u1ec1:</div>
<ul style="margin:0; padding-left:20px;">
<li>Tr\u1ea3 v\u1ec1 <code>access-token</code> v\u00e0 th\u00f4ng tin user. D\u00f9ng token n\u00e0y truy\u1ec1n v\u00e0o Headers cho c\u00e1c API kh\u00e1c.</li>
</ul>
</div>
</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold;">\u0110\u0103ng xu\u1ea5t<br/>(Logout)</td>
<td style="padding:10px; text-align:center"><b>GET</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#f9f9f9; color:#000; padding:4px 8px;">${$server_url$$}/api/user/logout</code>
<div style="margin-top:10px; font-size:13px;">
<div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Headers b\u1eaft bu\u1ed9c:</div>
<ul style="margin:0; padding-left:20px;">
<li><b>access-token:</b> Token hi\u1ec7n t\u1ea1i \u0111ang s\u1eed d\u1ee5ng c\u1ee7a phi\u00ean l\u00e0m vi\u1ec7c.</li>
</ul>
</div>
</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold;">\u0110\u1ed5i m\u1eadt kh\u1ea9u<br/>(Change Password)</td>
<td style="padding:10px; text-align:center"><b>POST</b></td>
<td style="padding:10px">
<code style="font-size:14px; background:#f9f9f9; color:#000; padding:4px 8px;">${$server_url$$}/api/changepassword</code>
<div style="margin-top:10px; font-size:13px;">
<div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Headers b\u1eaft bu\u1ed9c:</div>
<ul style="margin:0 0 10px 0; padding-left:20px;">
<li><b>access-token:</b> Token x\u00e1c th\u1ef1c.</li>
<li><b>Content-Type:</b> <code>application/json</code></li>
</ul>
<div style="color:#2c3e50; font-weight:bold; margin-bottom:3px;">Body (JSON):</div>
<ul style="margin:0; padding-left:20px;">
<li><b>oldPassword:</b> <code>String</code>. M\u1eadt kh\u1ea9u hi\u1ec7n t\u1ea1i.</li>
<li><b>newPassword:</b> <code>String</code>. M\u1eadt kh\u1ea9u m\u1edbi.</li>
<li><b>reNewPassword:</b> <code>String</code>. X\u00e1c nh\u1eadn l\u1ea1i m\u1eadt kh\u1ea9u m\u1edbi.</li>
</ul>
</div>
</td>
</tr>
</table>
`}
${`
<h3>2. \u0110\u0103ng k\u00fd t\u00e0i kho\u1ea3n (Sign Up)</h3>
<p style="color:#555; font-size:0.95em;">
API n\u00e0y d\u00f9ng \u0111\u1ec3 \u0111\u0103ng k\u00fd t\u00e0i kho\u1ea3n ng\u01b0\u1eddi d\u00f9ng m\u1edbi. Ngo\u00e0i ra, API c\u00f2n h\u1ed7 tr\u1ee3: <b>T\u1ef1 \u0111\u1ed9ng th\u00eam user v\u00e0o m\u1ed9t c\u00f4ng ty (App) c\u00f3 s\u1eb5n</b> ho\u1eb7c <b>Kh\u1edfi t\u1ea1o c\u00f4ng ty m\u1edbi</b> khi \u0111\u0103ng k\u00fd.
</p>
<table style="width:100%; border-collapse:collapse; margin-bottom:20px" border="1" bordercolor="#ddd">
<tr style="background:#fdfaf0;">
<td style="padding:15px; text-align:center; width:80px; font-weight:bold; color:#d35400;">POST</td>
<td style="padding:15px;"><code style="font-size:15px; background:none; color:#d35400;">${$server_url$$}/signup</code></td>
</tr>
</table>
<div style="display:flex; gap: 20px; flex-wrap: wrap; margin-bottom: 20px;">
<div style="flex:1; min-width: 300px;">
<h4 style="color:#2c3e50; margin-bottom: 10px;">Query Parameters (T\u00f9y ch\u1ecdn)</h4>
<table style="width:100%; border-collapse:collapse; font-size:13px; background:#fff" border="1" bordercolor="#ddd">
<tr style="background:#f2f2f2; text-align:left">
<th style="padding:8px;">Tham s\u1ed1</th>
<th style="padding:8px; width:80px;">Ki\u1ec3u</th>
<th style="padding:8px;">M\u00f4 t\u1ea3</th>
</tr>
<tr><td style="padding:8px; font-weight:bold; color:#e67e22;">g-recaptcha-response</td><td style="padding:8px;"><code>String</code></td><td style="padding:8px;">Token c\u1ee7a Google reCAPTCHA</td></tr>
<tr><td style="padding:8px; font-weight:bold; color:#e67e22;">once</td><td style="padding:8px;"><code>Boolean</code></td><td style="padding:8px;">\u0110\u00e1nh d\u1ea5u Token ch\u1ec9 s\u1eed d\u1ee5ng m\u1ed9t l\u1ea7n</td></tr>
</table>
</div>
<div style="flex:1; min-width: 300px;">
<h4 style="color:#2c3e50; margin-bottom: 10px;">Headers / Cookies</h4>
<ul style="background:#fff; border:1px solid #ddd; padding:15px 20px 15px 40px; border-radius:4px; font-size:13px; margin:0;">
<li style="margin-bottom:8px;"><b>Cookie (uid):</b> Ph\u1ee5c v\u1ee5 Rate Limit - Gi\u1edbi h\u1ea1n m\u1ed7i thi\u1ebft b\u1ecb ch\u1ec9 \u0111\u01b0\u1ee3c t\u1ea1o 1 t\u00e0i kho\u1ea3n.</li>
<li><b>User-Agent:</b> \u0110\u01b0\u1ee3c l\u01b0u v\u00e0o log h\u1ec7 th\u1ed1ng \u0111\u1ec3 theo d\u00f5i thi\u1ebft b\u1ecb \u0111\u0103ng k\u00fd.</li>
</ul>
</div>
</div>
<h4 style="color:#2c3e50; margin-top:30px; margin-bottom: 10px;">Body Payload (JSON)</h4>
<table style="width:100%; border-collapse:collapse; font-size:13px; background:#fff; margin-bottom:30px;" border="1" bordercolor="#ddd">
<tr style="background:#f2f2f2; text-align:left">
<th style="padding:10px; width:180px">Tr\u01b0\u1eddng (Field)</th>
<th style="padding:10px; width:80px">Ki\u1ec3u</th>
<th style="padding:10px; width:80px; text-align:center">B\u1eaft bu\u1ed9c</th>
<th style="padding:10px">M\u00f4 t\u1ea3 chi ti\u1ebft</th>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">email</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center; color:red; font-weight:bold;">Yes</td>
<td style="padding:10px;">Email ho\u1eb7c S\u1ed1 \u0111i\u1ec7n tho\u1ea1i VN h\u1ee3p l\u1ec7. <i>(T\u1ef1 \u0111\u1ed9ng trim & lowercase)</i></td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">name</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center; color:red; font-weight:bold;">Yes</td>
<td style="padding:10px;">H\u1ecd v\u00e0 t\u00ean ng\u01b0\u1eddi d\u00f9ng.</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">password</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center;">No</td>
<td style="padding:10px;">T\u1ed1i thi\u1ec3u 6 k\u00fd t\u1ef1 (g\u1ed3m ch\u1eef hoa, ch\u1eef th\u01b0\u1eddng, s\u1ed1). <b>N\u1ebfu kh\u00f4ng g\u1eedi, h\u1ec7 th\u1ed1ng t\u1ef1 sinh m\u1eadt kh\u1ea9u an to\u00e0n v\u00e0 g\u1eedi qua email.</b></td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">rePassword</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center; color:#e67e22;">(*)</td>
<td style="padding:10px;">B\u1eaft bu\u1ed9c n\u1ebfu c\u00f3 truy\u1ec1n <code>password</code>. Ph\u1ea3i kh\u1edbp v\u1edbi password.</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">id_app</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center;">No</td>
<td style="padding:10px;">MongoDB ObjectId c\u1ee7a c\u00f4ng ty. N\u1ebfu truy\u1ec1n, user s\u1ebd \u0111\u01b0\u1ee3c add v\u00e0o c\u00f4ng ty n\u00e0y.</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">cty_name</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center;">No</td>
<td style="padding:10px;">T\u00ean c\u00f4ng ty. D\u00f9ng \u0111\u1ec3 kh\u1edfi t\u1ea1o c\u00f4ng ty m\u1edbi n\u1ebfu ch\u01b0a c\u00f3 <code>id_app</code>.</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">introduce_code</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center;">No</td>
<td style="padding:10px;">M\u00e3 ng\u01b0\u1eddi gi\u1edbi thi\u1ec7u (Referral code).</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">g-recaptcha-response</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center; color:#e67e22;">(*)</td>
<td style="padding:10px;">Token reCAPTCHA. Y\u00eau c\u1ea7u ph\u1ee5 thu\u1ed9c v\u00e0o c\u1ea5u h\u00ecnh b\u1ea3o m\u1eadt c\u1ee7a h\u1ec7 th\u1ed1ng.</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">email2</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center;">No</td>
<td style="padding:10px;">Email ph\u1ee5.</td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">picture</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center;">No</td>
<td style="padding:10px;">URL Avatar. M\u1eb7c \u0111\u1ecbnh: <code>/images/avatar.jpg</code></td>
</tr>
<tr>
<td style="padding:10px; font-weight:bold; color:#e67e22;">partner</td>
<td style="padding:10px;"><code>String</code></td>
<td style="padding:10px; text-align:center;">No</td>
<td style="padding:10px;">ID c\u1ee7a \u0111\u1ed1i t\u00e1c li\u00ean k\u1ebft.</td>
</tr>
</table>
<div style="display:flex; gap: 20px; flex-wrap: wrap;">
<div style="flex:1; min-width: 300px;">
<h4 style="color:#2c3e50; margin-bottom: 10px;">K\u1ebft qu\u1ea3 tr\u1ea3 v\u1ec1 (Response)</h4>
<div style="background:#2c3e50; padding: 15px; border-radius: 6px; color: #ecf0f1; font-family: monospace; font-size: 13px; line-height:1.4;">
<span style="color: #2ecc71;">// Th\u00e0nh c\u00f4ng (HTTP 200 OK)</span>
{
"message": "T\u00e0i kho\u1ea3n \u0111\u00e3 \u0111\u01b0\u1ee3c \u0111\u0103ng k\u00fd th\u00e0nh c\u00f4ng",
"token": "eyJhbGciOiJIUzI1NiIsInR...",
"active": true
}
<span style="color: #e74c3c;">// Th\u1ea5t b\u1ea1i (HTTP 400 Bad Request)</span>
{
"error": "T\u00e0i kho\u1ea3n \u0111\u00e3 t\u1ed3n t\u1ea1i / Thi\u1ebft b\u1ecb \u0111\u00e3 \u0111\u01b0\u1ee3c \u0111\u0103ng k\u00fd"
}
</div>
</div>
<div style="flex:1; min-width: 300px;">
<h4 style="color:#2c3e50; margin-bottom: 10px;">Business Logic Quan Tr\u1ecdng</h4>
<ul style="background:#fff; border:1px solid #ddd; padding:15px 20px 15px 40px; border-radius:4px; font-size:13px; margin:0; line-height: 1.8;">
<li><b>\u0110\u1ecbnh d\u1ea1ng T\u1ef1 \u0111\u1ed9ng:</b> Email v\u00e0 S\u0110T lu\u00f4n \u0111\u01b0\u1ee3c t\u1ef1 \u0111\u1ed9ng lo\u1ea1i b\u1ecf kho\u1ea3ng tr\u1eafng (trim) v\u00e0 chuy\u1ec3n v\u1ec1 in th\u01b0\u1eddng (lowercase).</li>
<li><b>Auto Password:</b> N\u1ebfu kh\u00f4ng truy\u1ec1n password, h\u1ec7 th\u1ed1ng t\u1ef1 \u0111\u1ed9ng sinh v\u00e0 g\u1eedi v\u1ec1 email \u0111\u00e3 \u0111\u0103ng k\u00fd.</li>
<li><b>Join Company:</b> N\u1ebfu email/S\u0110T \u0111\u00e3 t\u1ed3n t\u1ea1i, thay v\u00ec b\u00e1o l\u1ed7i, h\u1ec7 th\u1ed1ng cho ph\u00e9p th\u00eam t\u00e0i kho\u1ea3n \u0111\u00f3 v\u00e0o m\u1ed9t App (c\u00f4ng ty) m\u1edbi.</li>
<li><b>B\u1ea3o v\u1ec7 ch\u1ed1ng Spam:</b> T\u00edch h\u1ee3p Rate limit d\u1ef1a tr\u00ean Cookie (uid) v\u00e0 IP \u0111\u1ec3 ng\u0103n ch\u1eb7n \u0111\u0103ng k\u00fd h\u00e0ng lo\u1ea1t.</li>
</ul>
</div>
</div>
`}
<div style="margin-top:60px; border-top:1px solid #eee; padding-top:20px; text-align:center; color:#999; font-size:12px">
T\u00e0i li\u1ec7u API Core/Auth t\u1ef1 \u0111\u1ed9ng \u0111\u01b0\u1ee3c t\u1ea1o b\u1edfi h\u1ec7 th\u1ed1ng © 2026
</div>
</body>
</html>
`};module.exports={apiDocs,apiReport,apiAuth};