feat: 회원가입 안내 및 oauth 2 페이지 퍼블리싱

This commit is contained in:
hong
2026-07-03 16:41:24 +09:00
parent 1c57d348e6
commit 551a2da717
8 changed files with 1428 additions and 1006 deletions
+374 -279
View File
@@ -694,6 +694,7 @@ hr {
--accent-green: #6BCF7F;
--accent-purple: #A78BFA;
--accent-color:#efdcb2;
--accent-light: #E9F9FF;
--text-dark: #1A1A2E;
--text-gray: #64748B;
--text-light: #94A3B8;
@@ -19084,262 +19085,329 @@ body.commission-print-page .btn-primary:hover {
font-size: 14px;
}
}
.signup-guide {
max-width: 1200px;
.service-main {
max-width: 1240px;
margin: 0 auto;
padding: 64px 20px 80px;
background-color: #f9fafb;
}
.signup-guide__header {
margin-bottom: 64px;
}
.signup-guide__title {
font-size: 48px;
line-height: 1;
color: #0049b4;
margin: 0 0 22px 0;
}
.signup-guide__underline {
width: 96px;
height: 4px;
background-color: #0049b4;
margin-bottom: 36px;
}
.signup-guide__desc p {
font-size: 20px;
font-weight: 400;
line-height: 1.625;
color: #1e2939;
margin: 0;
}
.signup-guide__card {
background: #fff;
border-radius: 16px;
padding: 48px 50px;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
margin-bottom: 64px;
}
.signup-guide__steps {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 16px;
}
.signup-guide__step {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.signup-guide__step--last .signup-guide__step-line {
display: none;
}
.signup-guide__step-icon {
width: 64px;
height: 64px;
border-radius: 50%;
background: #fff;
border: 1.6px solid #0049b4;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 2;
}
.signup-guide__step-icon svg {
width: 32px;
height: 32px;
}
.signup-guide__step-dot {
width: 12px;
height: 12px;
background-color: #0049b4;
border-radius: 50%;
margin-top: 12px;
position: relative;
z-index: 2;
}
.signup-guide__step-label {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 8px;
text-align: center;
}
.signup-guide__step-num {
font-size: 14px;
font-weight: 400;
color: #6a7282;
line-height: 20px;
}
.signup-guide__step-text {
font-size: 14px;
font-weight: 700;
color: #1e2939;
line-height: 20px;
margin-top: 4px;
white-space: nowrap;
}
.signup-guide__step-line {
position: absolute;
top: 32px;
left: calc(50% + 32px);
width: calc(100% - 32px);
height: 2px;
background: linear-gradient(to right, #0049b4, rgba(0, 73, 180, 0.3));
z-index: 1;
}
.signup-guide__notes {
margin-bottom: 48px;
}
.signup-guide__note {
padding: 60px 40px;
display: flex;
gap: 60px;
align-items: flex-start;
gap: 8px;
font-size: 18px;
font-weight: 400;
line-height: 32px;
color: #1e2939;
margin: 0 0 16px 0;
}
.signup-guide__note:last-child {
margin-bottom: 0;
.service-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 40px;
}
.signup-guide__note-mark {
.service-sidebar {
width: 213px;
flex-shrink: 0;
width: 18px;
}
.signup-guide__action {
text-align: center;
padding-top: 16px;
.service-nav {
display: flex;
flex-direction: column;
gap: 26px;
background: #fff;
border: 1px solid #e3e8f0;
border-radius: 20px;
padding: 28px 30px;
}
.signup-guide__btn {
display: inline-block;
padding: 18px 64px;
background: #0049b4;
color: #fff;
font-size: 18px;
font-weight: 600;
border-radius: 8px;
.service-nav:hover {
box-shadow: 0 4px 4px rgba(173, 173, 173, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.service-nav__item {
font-size: 16px;
font-weight: 500;
color: #0d0e11;
text-decoration: none;
transition: background 0.2s ease, transform 0.2s ease;
transition: color 0.2s;
}
.signup-guide__btn:hover {
background: rgb(0, 65.7, 162);
transform: translateY(-2px);
.service-nav__item:hover {
color: #2a69de;
}
.signup-guide__btn:active {
transform: translateY(0);
.service-nav__item--active {
color: #2a69de;
font-weight: 700;
}
@media (max-width: 1024px) {
.signup-guide {
padding: 48px 24px 64px;
.service-main {
flex-direction: column;
padding: 40px 20px;
}
.signup-guide__title {
font-size: 36px;
.service-sidebar {
width: 100%;
}
.signup-guide__steps {
grid-template-columns: repeat(3, 1fr);
gap: 24px 16px;
.service-nav {
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
padding: 20px;
}
.signup-guide__step:nth-child(3) .signup-guide__step-line {
display: none;
}
.signup-guide-v2 {
background-color: #fff;
padding-bottom: 100px;
}
.signup-guide-v2 .signup-hero {
background: linear-gradient(to right, #eff9fe, #fcfeff);
border: 1px solid #9cc2ff;
padding: 60px 0;
display: flex;
justify-content: center;
width: calc(100vw - 80px);
position: relative;
left: 50%;
transform: translateX(-50%);
margin-top: 40px;
}
.signup-guide-v2 .signup-hero__inner {
max-width: 1240px;
width: 100%;
display: flex;
align-items: center;
gap: 138px;
padding: 0 37px;
}
.signup-guide-v2 .signup-hero__icon-wrapper {
width: 230px;
height: 167px;
position: relative;
background: radial-gradient(circle at 50% 120%, rgba(0, 73, 180, 0.1), transparent 70%);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: #adb5bd;
}
.signup-guide-v2 .signup-hero__content {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 15px;
}
.signup-guide-v2 .signup-hero__badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 20px;
background: #fff;
border: 1px solid #d1e6f0;
border-radius: 38px;
}
.signup-guide-v2 .signup-hero__badge-dot {
width: 8px;
height: 8px;
background: var(--primary-color);
border-radius: 50%;
}
.signup-guide-v2 .signup-hero__badge-text {
font-size: 13px;
font-weight: 700;
color: #1b4ab7;
}
.signup-guide-v2 .signup-hero__title {
font-size: 36px;
font-weight: 700;
color: #000;
margin: 0;
}
.signup-guide-v2 .signup-hero__desc {
font-size: 16px;
font-weight: 500;
color: #6678ad;
line-height: 1.5;
margin: 0;
}
.signup-guide-v2 .signup-info-box {
background: #f5f5f5;
border-radius: 12px;
padding: 30px 40px;
display: flex;
align-items: center;
gap: 30px;
}
.signup-guide-v2 .signup-info-box__icon {
width: 76px;
height: 76px;
background: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.signup-guide-v2 .signup-info-box__icon img {
width: 40px;
height: 40px;
object-fit: contain;
}
.signup-guide-v2 .signup-info-box ul {
margin: 0;
padding-left: 0;
list-style: none;
}
.signup-guide-v2 .signup-info-box ul li {
position: relative;
padding-left: 14px;
color: #535151;
font-size: 16px;
font-weight: 500;
line-height: 1.8;
word-break: keep-all;
}
.signup-guide-v2 .signup-info-box ul li::before {
content: "·";
position: absolute;
left: 0;
color: #535151;
}
.signup-guide-v2 .signup-timeline {
display: flex;
flex-direction: column;
gap: 40px;
position: relative;
padding-left: 80px;
}
.signup-guide-v2 .signup-timeline::before {
content: "";
position: absolute;
left: 17px;
top: 47px;
bottom: 47px;
width: 2px;
background: #e6eefb;
z-index: 0;
}
.signup-guide-v2 .signup-step {
display: flex;
align-items: center;
gap: 40px;
position: relative;
z-index: 1;
}
.signup-guide-v2 .signup-step::before {
content: "";
position: absolute;
left: -71px;
top: 50%;
transform: translateY(-50%);
width: 16px;
height: 16px;
background: #2a69de;
border-radius: 50%;
box-shadow: 0 0 0 6px rgba(42, 105, 222, 0.15), 0 0 10px 6px rgba(42, 105, 222, 0.1);
z-index: 2;
}
.signup-guide-v2 .signup-step__icon-box {
width: 95px;
height: 95px;
background: #fff;
border: 1px solid #e3e8f0;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
box-shadow: 0 4px 4px rgba(173, 173, 173, 0.1);
}
.signup-guide-v2 .signup-step__icon-box svg {
width: 30px;
height: 30px;
}
.signup-guide-v2 .signup-step__card {
flex: 1;
background: #fff;
border: 1px solid #e3e8f0;
border-radius: 20px;
padding: 0 30px;
box-shadow: 0 4px 4px rgba(173, 173, 173, 0.1);
display: flex;
flex-direction: column;
justify-content: center;
height: 95px;
}
.signup-guide-v2 .signup-step__card-num {
font-size: 14px;
font-weight: 700;
color: #1b4ab7;
margin-bottom: 4px;
}
.signup-guide-v2 .signup-step__card-title {
font-size: 18px;
font-weight: 500;
color: #000;
margin: 0;
font-family: "Spoqa Han Sans Neo", "SpoqaHanSans", "Noto Sans KR", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}
.signup-guide-v2 .signup-step .one {
color: #2C4A8C;
}
.signup-guide-v2 .signup-step .two {
color: #1F7A5C;
}
.signup-guide-v2 .signup-step .three {
color: #F98E24;
}
.signup-guide-v2 .signup-step .four {
color: #2480F9;
}
.signup-guide-v2 .signup-step .five {
color: #FF5C5C;
}
.signup-guide-v2 .signup-step .six {
color: #5B4AEE;
}
.signup-guide-v2 .signup-action {
display: flex;
justify-content: center;
margin-top: 20px;
}
.signup-guide-v2 .signup-action__btn {
display: inline-block;
background: #2a69de;
color: #fff;
font-size: 20px;
font-weight: 700;
padding: 16px 48px;
border-radius: 10px;
text-decoration: none;
transition: background 0.2s, transform 0.2s;
}
.signup-guide-v2 .signup-action__btn:hover {
background: rgb(31.8731707317, 92.7219512195, 205.7268292683);
transform: translateY(-2px);
}
@media (max-width: 1024px) {
.signup-guide-v2 .signup-hero__inner {
flex-direction: column;
gap: 30px;
text-align: center;
}
.signup-guide__step-line {
width: calc(100% - 24px);
.signup-guide-v2 .signup-hero__content {
align-items: center;
}
}
@media (max-width: 768px) {
.signup-guide {
padding: 32px 16px 48px;
.signup-guide-v2 .signup-step {
gap: 20px;
}
.signup-guide__header {
margin-bottom: 32px;
.signup-guide-v2 .signup-step__icon-box {
width: 70px;
height: 70px;
}
.signup-guide__title {
font-size: 28px;
.signup-guide-v2 .signup-step__icon-box svg {
width: 32px;
height: 32px;
}
.signup-guide__underline {
width: 64px;
height: 3px;
margin-bottom: 24px;
}
.signup-guide__desc p {
font-size: 16px;
line-height: 1.75;
}
.signup-guide__card {
padding: 32px 20px;
margin-bottom: 32px;
}
.signup-guide__steps {
grid-template-columns: repeat(2, 1fr);
gap: 32px 16px;
}
.signup-guide__step:nth-child(2n) .signup-guide__step-line {
display: none;
}
.signup-guide__step:nth-child(3) .signup-guide__step-line {
display: block;
}
.signup-guide__step-icon {
width: 56px;
height: 56px;
}
.signup-guide__step-icon svg {
width: 28px;
height: 28px;
}
.signup-guide__step-dot {
width: 10px;
height: 10px;
}
.signup-guide__step-text {
font-size: 13px;
white-space: normal;
}
.signup-guide__step-line {
top: 28px;
left: calc(50% + 28px);
width: calc(100% - 28px);
}
.signup-guide__notes {
margin-bottom: 32px;
}
.signup-guide__note {
font-size: 14px;
line-height: 24px;
}
.signup-guide__btn {
padding: 16px 48px;
font-size: 16px;
width: 100%;
max-width: 320px;
}
}
@media (max-width: 480px) {
.signup-guide__steps {
grid-template-columns: 1fr;
gap: 24px;
}
.signup-guide__step {
flex-direction: row;
align-items: center;
gap: 16px;
}
.signup-guide__step .signup-guide__step-line {
display: none !important;
}
.signup-guide__step-icon {
flex-shrink: 0;
}
.signup-guide__step-dot {
display: none;
}
.signup-guide__step-label {
align-items: flex-start;
margin-top: 0;
text-align: left;
.signup-guide-v2 .signup-step__card {
height: 70px;
padding: 0 20px;
}
}
.service_guide_header {
@@ -19404,7 +19472,8 @@ body.commission-print-page .btn-primary:hover {
border-radius: 8px;
overflow: hidden;
}
.service_member_table table th, .service_member_table table td {
.service_member_table table th,
.service_member_table table td {
padding: 16px;
font-size: 14px;
line-height: 22px;
@@ -19489,7 +19558,8 @@ body.commission-print-page .btn-primary:hover {
max-width: 800px;
margin: 0 auto;
}
.service_member_table table th, .service_member_table table td {
.service_member_table table th,
.service_member_table table td {
padding: 20px 24px;
font-size: 15px;
}
@@ -19507,17 +19577,27 @@ body.commission-print-page .btn-primary:hover {
font-size: 18px;
}
}
.oauth2-2legged {
max-width: 1200px;
.oauth-main {
max-width: 1240px;
margin: 0 auto;
padding: 60px 40px;
display: flex;
gap: 60px;
align-items: flex-start;
}
.oauth2-2legged {
max-width: 1240px;
margin: 0 auto;
padding: 20px;
background-color: #FFFFFF;
color: #1A1A2E;
display: flex;
flex-direction: column;
gap: 24px;
box-sizing: border-box;
}
.oauth2-2legged__prereq, .oauth2-2legged__sequence, .oauth2-2legged__step, .oauth2-2legged__errors, .oauth2-2legged__error-example {
margin-bottom: 50px;
}
.oauth2-2legged__eyebrow {
display: inline-block;
font-size: 14px;
@@ -19527,7 +19607,7 @@ body.commission-print-page .btn-primary:hover {
margin-bottom: 8px;
}
.oauth2-2legged__h2 {
margin: 0 0 8px;
margin: 0 0 20px;
font-size: 26px;
font-weight: 700;
line-height: 1.3;
@@ -19540,57 +19620,68 @@ body.commission-print-page .btn-primary:hover {
color: #64748B;
}
.oauth2-2legged__hero {
background: linear-gradient(to right, #eff9fe, #fcfeff);
border: 1px solid #9cc2ff;
padding: 60px 0;
display: flex;
justify-content: center;
width: calc(100vw - 80px);
position: relative;
display: grid;
grid-template-columns: 1fr 320px;
gap: 32px;
padding: 48px 80px;
border-radius: 20px;
border: 1px solid #E2E8F0;
background: linear-gradient(135deg, #EDF9FE 0%, #FFFFFF 100%);
left: 50%;
transform: translateX(-50%);
margin-top: 40px;
}
.oauth2-2legged__hero-inner {
max-width: 1240px;
width: 100%;
display: flex;
align-items: center;
gap: 138px;
padding: 0 37px;
}
.oauth2-2legged__hero-body {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 15px;
}
.oauth2-2legged__hero-eyebrow {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 6px 18px;
border-radius: 14px;
background: #FFFFFF;
border: 1px solid #c3dfea;
color: #0049b4;
gap: 8px;
padding: 8px 20px;
background: #fff;
border: 1px solid #d1e6f0;
border-radius: 38px;
font-size: 13px;
font-weight: 600;
margin-bottom: 18px;
font-weight: 700;
color: #1b4ab7;
}
.oauth2-2legged__hero-eyebrow-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #0049b4;
background: var(--primary-color);
}
.oauth2-2legged__hero-title {
margin: 0 0 16px;
font-size: 36px;
font-weight: 800;
color: #1A1A2E;
letter-spacing: -0.5px;
line-height: 1.2;
white-space: nowrap;
color: #000;
margin: 0;
}
.oauth2-2legged__hero-lead {
margin: 0;
font-size: 16px;
font-weight: 500;
color: #64748B;
line-height: 1.6;
color: #6678ad;
line-height: 1.5;
margin: 0;
}
.oauth2-2legged__hero-lead + .oauth2-2legged__hero-lead {
margin-top: 2px;
margin-top: 4px;
}
.oauth2-2legged__hero-chips {
display: flex;
gap: 12px;
margin-top: 22px;
flex-wrap: wrap;
}
.oauth2-2legged__chip {
@@ -19610,16 +19701,19 @@ body.commission-print-page .btn-primary:hover {
color: #FFFFFF;
}
.oauth2-2legged__hero-illust {
align-self: center;
background: #FFFFFF;
border: 1px solid #c3dfea;
border-radius: 20px;
overflow: hidden;
width: 230px;
height: 167px;
position: relative;
background: radial-gradient(circle at 50% 120%, rgba(0, 73, 180, 0.1), transparent 70%);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.oauth2-2legged__hero-illust svg {
display: block;
width: 100%;
height: auto;
height: 100%;
}
.oauth2-2legged__prereq-grid {
display: grid;
@@ -19676,8 +19770,8 @@ body.commission-print-page .btn-primary:hover {
height: auto;
}
.oauth2-2legged__step-grid {
display: grid;
grid-template-columns: 1fr 1fr;
display: flex;
flex-direction: column;
gap: 24px;
}
.oauth2-2legged__endpoint-box {
@@ -20004,12 +20098,13 @@ body.commission-print-page .btn-primary:hover {
}
@media (max-width: 1024px) {
.oauth2-2legged__hero {
grid-template-columns: 1fr;
padding: 32px;
.oauth2-2legged__hero-inner {
flex-direction: column;
gap: 30px;
text-align: center;
}
.oauth2-2legged__hero-illust {
max-width: 280px;
.oauth2-2legged__hero-body {
align-items: center;
}
.oauth2-2legged__prereq-grid {
grid-template-columns: 1fr;
@@ -20037,7 +20132,7 @@ body.commission-print-page .btn-primary:hover {
gap: 16px;
}
.oauth2-2legged__hero {
padding: 28px 24px;
padding: 40px 0;
}
.oauth2-2legged__hero-title {
font-size: 28px;
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 537 KiB

File diff suppressed because it is too large Load Diff
@@ -1,156 +1,220 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/djbank_title_layout}">
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/djbank_title_layout}">
<body>
<th:block layout:fragment="contentFragment">
<div class="signup-guide">
<!-- Header Section -->
<div class="signup-guide__header">
<h1 class="signup-guide__title">회원 가입 안내</h1>
<div class="signup-guide__underline"></div>
<div class="signup-guide__desc">
<p>DJBank API 개발자 포털에 방문해 주셔서 감사합니다.</p>
<p>DJBank API 사용을 위해서는 다음과 같은 이용절차로 진행하여야 합니다.</p>
<th:block layout:fragment="contentFragment">
<div class="signup-guide-v2">
<!-- Hero Section -->
<section class="signup-hero">
<div class="signup-hero__inner">
<div class="signup-hero__icon-wrapper">
<img th:src="@{/img/keyimage/signUp_img.svg}" alt="회원가입 소개 3D 아이콘"
style="width: 100%; height: 100%; object-fit: contain;" />
</div>
<div class="signup-hero__content">
<div class="signup-hero__badge">
<span class="signup-hero__badge-dot"></span>
<span class="signup-hero__badge-text">회원가입 소개</span>
</div>
<h1 class="signup-hero__title">회원 가입 안내</h1>
<p class="signup-hero__desc">DJ Bank API 개발자 포털에 방문해 주셔서 감사합니다.<br>DJBank API 사용을 위해서는 다음과 같은
이용절차로 진행하여야 합니다.</p>
</div>
</div>
</section>
<!-- Main Content -->
<div class="service-main">
<!-- Sidebar -->
<th:block th:replace="~{fragment/djbank/service_sidebar :: sidebar('guide')}"></th:block>
<!-- Content -->
<section class="service-content">
<!-- Info Box -->
<div class="signup-info-box">
<div class="signup-info-box__icon">
<img th:src="@{/img/icon/icon_check_green.png}" alt="체크 아이콘" />
</div>
<ul class="signup-info-list">
<li>회원은 법인, 개인(개발자)분으로 구분되며, 개발자 포털에서 온라인으로 회원 가입 신청을 합니다.</li>
<li>포털 사용은 운영 담당자의 승인 후 가능합니다.</li>
<li>법인 관리자는 회원 승인 이후, 포털을 실제 사용할 직원(개발자)을 추가 등록해 주시기 바랍니다.</li>
</ul>
</div>
<!-- Vertical Timeline Steps -->
<div class="signup-timeline">
<!-- Step 1 -->
<div class="signup-step">
<div class="signup-step__icon-box one">
<!-- <svg width="40" height="40" viewBox="0 0 32 32" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M14 20C14 19.4477 14.4477 19 15 19H17C17.5523 19 18 19.4477 18 20V24C18 24.5523 17.5523 25 17 25H15C14.4477 25 14 24.5523 14 24V20Z"
stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"
stroke-linejoin="round" />
<path
d="M11 13C11 11.3431 12.3431 10 14 10C15.6569 10 17 11.3431 17 13C17 14.6569 15.6569 16 14 16C12.3431 16 11 14.6569 11 13Z"
stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"
stroke-linejoin="round" />
<path d="M20 21V20C20 18.8954 20.8954 18 22 18C23.1046 18 24 18.8954 24 20V21"
stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"
stroke-linejoin="round" />
<path
d="M19 14C19 12.8954 19.8954 12 21 12C22.1046 12 23 12.8954 23 14C23 15.1046 22.1046 16 21 16C19.8954 16 19 15.1046 19 14Z"
stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"
stroke-linejoin="round" />
</svg> -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-person-add" viewBox="0 0 16 16">
<path
d="M12.5 16a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7m.5-5v1h1a.5.5 0 0 1 0 1h-1v1a.5.5 0 0 1-1 0v-1h-1a.5.5 0 0 1 0-1h1v-1a.5.5 0 0 1 1 0m-2-6a3 3 0 1 1-6 0 3 3 0 0 1 6 0M8 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4" />
<path
d="M8.256 14a4.5 4.5 0 0 1-.229-1.004H3c.001-.246.154-.986.832-1.664C4.484 10.68 5.711 10 8 10q.39 0 .74.025c.226-.341.496-.65.804-.918Q8.844 9.002 8 9c-5 0-6 3-6 4s1 1 1 1z" />
</svg>
</div>
<div class="signup-step__card">
<div class="signup-step__card-num">STEP 01</div>
<div class="signup-step__card-title">회원가입</div>
</div>
</div>
<!-- Step 2 -->
<div class="signup-step">
<div class="signup-step__icon-box two">
<!-- <svg width="40" height="40" viewBox="0 0 32 32" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M14 20C14 19.4477 14.4477 19 15 19H17C17.5523 19 18 19.4477 18 20V24C18 24.5523 17.5523 25 17 25H15C14.4477 25 14 24.5523 14 24V20Z"
stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"
stroke-linejoin="round" />
<path
d="M11 13C11 11.3431 12.3431 10 14 10C15.6569 10 17 11.3431 17 13C17 14.6569 15.6569 16 14 16C12.3431 16 11 14.6569 11 13Z"
stroke="#0049B4" stroke -width="1.6" stroke-linecap="round"
stroke-linejoin="round" />
<path d="M19 16L21 18L25 14" stroke="#0049B4" stroke-width="1.6"
stroke-linecap="round" stroke-linejoin="round" />
</svg> -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-journal-check" viewBox="0 0 16 16">
<path fill-rule="evenodd"
d="M10.854 6.146a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7.5 8.793l2.646-2.647a.5.5 0 0 1 .708 0" />
<path
d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2" />
<path
d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z" />
</svg>
</div>
<div class="signup-step__card">
<div class="signup-step__card-num">STEP 02</div>
<div class="signup-step__card-title">승인</div>
</div>
</div>
<!-- Step 3 -->
<div class="signup-step">
<div class="signup-step__icon-box three">
<!-- <svg width="40" height="40" viewBox="0 0 32 32" fill="none"
xmlns="http://www.w3.org/2000/svg">
<rect x="7" y="7" width="18" height="18" rx="2" stroke="#0049B4" stroke-width="1.6"
stroke-linecap="round" stroke-linejoin="round" />
<path d="M12 12H20" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" />
<path d="M12 16H20" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" />
<path d="M12 20H16" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" />
</svg> -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-code" viewBox="0 0 16 16">
<path
d="M5.854 4.854a.5.5 0 1 0-.708-.708l-3.5 3.5a.5.5 0 0 0 0 .708l3.5 3.5a.5.5 0 0 0 .708-.708L2.707 8zm4.292 0a.5.5 0 0 1 .708-.708l3.5 3.5a.5.5 0 0 1 0 .708l-3.5 3.5a.5.5 0 0 1-.708-.708L13.293 8z" />
</svg>
</div>
<div class="signup-step__card">
<div class="signup-step__card-num">STEP 03</div>
<div class="signup-step__card-title">API/APP 사용 신청</div>
</div>
</div>
<!-- Step 4 -->
<div class="signup-step">
<div class="signup-step__icon-box four">
<!-- <svg width="40" height="40" viewBox="0 0 32 32" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M21 8H24V16" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"
stroke-linejoin="round" />
<path d="M8 8H11V16" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"
stroke-linejoin="round" />
</svg> -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-display" viewBox="0 0 16 16">
<path
d="M0 4s0-2 2-2h12s2 0 2 2v6s0 2-2 2h-4q0 1 .25 1.5H11a.5.5 0 0 1 0 1H5a.5.5 0 0 1 0-1h.75Q6 13 6 12H2s-2 0-2-2zm1.398-.855a.76.76 0 0 0-.254.302A1.5 1.5 0 0 0 1 4.01V10c0 .325.078.502.145.602q.105.156.302.254a1.5 1.5 0 0 0 .538.143L2.01 11H14c.325 0 .502-.078.602-.145a.76.76 0 0 0 .254-.302 1.5 1.5 0 0 0 .143-.538L15 9.99V4c0-.325-.078-.502-.145-.602a.76.76 0 0 0-.302-.254A1.5 1.5 0 0 0 13.99 3H2c-.325 0-.502.078-.602.145" />
</svg>
</div>
<div class="signup-step__card">
<div class="signup-step__card-num">STEP 04</div>
<div class="signup-step__card-title">개발/테스트</div>
</div>
</div>
<!-- Step 5 -->
<div class="signup-step">
<div class="signup-step__icon-box five">
<!-- <svg width="40" height="40" viewBox="0 0 32 32" fill="none"-->
<!-- xmlns="http://www.w3.org/2000/svg">-->
<!-- <rect x="7" y="7" width="18" height="18" rx="2" stroke="#0049B4" stroke-width="1.6"-->
<!-- stroke-linecap="round" stroke-linejoin="round" />-->
<!-- <path d="M12 11H20" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" />-->
<!-- <path d="M12 15L14.5 17.5L20 12" stroke="#0049B4" stroke-width="1.6"-->
<!-- stroke-linecap="round" stroke-linejoin="round" />-->
<!-- </svg>-->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-ui-checks-grid" viewBox="0 0 16 16">
<path d="M2 10h3a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1m9-9h3a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-3a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1m0 9a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-3a1 1 0 0 0-1-1zm0-10a2 2 0 0 0-2 2v3a2 2 0 0 0 2 2h3a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zM2 9a2 2 0 0 0-2 2v3a2 2 0 0 0 2 2h3a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2zm7 2a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2zM0 2a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm5.354.854a.5.5 0 1 0-.708-.708L3 3.793l-.646-.647a.5.5 0 1 0-.708.708l1 1a.5.5 0 0 0 .708 0z"/>
</svg>
</div>
<div class="signup-step__card">
<div class="signup-step__card-num">STEP 05</div>
<div class="signup-step__card-title">운영신청 및 심사</div>
</div>
</div>
<!-- Step 6 -->
<div class="signup-step">
<div class="signup-step__icon-box six">
<!-- <svg width="40" height="40" viewBox="0 0 32 32" fill="none"
xmlns="http://www.w3.org/2000/svg">
<rect x="7" y="9" width="18" height="16" rx="2" stroke="#0049B4" stroke-width="1.6"
stroke-linecap="round" stroke-linejoin="round" />
<path d="M7 13H25" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" />
<path d="M12 7V11" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" />
<path d="M20 7V11" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" />
<path d="M12 17H14" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" />
<path d="M12 21H14" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" />
</svg> -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-airplane" viewBox="0 0 16 16">
<path
d="M6.428 1.151C6.708.591 7.213 0 8 0s1.292.592 1.572 1.151C9.861 1.73 10 2.431 10 3v3.691l5.17 2.585a1.5 1.5 0 0 1 .83 1.342V12a.5.5 0 0 1-.582.493l-5.507-.918-.375 2.253 1.318 1.318A.5.5 0 0 1 10.5 16h-5a.5.5 0 0 1-.354-.854l1.319-1.318-.376-2.253-5.507.918A.5.5 0 0 1 0 12v-1.382a1.5 1.5 0 0 1 .83-1.342L6 6.691V3c0-.568.14-1.271.428-1.849m.894.448C7.111 2.02 7 2.569 7 3v4a.5.5 0 0 1-.276.447l-5.448 2.724a.5.5 0 0 0-.276.447v.792l5.418-.903a.5.5 0 0 1 .575.41l.5 3a.5.5 0 0 1-.14.437L6.708 15h2.586l-.647-.646a.5.5 0 0 1-.14-.436l.5-3a.5.5 0 0 1 .576-.411L15 11.41v-.792a.5.5 0 0 0-.276-.447L9.276 7.447A.5.5 0 0 1 9 7V3c0-.432-.11-.979-.322-1.401C8.458 1.159 8.213 1 8 1s-.458.158-.678.599" />
</svg>
</div>
<div class="signup-step__card">
<div class="signup-step__card-num">STEP 06</div>
<div class="signup-step__card-title">서비스 개시(예약)</div>
</div>
</div>
</div>
<div class="signup-action">
<a th:href="@{/signup}" class="signup-action__btn">회원가입하러 가기</a>
</div>
</section>
</div>
</div>
<!-- Step Process Card -->
<div class="signup-guide__card">
<div class="signup-guide__steps">
<!-- Step 1 -->
<div class="signup-guide__step">
<div class="signup-guide__step-icon">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 20C14 19.4477 14.4477 19 15 19H17C17.5523 19 18 19.4477 18 20V24C18 24.5523 17.5523 25 17 25H15C14.4477 25 14 24.5523 14 24V20Z" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11 13C11 11.3431 12.3431 10 14 10C15.6569 10 17 11.3431 17 13C17 14.6569 15.6569 16 14 16C12.3431 16 11 14.6569 11 13Z" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 21V20C20 18.8954 20.8954 18 22 18C23.1046 18 24 18.8954 24 20V21" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19 14C19 12.8954 19.8954 12 21 12C22.1046 12 23 12.8954 23 14C23 15.1046 22.1046 16 21 16C19.8954 16 19 15.1046 19 14Z" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<div class="signup-guide__step-dot"></div>
<div class="signup-guide__step-label">
<span class="signup-guide__step-num">Step1</span>
<span class="signup-guide__step-text">회원가입</span>
</div>
<div class="signup-guide__step-line"></div>
</div>
<!-- Step 2 -->
<div class="signup-guide__step">
<div class="signup-guide__step-icon">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 20C14 19.4477 14.4477 19 15 19H17C17.5523 19 18 19.4477 18 20V24C18 24.5523 17.5523 25 17 25H15C14.4477 25 14 24.5523 14 24V20Z" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11 13C11 11.3431 12.3431 10 14 10C15.6569 10 17 11.3431 17 13C17 14.6569 15.6569 16 14 16C12.3431 16 11 14.6569 11 13Z" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19 16L21 18L25 14" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<div class="signup-guide__step-dot"></div>
<div class="signup-guide__step-label">
<span class="signup-guide__step-num">Step2</span>
<span class="signup-guide__step-text">승인</span>
</div>
<div class="signup-guide__step-line"></div>
</div>
<!-- Step 3 -->
<div class="signup-guide__step">
<div class="signup-guide__step-icon">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="7" y="7" width="18" height="18" rx="2" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 12H20" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"/>
<path d="M12 16H20" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"/>
<path d="M12 20H16" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"/>
</svg>
</div>
<div class="signup-guide__step-dot"></div>
<div class="signup-guide__step-label">
<span class="signup-guide__step-num">Step3</span>
<span class="signup-guide__step-text">API/APP 사용 신청</span>
</div>
<div class="signup-guide__step-line"></div>
</div>
<!-- Step 4 -->
<div class="signup-guide__step">
<div class="signup-guide__step-icon">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 8H24V16" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 8H11V16" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<div class="signup-guide__step-dot"></div>
<div class="signup-guide__step-label">
<span class="signup-guide__step-num">Step4</span>
<span class="signup-guide__step-text">개발/테스트</span>
</div>
<div class="signup-guide__step-line"></div>
</div>
<!-- Step 5 -->
<div class="signup-guide__step">
<div class="signup-guide__step-icon">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="7" y="7" width="18" height="18" rx="2" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 11H20" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"/>
<path d="M12 15L14.5 17.5L20 12" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<div class="signup-guide__step-dot"></div>
<div class="signup-guide__step-label">
<span class="signup-guide__step-num">Step5</span>
<span class="signup-guide__step-text">운영신청 및 심사</span>
</div>
<div class="signup-guide__step-line"></div>
</div>
<!-- Step 6 -->
<div class="signup-guide__step signup-guide__step--last">
<div class="signup-guide__step-icon">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="7" y="9" width="18" height="16" rx="2" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 13H25" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"/>
<path d="M12 7V11" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"/>
<path d="M20 7V11" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"/>
<path d="M12 17H14" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"/>
<path d="M12 21H14" stroke="#0049B4" stroke-width="1.6" stroke-linecap="round"/>
</svg>
</div>
<div class="signup-guide__step-dot"></div>
<div class="signup-guide__step-label">
<span class="signup-guide__step-num">Step6</span>
<span class="signup-guide__step-text">서비스 개시(예약)</span>
</div>
</div>
</div>
</div>
<!-- Notes Section -->
<div class="signup-guide__notes">
<p class="signup-guide__note">
<span class="signup-guide__note-mark"></span>
<span>회원은 법인, 개인(개발자)분으로 구분되며, 개발자 포털에서 온라인으로 회원가입 신청을 합니다.</span>
</p>
<p class="signup-guide__note">
<span class="signup-guide__note-mark"></span>
<span>포털 사용은 운영 담당자의 승인 후 가능합니다.</span>
</p>
<p class="signup-guide__note">
<span class="signup-guide__note-mark"></span>
<span>법인 관리자는 회원 승인 이후, 포털을 실제 사용할 직원(개발자)을 추가 등록해 주시기 바랍니다.</span>
</p>
</div>
<!-- Action Button -->
<div class="signup-guide__action">
<a th:href="@{/signup}" class="signup-guide__btn">회원가입 하러가기</a>
</div>
</div>
</th:block>
</th:block>
</body>
<th:block layout:fragment="contentScript">
</th:block>
</html>
</html>
@@ -9,153 +9,160 @@
<!-- Section 1: Hero -->
<header class="oauth2-2legged__hero">
<div class="oauth2-2legged__hero-body">
<span class="oauth2-2legged__hero-eyebrow">
<span class="oauth2-2legged__hero-eyebrow-dot"></span>
개발 가이드 · 2-Legged · Client Credentials
</span>
<h1 class="oauth2-2legged__hero-title">OAuth2 개발가이드</h1>
<p class="oauth2-2legged__hero-lead">DJBank Open API를 호출하기 위한 ClientID/Secret 기반 토큰 발급과</p>
<p class="oauth2-2legged__hero-lead">Bearer 인증 호출 방법을 단계별로 설명합니다.</p>
<div class="oauth2-2legged__hero-inner">
<div class="oauth2-2legged__hero-illust" aria-hidden="true">
<svg viewBox="0 0 280 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Server-to-Server Token Flow">
<defs>
<marker id="o2leg-hero-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
<path d="M0,0 L10,5 L0,10 Z" fill="#0049b4"/>
</marker>
</defs>
<rect x="0" y="0" width="280" height="200" rx="20" fill="#FFFFFF"/>
<div class="oauth2-2legged__hero-chips">
<span class="oauth2-2legged__chip oauth2-2legged__chip--primary">Server-to-Server</span>
<span class="oauth2-2legged__chip">cURL 예제</span>
<span class="oauth2-2legged__chip">application/x-www-form</span>
<rect x="40" y="90" width="80" height="50" rx="8" fill="#EDF9FE" stroke="#0049b4"/>
<text x="80" y="120" text-anchor="middle" font-size="11" font-weight="700" fill="#0049b4">Client</text>
<rect x="160" y="90" width="80" height="50" rx="8" fill="#EDF9FE" stroke="#0049b4"/>
<text x="200" y="112" text-anchor="middle" font-size="10" font-weight="700" fill="#0049b4">DJBank</text>
<text x="200" y="126" text-anchor="middle" font-size="10" font-weight="700" fill="#0049b4">Open API</text>
<line x1="120" y1="115" x2="160" y2="115" stroke="#0049b4" stroke-width="2" marker-end="url(#o2leg-hero-arrow)"/>
<g transform="translate(60,30)">
<rect width="160" height="32" rx="6" fill="#1A1A2E"/>
<text x="14" y="21" font-family="'Fira Code', monospace" font-size="12" fill="#00D4FF">Bearer eyJhbG..</text>
</g>
<text x="140" y="170" text-anchor="middle" font-size="11" font-weight="600" fill="#64748B">Server-to-Server Token Flow</text>
</svg>
</div>
</div>
<div class="oauth2-2legged__hero-illust" aria-hidden="true">
<svg viewBox="0 0 280 200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Server-to-Server Token Flow">
<defs>
<marker id="o2leg-hero-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
<path d="M0,0 L10,5 L0,10 Z" fill="#0049b4"/>
</marker>
</defs>
<rect x="0" y="0" width="280" height="200" rx="20" fill="#FFFFFF"/>
<div class="oauth2-2legged__hero-body">
<span class="oauth2-2legged__hero-eyebrow">
<span class="oauth2-2legged__hero-eyebrow-dot"></span>
개발 가이드 · 2-Legged · Client Credentials
</span>
<h1 class="oauth2-2legged__hero-title">OAuth2 개발가이드</h1>
<p class="oauth2-2legged__hero-lead">DJBank Open API를 호출하기 위한 ClientID/Secret 기반 토큰 발급과<br>Bearer 인증 호출 방법을 단계별로 설명합니다.</p>
<rect x="40" y="90" width="80" height="50" rx="8" fill="#EDF9FE" stroke="#0049b4"/>
<text x="80" y="120" text-anchor="middle" font-size="11" font-weight="700" fill="#0049b4">Client</text>
<rect x="160" y="90" width="80" height="50" rx="8" fill="#EDF9FE" stroke="#0049b4"/>
<text x="200" y="112" text-anchor="middle" font-size="10" font-weight="700" fill="#0049b4">DJBank</text>
<text x="200" y="126" text-anchor="middle" font-size="10" font-weight="700" fill="#0049b4">Open API</text>
<line x1="120" y1="115" x2="160" y2="115" stroke="#0049b4" stroke-width="2" marker-end="url(#o2leg-hero-arrow)"/>
<g transform="translate(60,30)">
<rect width="160" height="32" rx="6" fill="#1A1A2E"/>
<text x="14" y="21" font-family="'Fira Code', monospace" font-size="12" fill="#00D4FF">Bearer eyJhbG..</text>
</g>
<text x="140" y="170" text-anchor="middle" font-size="11" font-weight="600" fill="#64748B">Server-to-Server Token Flow</text>
</svg>
<!-- <div class="oauth2-2legged__hero-chips">-->
<!-- <span class="oauth2-2legged__chip oauth2-2legged__chip&#45;&#45;primary">Server-to-Server</span>-->
<!-- <span class="oauth2-2legged__chip">cURL 예제</span>-->
<!-- <span class="oauth2-2legged__chip">application/x-www-form</span>-->
<!-- </div>-->
</div>
</div>
</header>
<!-- Section 2: 사전 준비 -->
<section class="oauth2-2legged__prereq" aria-labelledby="o2leg-prereq-title">
<span class="oauth2-2legged__eyebrow">PREREQUISITE</span>
<h2 class="oauth2-2legged__h2" id="o2leg-prereq-title">시작 전 준비 사항</h2>
<div class="service-main">
<!-- Sidebar -->
<th:block th:replace="~{fragment/djbank/service_sidebar :: sidebar('oauth2')}"></th:block>
<div class="oauth2-2legged__prereq-grid">
<article class="oauth2-2legged__prereq-card">
<span class="oauth2-2legged__prereq-num">1</span>
<div class="oauth2-2legged__prereq-body">
<h3 class="oauth2-2legged__prereq-title">앱 등록</h3>
<p>개발자포털 [내 앱] 메뉴에서 신규</p>
<p>애플리케이션을 등록합니다.</p>
</div>
</article>
<div class="service-content">
<article class="oauth2-2legged__prereq-card">
<span class="oauth2-2legged__prereq-num">2</span>
<div class="oauth2-2legged__prereq-body">
<h3 class="oauth2-2legged__prereq-title">ClientID / Secret 발급</h3>
<p>승인 완료 후 발급된 자격증명을</p>
<p>서버 환경변수에 안전하게 보관.</p>
</div>
</article>
<!-- Section 2: 사전 준비 -->
<section class="oauth2-2legged__prereq" aria-labelledby="o2leg-prereq-title">
<span class="oauth2-2legged__eyebrow">PREREQUISITE</span>
<h2 class="oauth2-2legged__h2" id="o2leg-prereq-title">시작 전 준비 사항</h2>
<article class="oauth2-2legged__prereq-card">
<span class="oauth2-2legged__prereq-num">3</span>
<div class="oauth2-2legged__prereq-body">
<h3 class="oauth2-2legged__prereq-title">Scope 확인</h3>
<p>호출하려는 API에 필요한 scope</p>
<p>권한이 부여됐는지 확인합니다.</p>
</div>
</article>
</div>
</section>
<div class="oauth2-2legged__prereq-grid">
<article class="oauth2-2legged__prereq-card">
<span class="oauth2-2legged__prereq-num">1</span>
<div class="oauth2-2legged__prereq-body">
<h3 class="oauth2-2legged__prereq-title">앱 등록</h3>
<p>개발자포털 [내 앱] 메뉴에서 신규</p>
<p>애플리케이션을 등록합니다.</p>
</div>
</article>
<!-- Section 3: 전체 인증·호출 시퀀스 -->
<section class="oauth2-2legged__sequence" aria-labelledby="o2leg-seq-title">
<span class="oauth2-2legged__eyebrow">SEQUENCE</span>
<h2 class="oauth2-2legged__h2" id="o2leg-seq-title">전체 인증·호출 시퀀스</h2>
<article class="oauth2-2legged__prereq-card">
<span class="oauth2-2legged__prereq-num">2</span>
<div class="oauth2-2legged__prereq-body">
<h3 class="oauth2-2legged__prereq-title">ClientID / Secret 발급</h3>
<p>승인 완료 후 발급된 자격증명을</p>
<p>서버 환경변수에 안전하게 보관.</p>
</div>
</article>
<div class="oauth2-2legged__sequence-diagram">
<svg viewBox="0 0 1120 282" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="OAuth 2.0 2-Legged Sequence">
<defs>
<marker id="o2leg-arrow-primary" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
<path d="M0,0 L10,5 L0,10 Z" fill="#0049b4"/>
</marker>
<marker id="o2leg-arrow-gray" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
<path d="M0,0 L10,5 L0,10 Z" fill="#64748B"/>
</marker>
</defs>
<article class="oauth2-2legged__prereq-card">
<span class="oauth2-2legged__prereq-num">3</span>
<div class="oauth2-2legged__prereq-body">
<h3 class="oauth2-2legged__prereq-title">Scope 확인</h3>
<p>호출하려는 API에 필요한 scope</p>
<p>권한이 부여됐는지 확인합니다.</p>
</div>
</article>
</div>
</section>
<g>
<rect x="120" y="24" width="240" height="48" rx="24" fill="#EDF9FE" stroke="#0049b4"/>
<text x="240" y="54" text-anchor="middle" font-size="14" font-weight="700" fill="#0049b4">Client Application</text>
<line x1="240" y1="72" x2="240" y2="254" stroke="#94A3B8" stroke-dasharray="4 4"/>
</g>
<g>
<rect x="760" y="24" width="240" height="48" rx="24" fill="#FFFFFF" stroke="#0049b4"/>
<text x="880" y="54" text-anchor="middle" font-size="14" font-weight="700" fill="#0049b4">DJBank Open API</text>
<line x1="880" y1="72" x2="880" y2="254" stroke="#94A3B8" stroke-dasharray="4 4"/>
</g>
<!-- Section 3: 전체 인증·호출 시퀀스 -->
<section class="oauth2-2legged__sequence" aria-labelledby="o2leg-seq-title">
<span class="oauth2-2legged__eyebrow">SEQUENCE</span>
<h2 class="oauth2-2legged__h2" id="o2leg-seq-title">전체 인증·호출 시퀀스</h2>
<text x="560" y="102" text-anchor="middle" font-size="12" font-weight="700" fill="#0049b4">① POST /dj/oauth/token</text>
<text x="560" y="118" text-anchor="middle" font-size="11" font-weight="500" fill="#64748B">grant_type=client_credentials, client_id, client_secret, scope</text>
<line x1="240" y1="128" x2="880" y2="128" stroke="#0049b4" stroke-width="2" marker-end="url(#o2leg-arrow-primary)"/>
<div class="oauth2-2legged__sequence-diagram">
<svg viewBox="0 0 1120 282" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="OAuth 2.0 2-Legged Sequence">
<defs>
<marker id="o2leg-arrow-primary" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
<path d="M0,0 L10,5 L0,10 Z" fill="#0049b4"/>
</marker>
<marker id="o2leg-arrow-gray" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
<path d="M0,0 L10,5 L0,10 Z" fill="#64748B"/>
</marker>
</defs>
<text x="560" y="160" text-anchor="middle" font-size="12" font-weight="700" fill="#64748B">② access_token 발급</text>
<line x1="880" y1="170" x2="240" y2="170" stroke="#64748B" stroke-width="2" marker-end="url(#o2leg-arrow-gray)"/>
<text x="560" y="188" text-anchor="middle" font-size="11" font-weight="500" fill="#64748B">{ access_token, token_type:"bearer", expires_in:86400, scope, jti }</text>
<g>
<rect x="120" y="24" width="240" height="48" rx="24" fill="#EDF9FE" stroke="#0049b4"/>
<text x="240" y="54" text-anchor="middle" font-size="14" font-weight="700" fill="#0049b4">Client Application</text>
<line x1="240" y1="72" x2="240" y2="254" stroke="#94A3B8" stroke-dasharray="4 4"/>
</g>
<g>
<rect x="760" y="24" width="240" height="48" rx="24" fill="#FFFFFF" stroke="#0049b4"/>
<text x="880" y="54" text-anchor="middle" font-size="14" font-weight="700" fill="#0049b4">DJBank Open API</text>
<line x1="880" y1="72" x2="880" y2="254" stroke="#94A3B8" stroke-dasharray="4 4"/>
</g>
<text x="560" y="216" text-anchor="middle" font-size="12" font-weight="700" fill="#0049b4">③ GET /api/v1/... · Authorization: Bearer &lt;access_token&gt;</text>
<line x1="240" y1="226" x2="880" y2="226" stroke="#0049b4" stroke-width="2" marker-end="url(#o2leg-arrow-primary)"/>
<text x="560" y="102" text-anchor="middle" font-size="12" font-weight="700" fill="#0049b4">① POST /dj/oauth/token</text>
<text x="560" y="118" text-anchor="middle" font-size="11" font-weight="500" fill="#64748B">grant_type=client_credentials, client_id, client_secret, scope</text>
<line x1="240" y1="128" x2="880" y2="128" stroke="#0049b4" stroke-width="2" marker-end="url(#o2leg-arrow-primary)"/>
<text x="560" y="248" text-anchor="middle" font-size="12" font-weight="700" fill="#64748B">④ 검증 후 API 응답</text>
<line x1="880" y1="254" x2="240" y2="254" stroke="#64748B" stroke-width="2" marker-end="url(#o2leg-arrow-gray)"/>
</svg>
</div>
</section>
<text x="560" y="160" text-anchor="middle" font-size="12" font-weight="700" fill="#64748B">② access_token 발급</text>
<line x1="880" y1="170" x2="240" y2="170" stroke="#64748B" stroke-width="2" marker-end="url(#o2leg-arrow-gray)"/>
<text x="560" y="188" text-anchor="middle" font-size="11" font-weight="500" fill="#64748B">{ access_token, token_type:"bearer", expires_in:86400, scope, jti }</text>
<!-- Section 4: STEP 1 — 액세스 토큰 요청 -->
<section class="oauth2-2legged__step" aria-labelledby="o2leg-step1-title">
<span class="oauth2-2legged__eyebrow">STEP 1</span>
<h2 class="oauth2-2legged__h2" id="o2leg-step1-title">액세스 토큰 요청</h2>
<p class="oauth2-2legged__desc">ClientID/Secret 으로 토큰 엔드포인트에 POST 합니다.</p>
<text x="560" y="216" text-anchor="middle" font-size="12" font-weight="700" fill="#0049b4">③ GET /api/v1/... · Authorization: Bearer &lt;access_token&gt;</text>
<line x1="240" y1="226" x2="880" y2="226" stroke="#0049b4" stroke-width="2" marker-end="url(#o2leg-arrow-primary)"/>
<div class="oauth2-2legged__endpoint-box">
<span class="oauth2-2legged__method">POST</span>
<code class="oauth2-2legged__endpoint-path">https://openapi.djbank.co.kr/dj/oauth/token</code>
<span class="oauth2-2legged__endpoint-content-type">x-www-form-urlencoded</span>
</div>
<text x="560" y="248" text-anchor="middle" font-size="12" font-weight="700" fill="#64748B">④ 검증 후 API 응답</text>
<line x1="880" y1="254" x2="240" y2="254" stroke="#64748B" stroke-width="2" marker-end="url(#o2leg-arrow-gray)"/>
</svg>
</div>
</section>
<div class="oauth2-2legged__step-grid">
<div class="oauth2-2legged__panel">
<h3 class="oauth2-2legged__panel-title">요청 파라미터</h3>
<table class="oauth2-2legged__table">
<thead>
<!-- Section 4: STEP 1 — 액세스 토큰 요청 -->
<section class="oauth2-2legged__step" aria-labelledby="o2leg-step1-title">
<span class="oauth2-2legged__eyebrow">STEP 1</span>
<h2 class="oauth2-2legged__h2" id="o2leg-step1-title">액세스 토큰 요청</h2>
<p class="oauth2-2legged__desc">ClientID/Secret 으로 토큰 엔드포인트에 POST 합니다.</p>
<div class="oauth2-2legged__endpoint-box">
<span class="oauth2-2legged__method">POST</span>
<code class="oauth2-2legged__endpoint-path">https://openapi.djbank.co.kr/dj/oauth/token</code>
<span class="oauth2-2legged__endpoint-content-type">x-www-form-urlencoded</span>
</div>
<div class="oauth2-2legged__step-grid">
<div class="oauth2-2legged__panel">
<h3 class="oauth2-2legged__panel-title">요청 파라미터</h3>
<table class="oauth2-2legged__table">
<thead>
<tr>
<th>PARAMETER</th>
<th>REQ</th>
<th>설명</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
<tr>
<td><code>grant_type</code></td>
<td><span class="oauth2-2legged__req-badge oauth2-2legged__req-badge--required">필수</span></td>
@@ -176,14 +183,14 @@
<td><span class="oauth2-2legged__req-badge oauth2-2legged__req-badge--optional">선택</span></td>
<td>호출 권한 범위 (공백 구분)</td>
</tr>
</tbody>
</table>
<p class="oauth2-2legged__warning">⚠ Content-Type: application/x-www-form-urlencoded 헤더 필수</p>
</div>
</tbody>
</table>
<p class="oauth2-2legged__warning">⚠ Content-Type: application/x-www-form-urlencoded 헤더 필수</p>
</div>
<div class="oauth2-2legged__code-panel">
<span class="oauth2-2legged__code-tag">cURL</span>
<pre class="oauth2-2legged__code-block"><span class="o2leg-cm"># 액세스 토큰 발급</span>
<div class="oauth2-2legged__code-panel">
<span class="oauth2-2legged__code-tag">cURL</span>
<pre class="oauth2-2legged__code-block"><span class="o2leg-cm"># 액세스 토큰 발급</span>
curl -X <span class="o2leg-y">POST</span> <span class="o2leg-c">'https://openapi.djbank.co.kr/dj/oauth/token'</span> \
-H <span class="o2leg-c">'Content-Type: application/x-www-form-urlencoded'</span> \
-d <span class="o2leg-c">'grant_type=client_credentials'</span> \
@@ -192,20 +199,20 @@ curl -X <span class="o2leg-y">POST</span> <span class="o2leg-c">'https://openapi
-d <span class="o2leg-c">'scope=read.accounts'</span>
<span class="o2leg-g"># 응답: 200 OK + JSON</span></pre>
</div>
</div>
</div>
</section>
</section>
<!-- Section 5: STEP 2 — 액세스 토큰 응답 -->
<section class="oauth2-2legged__step" aria-labelledby="o2leg-step2-title">
<span class="oauth2-2legged__eyebrow">STEP 2</span>
<h2 class="oauth2-2legged__h2" id="o2leg-step2-title">액세스 토큰 응답</h2>
<p class="oauth2-2legged__desc">정상 발급 시 200 OK 와 함께 다음 JSON 을 반환합니다.</p>
<!-- Section 5: STEP 2 — 액세스 토큰 응답 -->
<section class="oauth2-2legged__step" aria-labelledby="o2leg-step2-title">
<span class="oauth2-2legged__eyebrow">STEP 2</span>
<h2 class="oauth2-2legged__h2" id="o2leg-step2-title">액세스 토큰 응답</h2>
<p class="oauth2-2legged__desc">정상 발급 시 200 OK 와 함께 다음 JSON 을 반환합니다.</p>
<div class="oauth2-2legged__step-grid">
<div class="oauth2-2legged__code-panel">
<span class="oauth2-2legged__code-tag oauth2-2legged__code-tag--ok">200 OK · JSON</span>
<pre class="oauth2-2legged__code-block">{
<div class="oauth2-2legged__step-grid">
<div class="oauth2-2legged__code-panel">
<span class="oauth2-2legged__code-tag oauth2-2legged__code-tag--ok">200 OK · JSON</span>
<pre class="oauth2-2legged__code-block">{
<span class="o2leg-c">"access_token"</span>: <span class="o2leg-y">"eyJhbGciOiJSUzI1NiJ9..."</span>,
<span class="o2leg-c">"token_type"</span>: <span class="o2leg-y">"bearer"</span>,
<span class="o2leg-c">"expires_in"</span>: <span class="o2leg-p">86400</span>,
@@ -214,19 +221,19 @@ curl -X <span class="o2leg-y">POST</span> <span class="o2leg-c">'https://openapi
}
<span class="o2leg-g"># 응답 본문은 캐싱하여 expires_in 동안 재사용 가능</span></pre>
</div>
</div>
<div class="oauth2-2legged__panel">
<h3 class="oauth2-2legged__panel-title">응답 필드</h3>
<table class="oauth2-2legged__table">
<thead>
<div class="oauth2-2legged__panel">
<h3 class="oauth2-2legged__panel-title">응답 필드</h3>
<table class="oauth2-2legged__table">
<thead>
<tr>
<th>FIELD</th>
<th>TYPE</th>
<th>설명</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
<tr>
<td><code class="oauth2-2legged__field-name">access_token</code></td>
<td>string</td>
@@ -252,38 +259,38 @@ curl -X <span class="o2leg-y">POST</span> <span class="o2leg-c">'https://openapi
<td>string</td>
<td>토큰 고유 ID (감사/취소용)</td>
</tr>
</tbody>
</table>
</tbody>
</table>
</div>
</div>
</div>
</section>
</section>
<!-- Section 6: STEP 3 — API 호출 -->
<section class="oauth2-2legged__step" aria-labelledby="o2leg-step3-title">
<span class="oauth2-2legged__eyebrow">STEP 3</span>
<h2 class="oauth2-2legged__h2" id="o2leg-step3-title">발급 토큰으로 API 호출</h2>
<p class="oauth2-2legged__desc">Authorization 헤더에 Bearer 토큰을 실어 보호 자원 API 를 호출합니다.</p>
<!-- Section 6: STEP 3 — API 호출 -->
<section class="oauth2-2legged__step" aria-labelledby="o2leg-step3-title">
<span class="oauth2-2legged__eyebrow">STEP 3</span>
<h2 class="oauth2-2legged__h2" id="o2leg-step3-title">발급 토큰으로 API 호출</h2>
<p class="oauth2-2legged__desc">Authorization 헤더에 Bearer 토큰을 실어 보호 자원 API 를 호출합니다.</p>
<div class="oauth2-2legged__step-grid">
<div class="oauth2-2legged__panel">
<h3 class="oauth2-2legged__panel-title">필수 헤더</h3>
<div class="oauth2-2legged__header-box">
<code class="oauth2-2legged__header-key">Authorization:</code>
<code class="oauth2-2legged__header-value">Bearer eyJhbGciOiJSUzI1NiJ9...</code>
<div class="oauth2-2legged__step-grid">
<div class="oauth2-2legged__panel">
<h3 class="oauth2-2legged__panel-title">필수 헤더</h3>
<div class="oauth2-2legged__header-box">
<code class="oauth2-2legged__header-key">Authorization:</code>
<code class="oauth2-2legged__header-value">Bearer eyJhbGciOiJSUzI1NiJ9...</code>
</div>
<h4 class="oauth2-2legged__panel-subtitle">토큰 재사용 가이드</h4>
<ul class="oauth2-2legged__tips">
<li>동일 토큰은 expires_in(기본 86400초) 동안 재사용</li>
<li>만료 임박 시 재발급 후 교체 (예: TTL의 80% 시점)</li>
<li>매 호출마다 토큰을 새로 발급하지 마세요</li>
<li>권한이 다른 API 는 scope 별로 토큰을 분리 발급</li>
</ul>
</div>
<h4 class="oauth2-2legged__panel-subtitle">토큰 재사용 가이드</h4>
<ul class="oauth2-2legged__tips">
<li>동일 토큰은 expires_in(기본 86400초) 동안 재사용</li>
<li>만료 임박 시 재발급 후 교체 (예: TTL의 80% 시점)</li>
<li>매 호출마다 토큰을 새로 발급하지 마세요</li>
<li>권한이 다른 API 는 scope 별로 토큰을 분리 발급</li>
</ul>
</div>
<div class="oauth2-2legged__code-panel">
<span class="oauth2-2legged__code-tag">cURL</span>
<pre class="oauth2-2legged__code-block"><span class="o2leg-cm"># 보호 자원 API 호출</span>
<div class="oauth2-2legged__code-panel">
<span class="oauth2-2legged__code-tag">cURL</span>
<pre class="oauth2-2legged__code-block"><span class="o2leg-cm"># 보호 자원 API 호출</span>
curl -X <span class="o2leg-y">GET</span> \
<span class="o2leg-c">'https://openapi.djbank.co.kr/api/v1/accounts'</span> \
-H <span class="o2leg-c">'Authorization: Bearer eyJhbGciOiJSUzI..'</span> \
@@ -292,26 +299,26 @@ curl -X <span class="o2leg-y">GET</span> \
<span class="o2leg-g"># 응답</span>
HTTP/1.1 <span class="o2leg-g">200 OK</span>
{ <span class="o2leg-c">"accounts"</span>: [ ... ] }</pre>
</div>
</div>
</div>
</section>
</section>
<!-- Section 7: 대표 에러 응답 (표) -->
<section class="oauth2-2legged__errors" aria-labelledby="o2leg-errors-title">
<span class="oauth2-2legged__eyebrow">ERROR CODES</span>
<h2 class="oauth2-2legged__h2" id="o2leg-errors-title">대표 에러 응답</h2>
<!-- Section 7: 대표 에러 응답 (표) -->
<section class="oauth2-2legged__errors" aria-labelledby="o2leg-errors-title">
<span class="oauth2-2legged__eyebrow">ERROR CODES</span>
<h2 class="oauth2-2legged__h2" id="o2leg-errors-title">대표 에러 응답</h2>
<div class="oauth2-2legged__panel">
<table class="oauth2-2legged__table oauth2-2legged__table--errors">
<thead>
<div class="oauth2-2legged__panel">
<table class="oauth2-2legged__table oauth2-2legged__table--errors">
<thead>
<tr>
<th>HTTP</th>
<th>ERROR CODE</th>
<th>의미</th>
<th>해결 가이드</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
<tr>
<td><span class="oauth2-2legged__status-badge oauth2-2legged__status-badge--400">400</span></td>
<td><code>invalid_request</code></td>
@@ -336,21 +343,21 @@ HTTP/1.1 <span class="o2leg-g">200 OK</span>
<td>scope 권한 부족</td>
<td>필요 scope 추가 신청 후 재발급</td>
</tr>
</tbody>
</table>
</div>
</section>
</tbody>
</table>
</div>
</section>
<!-- Section 8: 에러 응답 예시 (단일 사례) -->
<section class="oauth2-2legged__error-example" aria-labelledby="o2leg-err-ex-title">
<span class="oauth2-2legged__eyebrow">ERROR RESPONSE</span>
<h2 class="oauth2-2legged__h2" id="o2leg-err-ex-title">에러 응답 예시</h2>
<p class="oauth2-2legged__desc">자격증명 불일치 시 401 Unauthorized 와 함께 다음 JSON 을 반환합니다.</p>
<!-- Section 8: 에러 응답 예시 (단일 사례) -->
<section class="oauth2-2legged__error-example" aria-labelledby="o2leg-err-ex-title">
<span class="oauth2-2legged__eyebrow">ERROR RESPONSE</span>
<h2 class="oauth2-2legged__h2" id="o2leg-err-ex-title">에러 응답 예시</h2>
<p class="oauth2-2legged__desc">자격증명 불일치 시 401 Unauthorized 와 함께 다음 JSON 을 반환합니다.</p>
<div class="oauth2-2legged__step-grid">
<div class="oauth2-2legged__code-panel oauth2-2legged__code-panel--error">
<span class="oauth2-2legged__code-tag oauth2-2legged__code-tag--error">401 Unauthorized · JSON</span>
<pre class="oauth2-2legged__code-block">{
<div class="oauth2-2legged__step-grid">
<div class="oauth2-2legged__code-panel oauth2-2legged__code-panel--error">
<span class="oauth2-2legged__code-tag oauth2-2legged__code-tag--error">401 Unauthorized · JSON</span>
<pre class="oauth2-2legged__code-block">{
<span class="o2leg-c">"error"</span>: <span class="o2leg-y">"invalid_client"</span>,
<span class="o2leg-c">"error_description"</span>:
<span class="o2leg-y">"Client authentication failed"</span>,
@@ -359,19 +366,19 @@ HTTP/1.1 <span class="o2leg-g">200 OK</span>
}
<span class="o2leg-g"># 처리: ClientID·Secret 확인 후 재시도</span></pre>
</div>
</div>
<div class="oauth2-2legged__panel">
<h3 class="oauth2-2legged__panel-title">응답 필드</h3>
<table class="oauth2-2legged__table">
<thead>
<div class="oauth2-2legged__panel">
<h3 class="oauth2-2legged__panel-title">응답 필드</h3>
<table class="oauth2-2legged__table">
<thead>
<tr>
<th>FIELD</th>
<th>TYPE</th>
<th>설명</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
<tr>
<td><code class="oauth2-2legged__field-name">error</code></td>
<td>string</td>
@@ -392,25 +399,27 @@ HTTP/1.1 <span class="o2leg-g">200 OK</span>
<td>string</td>
<td>에러 발생 시각 (ISO 8601)</td>
</tr>
</tbody>
</table>
<p class="oauth2-2legged__error-note">⚠ error 코드는 RFC 6749 표준 코드 또는 DJBank 확장 코드</p>
</tbody>
</table>
<p class="oauth2-2legged__error-note">⚠ error 코드는 RFC 6749 표준 코드 또는 DJBank 확장 코드</p>
</div>
</div>
</div>
</section>
</section>
<!-- Section 9: API 목록 CTA -->
<a class="oauth2-2legged__cta" th:href="@{/apis}">
<div class="oauth2-2legged__cta-body">
<span class="oauth2-2legged__cta-eyebrow">EXPLORE</span>
<h2 class="oauth2-2legged__cta-title">API 목록 보러가기</h2>
<p class="oauth2-2legged__cta-desc">사용 가능한 DJBank Open API 카탈로그를 확인하세요.</p>
<span class="oauth2-2legged__cta-button">API 목록 →</span>
</div>
<span class="oauth2-2legged__cta-deco oauth2-2legged__cta-deco--lg" aria-hidden="true"></span>
<span class="oauth2-2legged__cta-deco oauth2-2legged__cta-deco--sm" aria-hidden="true"></span>
</a>
<!-- Section 9: API 목록 CTA -->
<a class="oauth2-2legged__cta" th:href="@{/apis}">
<div class="oauth2-2legged__cta-body">
<span class="oauth2-2legged__cta-eyebrow">EXPLORE</span>
<h2 class="oauth2-2legged__cta-title">API 목록 보러가기</h2>
<p class="oauth2-2legged__cta-desc">사용 가능한 DJBank Open API 카탈로그를 확인하세요.</p>
<span class="oauth2-2legged__cta-button">API 목록 →</span>
</div>
<span class="oauth2-2legged__cta-deco oauth2-2legged__cta-deco--lg" aria-hidden="true"></span>
<span class="oauth2-2legged__cta-deco oauth2-2legged__cta-deco--sm" aria-hidden="true"></span>
</a>
</div>
</div>
</section>
</th:block>
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<!-- Service Left Sidebar Fragment -->
<aside class="service-sidebar" th:fragment="sidebar(activeMenu)">
<nav class="service-nav">
<a th:href="@{/service/intro}"
th:classappend="${activeMenu == 'intro'} ? 'service-nav__item--active' : ''"
class="service-nav__item">API 포탈 소개</a>
<a th:href="@{/service/guide}"
th:classappend="${activeMenu == 'guide'} ? 'service-nav__item--active' : ''"
class="service-nav__item">회원가입 안내</a>
<a th:href="@{/service/oauth2-guide}"
th:classappend="${activeMenu == 'oauth2'} ? 'service-nav__item--active' : ''"
class="service-nav__item">OAuth2 개발가이드</a>
</nav>
</aside>
</body>
</html>