From 822122c5a20c0414aeafa05e79d7b2b452369771 Mon Sep 17 00:00:00 2001 From: Sin-Kang Date: Wed, 3 Jun 2026 21:49:34 +0900 Subject: [PATCH] docs(tutorial): show the real dev workflow (IntelliJ Run + admin-ui console) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reframes Steps 4–6 around how you actually develop, while keeping the curl/API path: - Step 4 "Run the app": IntelliJ (Run MyappApplication, with the Gradle-reload tip) or `./gradlew bootRun` — content tabs. - Step 5 "Open the admin console": clone + `npm run dev` the admin-ui, log in in the browser; the curl login stays under a "prefer the API" note. - Step 6: content tabs — "In the admin console (clicks)" alongside "Via the API (curl)". Neither replaces the other. en/ko. mkdocs build --strict passes. --- docs/getting-started/tutorial.ko.md | 121 ++++++++++++++++---------- docs/getting-started/tutorial.md | 127 +++++++++++++++++----------- 2 files changed, 153 insertions(+), 95 deletions(-) diff --git a/docs/getting-started/tutorial.ko.md b/docs/getting-started/tutorial.ko.md index 66acf9b..1b5e39a 100644 --- a/docs/getting-started/tutorial.ko.md +++ b/docs/getting-started/tutorial.ko.md @@ -157,11 +157,24 @@ devslab: --- -## 4단계 — 실행 +## 4단계 — 앱 실행 -```bash -./gradlew bootRun -``` +평소 개발하던 방식으로 실행하세요: + +=== "IntelliJ IDEA (일반적)" + + `myapp` 폴더를 Gradle 프로젝트로 열고 import가 끝나면 `MyappApplication` 의 **Run**(▶) 실행. + + !!! tip "kit 추가/버전 변경 직후 Run이 실패하면" + `ClassNotFoundException: kr.devslab.kit.*` 는 IntelliJ 프로젝트 모델이 옛것이라는 뜻 — + **Gradle 리로드**(Gradle 툴 윈도우 → ↻ *Reload*)로 새 jar를 잡게 한 뒤 다시 Run. + (Gradle `bootRun` 은 매번 새로 해소해서 항상 됨.) + +=== "터미널" + + ```bash + ./gradlew bootRun + ``` 첫 실행 시 kit은: @@ -171,66 +184,80 @@ devslab: 3. 테넌트, 모든 `admin.*` 권한을 가진 `PLATFORM_ADMIN` 역할, `admin` 사용자를 **부트스트랩**, 4. `/admin/api/v1/**` 에 **관리자 REST API**, `/swagger-ui.html` 에 **Swagger UI** 제공. -이걸 띄워둔 채로 두 번째 터미널을 열어 다음 단계를 진행하세요. +이제 앱이 `http://localhost:8080` 에서 동작합니다. --- -## 5단계 — 로그인 +## 5단계 — admin 콘솔 띄우기 -모든 관리자 호출엔 토큰이 필요합니다. 부트스트랩 관리자로 로그인: +실무에서는 플랫폼을 curl이 아니라 **웹 콘솔**로 관리합니다. (앱과 별도 폴더에) 클론해서 실행: ```bash -curl -s localhost:8080/admin/api/v1/auth/login \ - -H 'Content-Type: application/json' \ - -d '{"tenantId":"default","loginId":"admin","rawPassword":"admin"}' +git clone https://github.com/devslab-kr/devslab-kit-admin-ui.git +cd devslab-kit-admin-ui +npm install +npm run dev ``` -응답에 JWT가 들어있습니다. 다음 명령에서 재사용하도록 셸 변수에 담으세요: +**http://localhost:5173** 을 엽니다 — dev 서버가 `/admin/api` 를 `:8080` 의 앱으로 프록시합니다. +부트스트랩 관리자로 로그인: 테넌트 `default`, 로그인 `admin`, 비밀번호 `admin`. 이제 다음 +단계들은 몇 번의 클릭으로 끝납니다 — [Admin 콘솔 가이드](../guides/admin-console.md)가 모든 +화면을 안내합니다. -```bash -TOKEN=$(curl -s localhost:8080/admin/api/v1/auth/login \ - -H 'Content-Type: application/json' \ - -d '{"tenantId":"default","loginId":"admin","rawPassword":"admin"}' | sed -E 's/.*"token":"([^"]+)".*/\1/') -echo "$TOKEN" -``` - -!!! tip "UI가 편하시면" - [admin 콘솔](https://github.com/devslab-kr/devslab-kit-admin-ui)을 `http://localhost:8080` - 에 연결하면 6단계를 curl 대신 클릭으로 할 수 있습니다. +!!! note "API / 스크립트가 편하면" + 전부 REST로도 됩니다. 로그인해 JWT를 받아 `$TOKEN` 으로 재사용: + ```bash + TOKEN=$(curl -s localhost:8080/admin/api/v1/auth/login \ + -H 'Content-Type: application/json' \ + -d '{"tenantId":"default","loginId":"admin","rawPassword":"admin"}' | sed -E 's/.*"token":"([^"]+)".*/\1/') + echo "$TOKEN" + ``` --- ## 6단계 — 권한·역할·사용자 만들기 **권한**은 문자열 코드(`resource.action`), **역할**은 권한 묶음, **사용자**는 역할을 가집니다. -새 사용자에게 "책 읽기" 권한을 줘봅시다. +새 사용자에게 "책 읽기" 권한을 줘봅시다 — 편한 방식으로: -```bash -# 1) 권한 생성 -> 응답의 "id" 기록 -curl -s -X POST localhost:8080/admin/api/v1/permissions \ - -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ - -d '{"code":"book.read","description":"책 읽기"}' - -# 2) 역할 생성 -> "id" 기록 -curl -s -X POST localhost:8080/admin/api/v1/roles \ - -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ - -d '{"tenantId":"default","code":"LIBRARIAN","name":"사서"}' - -# 3) 역할에 권한 부여 (1·2의 id 사용) -curl -s -X POST "localhost:8080/admin/api/v1/roles//permissions/" \ - -H "Authorization: Bearer $TOKEN" - -# 4) 사용자 생성 -curl -s -X POST localhost:8080/admin/api/v1/users \ - -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ - -d '{"tenantId":"default","loginId":"alice","rawPassword":"alice-password","email":"alice@example.com"}' - -# 5) 사용자에게 역할 할당 (2·4의 id 사용) -curl -s -X POST "localhost:8080/admin/api/v1/roles//users/?tenantId=default" \ - -H "Authorization: Bearer $TOKEN" -``` +=== "admin 콘솔에서 (클릭)" + + 1. **Permissions → Create** — resource `book`, action `read`; 코드가 `book.read` 로 미리보기. **Create**. + 2. **Roles → Create** — code `LIBRARIAN`, 이름 `사서`. 그 행의 **권한 관리**(열쇠 아이콘) → `book.read` 를 *할당* 으로 옮기고 **저장**. + 3. **Users → Create** — 로그인 `alice`, 비밀번호. 그 행의 **역할 관리**(신분증 아이콘) → `LIBRARIAN` 추가 → **저장**. + + 각 화면·버튼은 [Admin 콘솔 가이드](../guides/admin-console.md)에 자세히 있습니다. + +=== "API로 (curl)" + + 5단계의 `$TOKEN` 사용. + + ```bash + # 1) 권한 생성 -> 응답의 "id" 기록 + curl -s -X POST localhost:8080/admin/api/v1/permissions \ + -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ + -d '{"code":"book.read","description":"책 읽기"}' + + # 2) 역할 생성 -> "id" 기록 + curl -s -X POST localhost:8080/admin/api/v1/roles \ + -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ + -d '{"tenantId":"default","code":"LIBRARIAN","name":"사서"}' + + # 3) 역할에 권한 부여 (1·2의 id 사용) + curl -s -X POST "localhost:8080/admin/api/v1/roles//permissions/" \ + -H "Authorization: Bearer $TOKEN" + + # 4) 사용자 생성 + curl -s -X POST localhost:8080/admin/api/v1/users \ + -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ + -d '{"tenantId":"default","loginId":"alice","rawPassword":"alice-password","email":"alice@example.com"}' + + # 5) 사용자에게 역할 할당 (2·4의 id 사용) + curl -s -X POST "localhost:8080/admin/api/v1/roles//users/?tenantId=default" \ + -H "Authorization: Bearer $TOKEN" + ``` -이제 `alice`로 로그인(5단계, alice 자격증명)하면 `book.read` 권한을 가집니다. +이제 `alice`로 로그인(콘솔 또는 API)하면 `book.read` 권한을 가집니다. --- diff --git a/docs/getting-started/tutorial.md b/docs/getting-started/tutorial.md index 92a5002..58aa52b 100644 --- a/docs/getting-started/tutorial.md +++ b/docs/getting-started/tutorial.md @@ -161,11 +161,26 @@ devslab: --- -## Step 4 — Run it +## Step 4 — Run the app -```bash -./gradlew bootRun -``` +Run it the way you normally develop: + +=== "IntelliJ IDEA (typical)" + + Open the `myapp` folder as a Gradle project, let the import finish, then **Run** + `MyappApplication` (the green ▶ by `main`). + + !!! tip "If Run fails right after adding/bumping the kit" + A `ClassNotFoundException: kr.devslab.kit.*` means IntelliJ's project model is + stale — **reload Gradle** (Gradle tool window → the ↻ *Reload* button) so it + picks up the new jars, then Run again. (Gradle `bootRun` always works because it + resolves fresh.) + +=== "Terminal" + + ```bash + ./gradlew bootRun + ``` On first start the kit: @@ -177,66 +192,82 @@ On first start the kit: 4. serves the **admin REST API** at `/admin/api/v1/**` and **Swagger UI** at `/swagger-ui.html`. -Leave it running and open a second terminal for the next steps. +The app is now listening on `http://localhost:8080`. --- -## Step 5 — Log in +## Step 5 — Open the admin console -Every admin call needs a token. Log in as the bootstrap admin: +Day to day you manage the platform from the **web console**, not curl. Clone and run it +(in its own folder, alongside your app): ```bash -curl -s localhost:8080/admin/api/v1/auth/login \ - -H 'Content-Type: application/json' \ - -d '{"tenantId":"default","loginId":"admin","rawPassword":"admin"}' +git clone https://github.com/devslab-kr/devslab-kit-admin-ui.git +cd devslab-kit-admin-ui +npm install +npm run dev ``` -The response contains a JWT — copy it into a shell variable so the next commands can reuse it: +Open **http://localhost:5173** — the dev server proxies `/admin/api` to your app on +`:8080`. Sign in with the bootstrap admin: tenant `default`, login `admin`, password +`admin`. From here everything in the next steps is a few clicks — the +[Admin Console guide](../guides/admin-console.md) walks through every screen. -```bash -TOKEN=$(curl -s localhost:8080/admin/api/v1/auth/login \ - -H 'Content-Type: application/json' \ - -d '{"tenantId":"default","loginId":"admin","rawPassword":"admin"}' | sed -E 's/.*"token":"([^"]+)".*/\1/') -echo "$TOKEN" -``` - -!!! tip "Prefer a UI?" - Point the [admin console](https://github.com/devslab-kr/devslab-kit-admin-ui) at - `http://localhost:8080` and do all of Step 6 by clicking instead of curl. +!!! note "Prefer the API / scripting it?" + Everything also works over REST. Log in to get a JWT and reuse it as `$TOKEN`: + ```bash + TOKEN=$(curl -s localhost:8080/admin/api/v1/auth/login \ + -H 'Content-Type: application/json' \ + -d '{"tenantId":"default","loginId":"admin","rawPassword":"admin"}' | sed -E 's/.*"token":"([^"]+)".*/\1/') + echo "$TOKEN" + ``` --- ## Step 6 — Create a permission, a role, and a user -A **permission** is a string code (`resource.action`). A **role** is a bundle of -permissions. A **user** holds roles. Let's give a new user the ability to read books. +A **permission** is a string code (`resource.action`); a **role** bundles permissions; a +**user** holds roles. Let's give a new user the ability to read books — do it whichever way +suits you: -```bash -# 1) create a permission -> note its "id" in the response -curl -s -X POST localhost:8080/admin/api/v1/permissions \ - -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ - -d '{"code":"book.read","description":"Read books"}' - -# 2) create a role -> note its "id" -curl -s -X POST localhost:8080/admin/api/v1/roles \ - -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ - -d '{"tenantId":"default","code":"LIBRARIAN","name":"Librarian"}' - -# 3) grant the permission to the role (use the ids from steps 1 & 2) -curl -s -X POST "localhost:8080/admin/api/v1/roles//permissions/" \ - -H "Authorization: Bearer $TOKEN" - -# 4) create a user -curl -s -X POST localhost:8080/admin/api/v1/users \ - -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ - -d '{"tenantId":"default","loginId":"alice","rawPassword":"alice-password","email":"alice@example.com"}' - -# 5) assign the role to the user (ids from steps 2 & 4) -curl -s -X POST "localhost:8080/admin/api/v1/roles//users/?tenantId=default" \ - -H "Authorization: Bearer $TOKEN" -``` +=== "In the admin console (clicks)" + + 1. **Permissions → Create** — resource `book`, action `read`; the code previews as `book.read`. **Create**. + 2. **Roles → Create** — code `LIBRARIAN`, name `Librarian`. Then on its row click **Manage permissions** (key icon) and move `book.read` to *Assigned* → **Save**. + 3. **Users → Create** — login `alice`, a password. Then on her row click **Manage roles** (id-card icon) and add `LIBRARIAN` → **Save**. + + Every screen/button is detailed in the [Admin Console guide](../guides/admin-console.md). + +=== "Via the API (curl)" + + Uses the `$TOKEN` from Step 5. + + ```bash + # 1) create a permission -> note its "id" in the response + curl -s -X POST localhost:8080/admin/api/v1/permissions \ + -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ + -d '{"code":"book.read","description":"Read books"}' + + # 2) create a role -> note its "id" + curl -s -X POST localhost:8080/admin/api/v1/roles \ + -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ + -d '{"tenantId":"default","code":"LIBRARIAN","name":"Librarian"}' + + # 3) grant the permission to the role (use the ids from steps 1 & 2) + curl -s -X POST "localhost:8080/admin/api/v1/roles//permissions/" \ + -H "Authorization: Bearer $TOKEN" + + # 4) create a user + curl -s -X POST localhost:8080/admin/api/v1/users \ + -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ + -d '{"tenantId":"default","loginId":"alice","rawPassword":"alice-password","email":"alice@example.com"}' + + # 5) assign the role to the user (ids from steps 2 & 4) + curl -s -X POST "localhost:8080/admin/api/v1/roles//users/?tenantId=default" \ + -H "Authorization: Bearer $TOKEN" + ``` -Now `alice` can log in (Step 5 with her credentials) and holds `book.read`. +Now `alice` can sign in (console or API) and holds `book.read`. ---