오랜만에 커밋

This commit is contained in:
2026-05-04 10:30:04 +09:00
parent c35c042afa
commit 722d5dbfaf
56 changed files with 2288 additions and 11 deletions
-1
View File
@@ -1 +0,0 @@
[[Aider 사용기]]
@@ -0,0 +1,9 @@
[[Gitea & Quartz 배포 자동화 트러블슈팅]]
[[gitea, qurtz 설치]]
[[kui-vault]]
[[WebHook]]
@@ -1,5 +0,0 @@
## Language
[[파이썬(python) 통찰]]
## Tech
[[Functional Domain Modeling]]
+2
View File
@@ -0,0 +1,2 @@
[[전표처리]]
+4
View File
@@ -0,0 +1,4 @@
### Coding Agent
[[Aider 사용기]]
[[Aider 프로젝트 생성]]
+2
View File
@@ -0,0 +1,2 @@
[[Functional Domain Modeling]]
+2
View File
@@ -0,0 +1,2 @@
[[파이썬(python) 통찰]]
+5
View File
@@ -0,0 +1,5 @@
[[VPN으로 외부 DB에 접근]]
[[Pc끼리 Lan선으로 Direct 연결]]
[[RS-232와 Serial 통신]]
+2
View File
@@ -0,0 +1,2 @@
### Server
[[어플리케이션(서비스) 실행 시 계정 구분하는 이유]]
+22
View File
@@ -0,0 +1,22 @@
---
id: "Aider 단축키 20260413"
created: "2026-04-13 13:35"
tags:
---
| **명령어** | **설명** | **비고** |
| --------------- | --------------------------------- | ----------------------------------- |
| **/undo** | **AI가 방금 수정한 코드를 취소하고 직전 상태로 복구** | 가장 자주 쓰임 |
| **/add <파일>** | 수정하거나 참고할 파일을 채팅창에 추가 | 파일명 일부만 쳐도 자동완성 |
| **/drop <파일>** | 채팅창에서 특정 파일 제외 | 실제 파일이 삭제되지는 않음 |
| **/ls** | 현재 채팅창에 포함된 파일 목록 확인 | |
| **/diff** | 마지막 수정 사항의 변경 전/후 차이점 표시 | |
| **/test <명령어>** | 테스트 명령을 실행하고 실패 시 AI가 자동 수정 | 예: `/test pytest` |
| **/model <모델>** | 사용 중인 AI 모델을 즉시 변경 | 예: `/model gemini/gemini-2.5-flash` |
| **/tokens** | 현재 세션의 토큰 사용량과 비용 정보 확인 | |
| **/run <명령어>** | 에이더를 나가지 않고 터미널 명령어 실행 | 예: `/run ls -al` |
| **/exit** | 에이더 종료 | `/quit`과 동일 |
| **/help** | 모든 명령어 목록과 상세 도움말 확인 | |
| **명령어** | **용도** | **특징** |
| **/ask <질문>** | 코드에 대해 질문하기 | 코드를 **직접 수정하지 않고** 설명만 해줍니다. |
| **/chat <메시지>** | 일반적인 대화/토론 | 파일 수정 없이 구현 방법이나 구조에 대해 논의할 때 씁니다. |
| **/code <명령>** | 코드 수정 요청 | 기본 모드입니다. 지시한 대로 파일을 직접 수정합니다. |
+689
View File
@@ -0,0 +1,689 @@
---
id: "Aider 최초 사용 20260413"
created: "2026-04-13 14:01"
tags:
---
Gemini를 채찍질해서 아래의 명세를 가지는 VaultKeeper 어플리케이션 구상을 함.
( kui-veil 서버의 auth 관리 어플리케이션임 )
```markdown
## 🏗️ VaultKeeper 프로젝트 상세 설계도 (Ver 2.0)
### 1. 개요
- **목적**: Nginx의 `.htpasswd` 파일을 웹 GUI를 통해 관리하는 초경량 도구.
- **타겟 환경**: Google Cloud e2-micro (저사양 서버).
- **주요 언어**: **Go** (백엔드), **Vanilla JS** (프론트엔드).
### 2. 보안 전략 (핵심)
- **인증 분리**: 백엔드 자체에 로그인 로직을 구현하지 않고, Nginx의 `auth_basic` 모듈에 인증을 위임함.
- **접근 권한**: 서버 관리자가 터미널에서 직접 생성한 계정으로만 웹 UI에 접근 가능.
- **입력값 검증**: `os/exec` 실행 시 쉘 인젝션을 방지하기 위해 사용자 이름에 특수문자 입력을 제한함.
### 3. 구성 요소
- **Backend (`main.go`)**:
- 환경 변수 `HTPASSWD_PATH`를 통해 대상 파일 경로 지정.
- 표준 패키지 `net/http`를 사용하여 메모리 점유 최소화.
- `htpasswd` 시스템 명령어를 서브프로세스로 호출하여 계정 추가/삭제.
- **Frontend (`index.html`)**:
- 단일 파일 SPA 구조.
- Tailwind CSS(CDN)를 활용한 직관적인 대시보드.
```
```markdown
## 🤖 에이더(Aider)를 위한 최종 지시서
아래 내용을 에이더 채팅창에 입력하시면 됩니다.
**프로젝트: VaultKeeper (Nginx .htpasswd 관리 도구)**
**1. 백엔드 구현 (`main.go`)**
- **언어**: Go (표준 라이브러리 위주로 매우 가볍게).
- **기능**:
- `GET /api/users`: `.htpasswd` 파일을 읽어 유저 목록을 JSON으로 반환.
- `POST /api/users`: `username`, `password`를 받아 `htpasswd -b` 실행.
- `DELETE /api/users/{username}`: `htpasswd -D` 실행.
- **보안**: 사용자 이름 입력값에서 쉘 인젝션이 발생하지 않도록 유효성 검사 로직 포함.
- **설정**: `.htpasswd` 경로를 환경 변수 `HTPASSWD_PATH`에서 읽어오도록 설정.
**2. 프론트엔드 구현 (`index.html`)**
- 단일 파일 SPA로 작성하고 Tailwind CSS를 사용하여 깔끔한 UI 제공.
- 유저 목록 표시, 추가 폼, 삭제 버튼 구현.
**3. 배포 가이드 (`deployment.md`) 생성**
- `go build`를 이용한 경량 바이너리 빌드 방법 (`-s -w` 옵션 포함).
- 터미널에서 최초 관리자 계정을 생성하는 명령어 안내.
- 이 서비스를 Nginx `auth_basic` 뒤에 배치하기 위한 `location` 블록 설정 예시. (8000번 포트 기준)
**주의**: 모든 코드와 문서에서 특정 개인의 이름이나 개인정보를 절대 포함하지 말고 `Admin` 또는 `User`와 같은 공용 용어만 사용해줘.
```
이걸 aider에게 먹이고 (add)
```bash
────────────────────────────────────────────────────────────────────────────────
> /add "doc/vault-keeper 상세 설계도.txt" "doc/지시서.txt"
Added doc\vault-keeper 상세 설계도.txt to the chat
Added doc\지시서.txt to the chat
────────────────────────────────────────────────────────────────────────────────
```
진행해보라고 했다.
```bash
doc\vault-keeper 상세 설계도.txt doc\지시서.txt
> 내가 추가한 상세 설계도와 지시서를 바탕으로 어플리케이션을 만들어봐
```
과연.. 결과는?
어.. 뭔가 만들어지긴 했다..
아래는 콘솔에 찍힌 내용 전체
요청하신 내용에 따라 애플리케이션을 만들겠습니다. main.go, index.html, deployment.md 파일을 새로 생성합니다.
다음은 필요한 SEARCH/REPLACE 블록입니다:
main.go
<<<<<<< SEARCH
=======
package main
import (
"bufio"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"os/exec"
"regexp"
"strings"
"sync"
)
// User는 .htpasswd 파일의 사용자 정보를 나타냅니다.
type User struct {
Username string `json:"username"`
}
// AddUserRequest는 새 사용자 추가 요청에 사용됩니다.
type AddUserRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
var (
htpasswdPath string
htpasswdMutex sync.Mutex // htpasswd 명령 실행 시 동시성 문제를 방지하기 위한 뮤텍스
usernameRegex *regexp.Regexp // 사용자 이름 유효성 검사를 위한 정규식
)
func init() {
// HTPASSWD_PATH 환경 변수 설정
htpasswdPath = os.Getenv("HTPASSWD_PATH")
if htpasswdPath == "" {
log.Fatal("환경 변수 HTPASSWD_PATH가 설정되지 않았습니다.")
}
// 사용자 이름 유효성 검사 정규식 초기화: 영문, 숫자, 하이픈, 언더스코어만 허용
usernameRegex = regexp.MustCompile("^[a-zA-Z0-9_-]+$")
}
func main() {
mux := http.NewServeMux()
// 정적 파일(index.html) 제공
mux.HandleFunc("/", serveFrontend)
// API 엔드포인트
mux.HandleFunc("/api/users", handleUsers)
mux.HandleFunc("/api/users/", handleDeleteUser) // DELETE 요청 처리
log.Println("VaultKeeper 서버가 8000 포트에서 시작됩니다.")
log.Printf("HTPASSWD_PATH: %s\n", htpasswdPath)
log.Fatal(http.ListenAndServe(":8000", mux))
}
// serveFrontend는 index.html 파일을 제공합니다.
func serveFrontend(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" || r.URL.Path == "/index.html" {
http.ServeFile(w, r, "index.html")
return
}
http.NotFound(w, r)
}
// handleUsers는 GET /api/users 및 POST /api/users 요청을 처리합니다.
func handleUsers(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
getUsers(w, r)
case http.MethodPost:
addUser(w, r)
default:
http.Error(w, "허용되지 않는 메소드입니다.", http.StatusMethodNotAllowed)
}
}
// getUsers는 .htpasswd 파일에서 사용자 목록을 읽어 JSON으로 반환합니다.
func getUsers(w http.ResponseWriter, r *http.Request) {
htpasswdMutex.Lock()
defer htpasswdMutex.Unlock()
file, err := os.Open(htpasswdPath)
if os.IsNotExist(err) {
// 파일이 없으면 빈 목록 반환 (처음 생성 시)
json.NewEncoder(w).Encode([]User{})
return
}
if err != nil {
log.Printf("Error opening .htpasswd file: %v", err)
http.Error(w, "사용자 파일을 읽을 수 없습니다.", http.StatusInternalServerError)
return
}
defer file.Close()
var users []User
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if len(line) > 0 && !strings.HasPrefix(line, "#") { // 주석 및 빈 줄 무시
parts := strings.SplitN(line, ":", 2)
if len(parts) > 0 {
users = append(users, User{Username: parts[0]})
}
}
}
if err := scanner.Err(); err != nil {
log.Printf("Error scanning .htpasswd file: %v", err)
http.Error(w, "사용자 파일을 스캔할 수 없습니다.", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
// addUser는 새 사용자를 .htpasswd 파일에 추가합니다.
func addUser(w http.ResponseWriter, r *http.Request) {
var req AddUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "유효하지 않은 요청 본문입니다.", http.StatusBadRequest)
return
}
// 사용자 이름 유효성 검사
if !usernameRegex.MatchString(req.Username) {
http.Error(w, "사용자 이름은 영문, 숫자, 하이픈, 언더스코어만 포함할 수 있습니다.", http.StatusBadRequest)
return
}
if req.Username == "" || req.Password == "" {
http.Error(w, "사용자 이름과 비밀번호는 필수입니다.", http.StatusBadRequest)
return
}
htpasswdMutex.Lock()
defer htpasswdMutex.Unlock()
// htpasswd -b <file> <username> <password>
// 파일이 없으면 -c 옵션이 필요하지만, 첫 생성은 터미널에서 하도록 가이드하므로 여기서는 -b만 사용.
// -b는 파일이 없으면 생성하고, 있으면 추가/수정합니다.
cmd := exec.Command("htpasswd", "-b", htpasswdPath, req.Username, req.Password)
output, err := cmd.CombinedOutput()
if err != nil {
log.Printf("Error executing htpasswd -b: %v, Output: %s", err, output)
http.Error(w, fmt.Sprintf("사용자 추가 실패: %s", strings.TrimSpace(string(output))), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(map[string]string{"message": "사용자가 성공적으로 추가되었습니다."})
}
// handleDeleteUser는 DELETE /api/users/{username} 요청을 처리합니다.
func handleDeleteUser(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodDelete {
http.Error(w, "허용되지 않는 메소드입니다.", http.StatusMethodNotAllowed)
return
}
username := strings.TrimPrefix(r.URL.Path, "/api/users/")
if username == "" {
http.Error(w, "사용자 이름을 지정해야 합니다.", http.StatusBadRequest)
return
}
// 사용자 이름 유효성 검사 (삭제도 동일하게 적용)
if !usernameRegex.MatchString(username) {
http.Error(w, "유효하지 않은 사용자 이름 형식입니다.", http.StatusBadRequest)
return
}
htpasswdMutex.Lock()
defer htpasswdMutex.Unlock()
// htpasswd -D <file> <username>
cmd := exec.Command("htpasswd", "-D", htpasswdPath, username)
output, err := cmd.CombinedOutput()
if err != nil {
// htpasswd -D는 사용자가 존재하지 않을 경우에도 에러를 반환합니다.
// 그러나 사용자 삭제 요청 자체는 성공했다고 간주할 수 있습니다 (해당 사용자가 없는 상태이므로).
// 실제 htpasswd의 에러 메시지를 확인하여 사용자 부재인지 다른 에러인지 구분할 수 있으나,
// 간단하게 사용자 부재 메시지가 아니라면 서버 에러로 처리합니다.
if strings.Contains(strings.ToLower(string(output)), "not found") {
http.Error(w, fmt.Sprintf("사용자 '%s'를 찾을 수 없습니다.", username), http.StatusNotFound)
return
}
log.Printf("Error executing htpasswd -D: %v, Output: %s", err, output)
http.Error(w, fmt.Sprintf("사용자 삭제 실패: %s", strings.TrimSpace(string(output))), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(map[string]string{"message": fmt.Sprintf("사용자 '%s'가 성공적으로 삭제되었습니다.", username)})
}
>>>>>>> REPLACE
index.html
<<<<<<< SEARCH
=======
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VaultKeeper - Nginx .htpasswd 관리</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<style>
body {
background-color: #f3f4f6;
}
</style>
</head>
<body class="font-sans antialiased text-gray-900">
<div class="min-h-screen flex flex-col items-center justify-center p-4">
<div class="w-full max-w-2xl bg-white rounded-lg shadow-xl p-8 space-y-8">
<h1 class="text-3xl font-bold text-center text-gray-800">VaultKeeper</h1>
<p class="text-center text-gray-600">Nginx .htpasswd 파일 관리</p>
<!-- 사용자 추가 폼 -->
<div class="border-t border-gray-200 pt-8">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">새 사용자 추가</h2>
<form id="addUserForm" class="space-y-4">
<div>
<label for="username" class="block text-sm font-medium text-gray-700">사용자 이름</label>
<input type="text" id="username" name="username" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none
focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700">비밀번호</label>
<input type="password" id="password" name="password" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none
focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<button type="submit"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm
font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
사용자 추가
</button>
</form>
<div id="addMessage" class="mt-3 text-center font-medium"></div>
</div>
<!-- 사용자 목록 -->
<div class="border-t border-gray-200 pt-8">
<h2 class="text-2xl font-semibold text-gray-800 mb-4">현재 사용자 목록</h2>
<div id="userListContainer">
<ul id="userList" class="divide-y divide-gray-200 bg-white rounded-md shadow-sm">
<!-- 사용자는 여기에 동적으로 로드됩니다. -->
</ul>
<p id="noUsersMessage" class="text-center text-gray-500 mt-4 hidden">등록된 사용자가 없습니다.</p>
</div>
<div id="listMessage" class="mt-3 text-center font-medium"></div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const addUserForm = document.getElementById('addUserForm');
const usernameInput = document.getElementById('username');
const passwordInput = document.getElementById('password');
const addMessageDiv = document.getElementById('addMessage');
const userList = document.getElementById('userList');
const noUsersMessage = document.getElementById('noUsersMessage');
const listMessageDiv = document.getElementById('listMessage');
async function fetchUsers() {
listMessageDiv.textContent = '';
userList.innerHTML = '';
try {
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const users = await response.json();
if (users.length === 0) {
noUsersMessage.classList.remove('hidden');
} else {
noUsersMessage.classList.add('hidden');
users.forEach(user => {
const li = document.createElement('li');
li.className = 'flex items-center justify-between p-4 hover:bg-gray-50';
li.innerHTML = `
<span class="text-lg font-medium">${user.username}</span>
<button data-username="${user.username}"
class="delete-btn bg-red-500 hover:bg-red-600 text-white font-bold py-1 px-3 rounded text-sm">
삭제
</button>
`;
userList.appendChild(li);
});
addDeleteEventListeners();
}
} catch (error) {
console.error('Error fetching users:', error);
listMessageDiv.textContent = `사용자 목록을 불러오는 데 실패했습니다: ${error.message}`;
listMessageDiv.className = 'mt-3 text-center font-medium text-red-600';
}
}
async function addUser(event) {
event.preventDefault();
addMessageDiv.textContent = '';
const username = usernameInput.value;
const password = passwordInput.value;
try {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || '사용자 추가 실패');
}
addMessageDiv.textContent = data.message;
addMessageDiv.className = 'mt-3 text-center font-medium text-green-600';
usernameInput.value = '';
passwordInput.value = '';
fetchUsers(); // 사용자 목록 새로 고침
} catch (error) {
console.error('Error adding user:', error);
addMessageDiv.textContent = `사용자 추가 실패: ${error.message}`;
addMessageDiv.className = 'mt-3 text-center font-medium text-red-600';
}
}
async function deleteUser(username) {
listMessageDiv.textContent = '';
if (!confirm(`사용자 '${username}'을(를) 정말 삭제하시겠습니까?`)) {
return;
}
try {
const response = await fetch(`/api/users/${username}`, {
method: 'DELETE',
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || '사용자 삭제 실패');
}
listMessageDiv.textContent = data.message;
listMessageDiv.className = 'mt-3 text-center font-medium text-green-600';
fetchUsers(); // 사용자 목록 새로 고침
} catch (error) {
console.error('Error deleting user:', error);
listMessageDiv.textContent = `사용자 삭제 실패: ${error.message}`;
listMessageDiv.className = 'mt-3 text-center font-medium text-red-600';
}
}
function addDeleteEventListeners() {
document.querySelectorAll('.delete-btn').forEach(button => {
button.onclick = () => deleteUser(button.dataset.username);
});
}
addUserForm.addEventListener('submit', addUser);
// 페이지 로드 시 사용자 목록 가져오기
fetchUsers();
});
</script>
</body>
</html>
>>>>>>> REPLACE
deployment.md
<<<<<<< SEARCH
=======
# VaultKeeper 배포 가이드
이 문서는 VaultKeeper 애플리케이션의 빌드, 초기 설정 및 Nginx 연동 방법을 안내합니다.
## 1. 백엔드 빌드
Go 바이너리를 가볍게 빌드하려면 다음 명령어를 사용합니다. 이 명령어는 디버그 정보를 제거하고 심볼 테이블을 생략하여 최종 바이너리
크기를 줄입니다.
```bash
go build -o vaultkeeper -ldflags "-s -w" main.go
빌드가 완료되면 현재 디렉토리에 vaultkeeper 실행 파일이 생성됩니다.
2. .htpasswd 파일 경로 설정
VaultKeeper는 .htpasswd 파일의 경로를 환경 변수 HTPASSWD_PATH를 통해 설정합니다. 애플리케이션을 실행하기 전에 이 환경 변수를 설정해야
합니다.
예시:
export HTPASSWD_PATH="/etc/nginx/.htpasswd"
또는
export HTPASSWD_PATH="/usr/local/etc/htpasswd"
주의: 지정된 경로에 Nginx가 실제로 사용하는 .htpasswd 파일이 있어야 합니다. 쓰기 권한도 필요합니다.
3. 최초 관리자 계정 생성 (터미널)
VaultKeeper는 자체 로그인 로직을 포함하지 않으며, Nginx auth_basic 모듈에 인증을 위임합니다. 웹 UI에 접근하려면 Nginx를 통해 인증할 수
있는 계정이 필요합니다. 최초 관리자 계정은 VaultKeeper가 실행되기 전에 터미널에서 htpasswd 명령어를 사용하여 생성해야 합니다.
.htpasswd 파일이 아직 없는 경우:
htpasswd -c /etc/nginx/.htpasswd adminuser
adminuser를 원하는 관리자 사용자 이름으로 바꾸세요. 이 명령어는 /etc/nginx/.htpasswd 파일을 생성하고 adminuser를 추가합니다.
.htpasswd 파일이 이미 있는 경우 (새 사용자를 추가하거나 기존 사용자의 비밀번호를 변경):
htpasswd /etc/nginx/.htpasswd anotheruser
-c 옵션을 사용하면 기존 파일이 덮어쓰여지므로 절대 이미 존재하는 파일에 -c 옵션을 다시 사용하지 마세요.
4. VaultKeeper 실행
환경 변수 설정 및 .htpasswd 파일 준비가 완료되면, 빌드된 VaultKeeper 바이너리를 실행합니다.
./vaultkeeper
기본적으로 VaultKeeper는 8000번 포트에서 수신 대기합니다.
5. Nginx 설정 예시
Nginx의 auth_basic 모듈 뒤에서 VaultKeeper를 실행하여 접근을 제한할 수 있습니다. 다음은 Nginx 설정 파일 (/etc/nginx/nginx.conf 또는
conf.d 내부 파일)에 추가할 수 있는 location 블록 예시입니다.
이 설정은 /vaultkeeper/ 경로로 들어오는 요청을 VaultKeeper 백엔드(8000번 포트)로 프록시하고, auth_basic을 통해 .htpasswd 파일로 인증을
요구합니다.
server {
listen 80;
server_name your_domain.com; # 도메인 또는 IP 주소로 변경
location /vaultkeeper/ {
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/.htpasswd; # .htpasswd 파일 경로를 정확히 지정
proxy_pass http://127.0.0.1:8000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
# 다른 Nginx 설정...
}
Nginx 설정을 변경한 후에는 반드시 Nginx를 재로드하거나 재시작하여 변경사항을 적용해야 합니다.
sudo nginx -t # 설정 파일 유효성 검사
sudo systemctl reload nginx # Nginx 재로드
이제 http://your_domain.com/vaultkeeper/ (또는 http://your_server_ip/vaultkeeper/)로 접근하여 VaultKeeper 웹 UI를 사용할 수 있습니다.
접근 시 Nginx가 사용자 이름과 비밀번호를 요청할 것입니다.
▌ ▌ ▌ ▌ ▌ ▌ ▌ REPLACE
새로 생성된 파일을 확인하고 싶으시다면, 다음 명령어를 실행하여 바이너리를 빌드하고 서버를 시작할 수 있습니다:
```bash
go build -o vaultkeeper -ldflags "-s -w" main.go
export HTPASSWD_PATH="/tmp/.htpasswd" # 테스트용 임시 경로, 실제 경로로 변경 필요
htpasswd -c /tmp/.htpasswd adminuser # 최초 관리자 계정 생성
./vaultkeeper
index.html을 브라우저에서 열거나, Nginx를 설정한 후 http://localhost:8000 (또는 Nginx 프록시 설정에 따른 URL)으로 접속하여 프론트엔드를
확인할 수 있습니다.
Tokens: 3.3k sent, 5.0k received. Cost: $0.01 message, $0.01 session.
main.go
Create new file? (Y)es/(N)o [Yes]: y
index.html
Create new file? (Y)es/(N)o [Yes]: y
deployment.md
Create new file? (Y)es/(N)o [Yes]: y
Applied edit to main.go
Applied edit to index.html
Applied edit to deployment.md
Commit bd414ad feat: 새로운 htpasswd 관리 애플리케이션 VaultKeeper 구현
go build -o vaultkeeper -ldflags "-s -w" main.go
export HTPASSWD_PATH="/tmp/.htpasswd" # 테스트용 임시 경로, 실제 경로로 변경 필요
htpasswd -c /tmp/.htpasswd adminuser # 최초 관리자 계정 생성
./vaultkeeper
Run shell commands? (Y)es/(N)o/(D)on't ask again [Yes]: y
Running go build -o vaultkeeper -ldflags "-s -w" main.go
Running export HTPASSWD_PATH="/tmp/.htpasswd" # 테스트용 임시 경로, 실제 경로로 변경 필요
'export'() Ǵ ܺ , ִ α׷, Ǵ
ġ ƴմϴ.
Running htpasswd -c /tmp/.htpasswd adminuser # 최초 관리자 계정 생성
'htpasswd'() Ǵ ܺ , ִ α׷, Ǵ
ġ ƴմϴ.
Running ./vaultkeeper
'.'() Ǵ ܺ , ִ α׷, Ǵ
ġ ƴմϴ.
Add command output to the chat? (Y)es/(N)o/(D)on't ask again [Yes]: y
Added 11 lines of output to the chat.
You can use /undo to undo and discard each aider commit.
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.md doc\vault-keeper 상세 설계도.txt doc\지시서.txt index.html main.go
> /ls
Files in chat:
deployment.md
index.html
main.go
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
deployment.md doc\vault-keeper 상세 설계도.txt doc\지시서.txt index.html main.go
>
@@ -0,0 +1,69 @@
---
id: "Aider 프로젝트 생성 20260413"
created: "2026-04-13 13:31"
tags:
---
새로운 프로젝트를 만든다고 가정
만들고싶은 디렉토리에서
### 1단계: 프로젝트 폴더 생성 및 이동
먼저 프로젝트별로 방을 나눠야 합니다.
```bash
mkdir my-new-project # 원하는 프로젝트 이름으로 생성
cd my-new-project
```
### 2단계: Git 초기화 (매우 중요)
에이더는 작업 내용을 자동으로 기록하고 커밋하기 위해 **Git**을 기반으로 움직입니다. 폴더를 만들자마자 가장 먼저 해야 할 일입니다.
```bash
git init
```
- 이 과정을 거쳐야 나중에 에이더가 사고를 쳐도 `git checkout` 등으로 안전하게 코드를 복구할 수 있습니다.
### 3단계: API 키 및 기본 설정 확인
매번 키를 입력하기 귀찮다면, 아까 논의했던 대로 **환경 변수**나 **설정 파일**이 준비되어 있는지 확인합니다.
- 이미 윈도우 환경 변수에 `GEMINI_API_KEY`를 등록하셨다면 이 단계는 건너뛰셔도 됩니다.
- 만약 특정 모델을 고정하고 싶다면 이 폴더에 `.aider.conf.yml` 파일을 만드세요.
### 4단계: 에이더(Aider) 실행
이제 준비가 끝났습니다. 에이더를 깨웁니다.
```bash
aider
```
- 만약 별칭(alias)이나 설정 파일을 만들지 않았다면 직접 모델명을 적어줍니다: `aider --model gemini/gemini-1.5-pro`
- pro는 비싸니까 그냥 flash로 하는게 정신건강과 지갑건강상 좋음
### 5단계: 첫 번째 파일 생성 요청
에이더가 실행되면 AI에게 첫 작업을 시켜보세요.
- 예: `Hello! 파이썬으로 간단한 계산기 로직이 담긴 calculator.py 파일을 만들어줘.`
### 최종 결과물 구조
이렇게 순서대로 진행하면 폴더 안이 아래와 같이 예쁘게 정렬됩니다.
```cmd
workspaces/
└── my-new-project/
├── .git/ (2단계에서 생성)
├── .aider.chat.history.md (4단계 실행 후 생성)
├── .aider.tags.cache.v4/ (4단계 실행 후 생성)
└── calculator.py (5단계에서 생성됨)
```
**꿀팁:** 작업을 하다가 마음에 안 들면 에이더 채팅창 안에서 `/undo`를 입력하세요. 그러면 에이더가 방금 한 커밋을 취소하고 코드를 직전 상태로 돌려놓습니다.
@@ -0,0 +1,66 @@
---
id: "MariaDB vs PostgreSql 20260421"
created: "2026-04-21 16:43"
tags:
---
이 두 DB는 현재 오픈소스 RDBMS 시장의 양대 산맥입니다. **MariaDB**가 MySQL의 친숙함을 계승하며 실용성에 집중한다면, **PostgreSQL**은 데이터 무결성과 고급 기능을 중시하는 학구적이고 정교한 DB라고 할 수 있습니다.
## 1. 철학 및 개발 배경
|**구분**|**MariaDB**|**PostgreSQL**|
|---|---|---|
|**태생**|MySQL에서 분차(Fork)되어 나온 실용주의 DB|학계에서 시작된 객체-관계형(ORDBMS) 표준 지향 DB|
|**슬로건**|"MySQL보다 빠르고 더 많은 기능을 무료로"|"세계에서 가장 진보된 오픈소스 관계형 데이터베이스"|
|**라이선스**|GPL v2 (비즈니스 시 소스 공개 의무 주의)|PostgreSQL 라이선스 (BSD/MIT와 유사, 매우 자유로움)|
## 2. 기술적 핵심 차이
### 🚩 SQL 표준 및 복잡한 쿼리 처리
- **PostgreSQL:** SQL 표준 준수율이 매우 높습니다. 복잡한 조인(Join), 재귀 쿼리(Recursive CTE), 윈도우 함수 성능이 뛰어나며, 분석용 쿼리 최적화가 강력합니다. (MSSQL과 사용감이 비슷합니다.)
- **MariaDB:** MySQL의 문법을 따르며, 단순한 CRUD 성능에 최적화되어 있습니다. 최근 버전에서 CTE나 윈도우 함수를 지원하지만, 복잡한 비즈니스 로직 처리에서는 PostgreSQL에 비해 최적화가 덜 정교할 수 있습니다.
### 🚩 데이터 타입과 확장성
- **PostgreSQL:** 독보적입니다. JSONB(바이너리 JSON) 지원으로 NoSQL처럼 쓸 수 있고, 지리 정보(PostGIS), 전문 검색(Full-text search) 등이 내장되어 있습니다. 사용자 정의 타입도 만들 수 있습니다.
- **MariaDB:** 동적 컬럼(Dynamic Columns) 기능을 통해 비정형 데이터를 다루지만, PostgreSQL의 JSONB 성능에는 미치지 못합니다. 대신 다양한 스토리지 엔진(InnoDB, Aria, ColumnStore 등)을 용도에 맞게 선택할 수 있는 유연성이 있습니다.
### 🚩 동시성 제어 (MVCC)
- **PostgreSQL:** 데이터 쓰기 중에도 읽기가 차단되지 않는 MVCC(Multi-Version Concurrency Control) 방식이 매우 세련되어 있어, 동시 접속자가 많은 대형 시스템에 유리합니다.
- **MariaDB:** 스토리지 엔진(주로 InnoDB) 수준에서 MVCC를 지원하며, 읽기 위주의 서비스에서 가볍고 빠르게 동작합니다.
## 3. 상세 비교 테이블
| **항목** | **MariaDB** | **PostgreSQL** |
| ------------------- | ---------------------------- | ------------------------------------------- |
| **주요 용도** | 웹 서비스, CMS(워드프레스 등), 단순 CRUD | 복잡한 데이터 분석, 금융 시스템, GIS 서비스 |
| **성능 특징** | 읽기(Read) 성능이 매우 빠름 | 복잡한 쓰기(Write) 및 대량 데이터 처리에 강함 |
| **복제(Replication)** | 마스터-슬레이브 방식이 매우 쉽고 직관적 | 논리적 복제 등 다양한 방식 지원 (설정은 좀 더 복잡) |
| **저장 프로시저** | 지원 (MySQL 문법) | 강력 지원 (PL/pgSQL, Python, Perl 등 지원) |
| **인덱싱** | 기본 B-Tree 위주 | B-Tree, Hash, GiST, SP-GiST, GIN, BRIN 등 다양 |
## 4. 어떤 것을 선택해야 할까?
### 🐧 MariaDB를 선택할 때
- 기존에 MySQL을 써본 적이 있어 익숙함이 중요할 때.
- 커뮤니티나 자료가 많은 것을 선호할 때.
- 단순한 웹 게시판이나 가벼운 데이터 저장용일 때.
- PHP나 구형 웹 스택과의 호환성이 중요할 때.
### 🐘 PostgreSQL을 선택할 때
- **MSSQL 2019의 고급 기능을 오픈소스에서도 누리고 싶을 때.**
- 데이터 정합성이 무엇보다 중요한 금융, 결제, 정산 관련 프로젝트일 때.
- JSON 데이터를 빈번하게 다루면서 속도도 포기할 수 없을 때.
- 프로젝트가 커질 것을 대비해 확장성이 뛰어난 DB가 필요할 때.
+64
View File
@@ -0,0 +1,64 @@
---
id: RDBMS vs NoSQL 20260420
created: 2026-04-20 08:43
tags:
---
DB에는 크게 [[RDBMS]]와 NoSQL 두가지의 범주가 있음.
둘 다 데이터베이스를 구축하기위한 방법론의 개념이고 상호간에 차이점들이 존재한다.
하지만 데이터베이스라면 당연히 [[데이터 정합성(Data Consistency)]]을 지키는것이 최우선 목표이다.
NoSQL이 [[데이터 정합성(Data Consistency)]]을 지키지 않는 것은 절대 아니다.
[[데이터 정합성(Data Consistency)]]을 지키지 않는 건 데이터베이스로서 가치가 없다.
이 둘의 가장 큰 차이점은 데이터의 중복을 어느 정도 허용할 것인가? 라고 생각된다.
![[NoSQL#데이터 중복(Data Redundancy)]]
## NoSQL이 중복을 허용하는 이유
### **JOIN 연산의 배제**
NoSQL은 수평적 확장을 위해 데이터를 여러 서버에 분산 저장합니다. 이때 여러 서버에 흩어진 데이터를 JOIN 하는 작업은 성능에 막대한 지장을 줍니다. 이를 피하기 위해 필요한 데이터를 한 곳에 모아(중복 저장) 한 번의 쿼리로 읽어오도록 설계합니다.
### **읽기 성능 극대화**
사용자가 화면을 볼 때 필요한 모든 정보를 하나의 'Document'나 'Row'에 다 담아두면, 여러 테이블을 뒤질 필요 없이 즉시 응답할 수 있습니다.
## 데이터 중복으로 인한 기회비용
중복을 허용하면 얻는 것도 있지만, 반드시 대가를 치러야 합니다.
- **데이터 수정의 복잡성 (Update Anomaly):** 사용자 이름이 바뀌면, 그 이름이 중복 저장된 수천 개의 게시글 데이터를 모두 업데이트해야 합니다. 이때 일부가 누락되면 데이터 정합성이 깨집니다.
- **저장 공간 증가:** 동일한 데이터가 반복 저장되므로 저장 용량을 더 많이 차지합니다. 하지만 현대의 클라우드 인프라에서는 저장 비용보다 컴퓨팅 성능(속도) 비용이 더 중요하므로 대개 용납됩니다.
- **결과적 일관성 (Eventual Consistency):** 모든 중복 데이터를 즉시 수정하는 것이 어렵기 때문에, "잠시 동안은 데이터가 다를 수 있지만 결국에는 같아진다"는 원칙을 따르게 됩니다.
## RDBMS vs NoSQL: 언제 무엇을 쓸까?
어느 하나가 절대적으로 우월한 것이 아니라, 서비스의 성격에 맞춰 선택하거나 두 가지를 혼합해서 사용합니다.
### **RDBMS를 써야 할 때**
- 데이터 구조가 명확하고 변경될 일이 적을 때
- **금융 시스템**처럼 [[데이터 정합성(Data Consistency)]]과 [[트랜잭션(Transaction)|트랜젝션]]([[ACID]])이 매우 중요할 때
- 복잡한 쿼리와 JOIN 연산이 자주 필요할 때
### **NoSQL을 써야 할 때**
- 데이터 구조가 확정되지 않았거나 자주 변경될 때
- **빅데이터, 로그 관리, 실시간 메신저**처럼 막대한 양의 데이터를 빠르게 처리해야 할 때
- [[데이터 정합성(Data Consistency)]]보다는 서비스의 [[가용성(Availability)]](항상 접속 가능함)이 더 중요할 때
[[NoSQL]]은 "데이터가 조금 틀려도 괜찮으니, 절대 죽지 않고 엄청나게 빠른 시스템"을 만들 때 씁니다. 반면 [[RDBMS]]는 "성능이 조금 답답하더라도, 데이터는 단 1원, 1글자도 틀리면 안 되는 시스템"에 씁니다.
> [!warning] 그렇다고 해서 NoSQL이 데이터정합성이 안맞단건 절대 아님
> 실시간으로 정합성을 맞춰주느냐? (RDBMS), 순간적으로는 안맞을 수 있지만 결과적으론 정합성이 맞다 (NoSQL)
@@ -0,0 +1,20 @@
---
id: RDBMS사용 시 주의점들 20260420
created: 2026-04-20 10:55
tags:
---
> [!question]
> Q. 관계형db에서는 테이블간의 관계를 여러테이블을 조인하지 않게끔 적절히 분산시키면서 인덱스를 잘 거는게 엄청 중요하겠네?
> A. 정확하게 짚으셨습니다! 관계형 데이터베이스(RDBMS) 운영의 핵심이자 개발자의 실력이 가장 극명하게 드러나는 지점이 바로 그 **'조인(JOIN) 최소화'와 '인덱스(Index) 전략'**입니다.
## 조인 최소화: "관계는 유지하되, 데이터는 뭉친다"
관계형 DB라고 해서 무조건 모든 데이터를 쪼개는 게 정답은 아닙니다. 성능을 위해 의도적으로 정합성을 조금 희생하는 기법들이 필요합니다.
과도하게 데이터를 쪼개놓을 경우 데이터 조인이 많이 발생될 수 밖에 없는데 데이터 조인은 어느정도 느릴 수 밖에 없다.
- [[데이터 조인이 느린 이유]]
결국 RDBMS 설계의 꽃은 **인덱스를 활용해 '수학적인 탐색 비용'을 얼마나 낮게 유지하느냐**에 달려 있습니다.
하지만 아무리 인덱스를 잘 설정해도 조인해야 할 테이블이 5개, 10개씩 늘어나면 성능은 떨어질 수밖에 없습니다.
- **Nested Loop의 누적:** 조인이 중첩될수록 내부 루프의 횟수가 곱하기로 늘어납니다.
그래서 적당한 데이터 분산이 중요합니다.
@@ -0,0 +1,32 @@
---
id: 어플리케이션(서비스) 실행 20260413
created: 2026-04-13 14:57
tags:
---
> [!question]
> Q. 리눅스에서 서비스나 어플리케이션 새로 실행할 때 계정을 따로 생성해서 그 계정으로 실행하는 이유가 뭐야?
> A. 리눅스에서 Gitea, Jenkins와 같은 서비스를 전용 계정(Service Account)으로 실행하는 가장 큰 이유는 **보안**과 **시스템 안정성** 때문입니다. 만약 루트(root) 권한으로 서비스를 실행했다가 해당 서비스가 해킹당하면 시스템 전체가 장악될 수 있기 때문이죠.
### 1. 최소 권한의 원칙 (Principle of Least Privilege)
가장 핵심적인 개념입니다. 특정 서비스가 작동하는 데 필요한 **최소한의 권한**만 부여하는 것입니다.
- **격리:** 전용 계정을 만들면 해당 계정은 자신의 홈 디렉터리와 서비스 관련 파일에만 접근할 수 있습니다.
- **피해 최소화:** 서비스에 취약점이 있어 해커가 침입하더라도, 해커는 해당 계정의 권한만 갖게 됩니다. 시스템 설정 파일을 수정하거나 다른 사용자의 데이터를 훔쳐보는 것이 차단됩니다.
### 2. 시스템 자원 및 프로세스 관리
전용 계정을 사용하면 관리 효율성이 높아집니다.
- **자원 제한:** 특정 계정이 사용할 수 있는 CPU, 메모리, 파일 열기 개수 등을 제한(ulimit 등)하여 하나의 서비스가 시스템 전체 자원을 독점하는 것을 방지할 수 있습니다.
- **로그 및 모니터링:** 어떤 프로세스가 어떤 계정으로 실행 중인지 명확하므로, 로그를 분석하거나 문제를 추적할 때 훨씬 수월합니다.
### 3. 보안 사고 발생 시 대응
- **계정 차단:** 특정 서비스 계정에서 이상 징후가 발견되면 시스템 전체를 내릴 필요 없이 해당 계정만 잠그거나 권한을 박탈하여 즉각 대응할 수 있습니다.
- **비로그인 계정:** 보통 서비스용 계정은 `nologin`이나 `false` 쉘을 부여하여, 사람이 직접 SSH 등으로 로그인하는 것을 막아둡니다. 이는 외부 공격자가 해당 계정으로 서버에 직접 접속하는 경로를 원천 차단하는 효과가 있습니다.
@@ -0,0 +1,21 @@
---
id: 라우팅 20260428
created: 2026-04-28 14:14
tags:
---
PC1과 PC2 사이에 랜선으로 직접 연결하여 통신을 하게 할 수 있음.
단, 연결하자마자 곧바로 되는 건 아니고 몇 가지 설정을 해야 함.
일단 이 랜선이 꽂힌 랜포트에 대해 설정을 해주어야 함.
이 연결에는 [[DHCP(Dynamic Host Configuration Protocol)]]서버가 없기 때문에 자동으로 설정할 수 없음.
[[IP]]주소, [[서브넷 마스크(Subnet Mask)]], 기본[[게이트웨이(Gateway)]]를 설정한다.
그리고 PC에 더이상의 추가적인 통신연결이 없을경우에는 별도의 설정없이 곧바로 통신이 가능해진다.
"어디로든 나가야 하면 일단 이 랜선으로 나가자"라는 기본 규칙(Default Route)이 아주 단순하게 작동하게됨.
만약 둘 이상의 통신연결이 있을 경우 [[라우팅 테이블(Routing Table)]]에 등록이 되어있어야 통신이 가능해진다.
[[라우팅 테이블(Routing Table)]]은 통신연결 시도측, 받는측 양측 모두에 상대방이 등록되어있어야 한다.
> [!info] **자동 생성:**
> 윈도우나 리눅스 같은 운영체제는 랜카드에 IP(`192.168.100.x`)를 설정하는 순간, **"이 대역으로 가는 길은 이 랜카드다"라는 규칙을 라우팅 테이블에 자동으로 추가**합니다.
@@ -0,0 +1,9 @@
---
id: "RS-232 20260504"
created: "2026-05-04 09:20"
tags:
---
RS-232는 [[시리얼 통신(Serial Communication)]] 방식을 구현하기 위해 정해진 구체적인 표준임.
Serial이 교통수단이라면 RS-232는 자동차라고 볼 수 있음.
@@ -0,0 +1,63 @@
---
id: "worker server spec 20260414"
created: "2026-04-14 13:28"
tags:
---
ubuntu@instance-20260414-0951:~$ **lscpu**
Architecture: aarch64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Vendor ID: ARM
Model name: Neoverse-N1
Model: 1
Thread(s) per core: 1
Core(s) per socket: 4
Socket(s): 1
Stepping: r3p1
BogoMIPS: 50.00
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
NUMA:
NUMA node(s): 1
NUMA node0 CPU(s): 0-3
Vulnerabilities:
Gather data sampling: Not affected
Ghostwrite: Not affected
Indirect target selection: Not affected
Itlb multihit: Not affected
L1tf: Not affected
Mds: Not affected
Meltdown: Not affected
Mmio stale data: Not affected
Old microcode: Not affected
Reg file data sampling: Not affected
Retbleed: Not affected
Spec rstack overflow: Not affected
Spec store bypass: Mitigation; Speculative Store Bypass disabled via p
rctl
Spectre v1: Mitigation; __user pointer sanitization
Spectre v2: Mitigation; CSV2, BHB
Srbds: Not affected
Tsa: Not affected
Tsx async abort: Not affected
Vmscape: Not affected
ubuntu@instance-20260414-0951:~$ **free -h**
total used free shared buff/cache available
Mem: 23Gi 691Mi 21Gi 5.4Mi 1.9Gi 22Gi
Swap: 0B 0B 0B
ubuntu@instance-20260414-0951:~$ **df -h**
Filesystem Size Used Avail Use% Mounted on
tmpfs 2.4G 1.5M 2.4G 1% /run
efivarfs 256K 14K 243K 6% /sys/firmware/efi/efivars
/dev/sda1 193G 3.1G 190G 2% /
tmpfs 12G 0 12G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/sda16 891M 94M 735M 12% /boot
/dev/sda15 98M 6.4M 92M 7% /boot/efi
tmpfs 2.4G 12K 2.4G 1% /run/user/1001
+45
View File
@@ -0,0 +1,45 @@
---
id: 전표처리 20260413
created: 2026-04-13 08:42
tags:
---
![[전표#📑 개념]]
회사 법인카드 사용하고나서 [[분개전표]] 처리를 해야한다. ([[전표]])
돈을 얼마나 썼는지, 왜 썼는지에 대한 상세사항정리 정도로 생각하면 됨.
> [!warning]
**분개전표 입력전에 법인카드사용내역회계전표생성(개인) 부터 먼저해야함.**
여기에 등록하고 승인나면 그때 자동으로 입력된 전표를 처리해야 함.
![[Pasted image 20260427095731.png]]
위 화면에선 특별히 추가할 거 없이 결재상신 하면 됨
1. 30만원 이하  PM -> 팀장 -> 사업부장, 합의 문새별 -> 김성민 입니다. (PM이 없는 경우나 PM이 팀장인 경우는 PM 생략)
결제 상세는 [[법인카드 결제상신 경로]] 참고
> [!note] 부가세 여부
[[부가세여부]] 참고
업무용 택시비, 소모품비, 숙소비는 부가세여부 O
일반차량 유류비, 톨게이트비 부가세여부 X
> [!warning] 법인카드사용내역회계전표생성(개인) 부터 먼저 결제하지 않고 진행하면...
전표 유형이 법인카드사용내역전표(개인) 이 아니고 일반분개전표 로 진행이 되어버림..
![[Pasted image 20260427133315.png]]
ERP에서 ESS -> 회계 -> 전표입력 으로 가서 전표입력 하면 됨.
![[분개(分介)#예시 이미지]]
위와같은 형태로 입력한다.
0002 대변금액은 직접 적는게 아니고 0001 차변금액을 아래로 드래그해서 추가하면 됨.
여기서 전표를 추가하고 그룹웨어에서 결제 진행하면 됨.
+26
View File
@@ -0,0 +1,26 @@
---
id: ACID 20260420
created: 2026-04-20 08:44
tags:
aliases:
---
---
## 📑 개념
DB에서 하나의 논리적 작업 단위를 '트랜잭션'이라고 합니다. RDBMS는 이 트랜잭션이 안전하게 처리됨을 보장하기 위해 ACID 특성을 가집니다.
## 📌 상세
- **Atomicity (원자성):** 전부 성공하거나, 전부 실패하거나. - "All or Nothing"
트랜잭션 내의 모든 연산은 반드시 한꺼번에 완료되어야 하며, 그렇지 못할 경우 모두 취소되어야 합니다.
**예:** 계좌 이체 시 '내 계좌 출금'은 성공했는데 '상대 계좌 입금'에서 오류가 나면, 내 계좌의 출금 내역도 취소되어야 합니다.
- **Consistency (일관성):** 완료 후 DB 상태가 규칙을 위반하지 않음.
트랜잭션 수행 전후의 데이터베이스 상태는 항상 논리적으로 올바른 상태여야 합니다.
**예:** 모든 계좌의 잔액은 0원 이상이어야 한다는 제약 조건이 있다면, 트랜잭션 후 잔액이 마이너스가 되는 결과는 허용되지 않습니다.
- **Isolation (고립성):** 동시에 실행되는 트랜잭션들이 서로 방해하지 않음.
동시에 여러 트랜잭션이 실행될 때, 각 트랜잭션은 서로의 작업에 간섭할 수 없습니다. 하나의 트랜잭션이 끝나기 전까지는 다른 트랜잭션에서 그 중간 결과를 볼 수 없습니다.
- **Durability (지속성):** 성공한 결과는 영구적으로 저장됨.
성공적으로 완료된 트랜잭션의 결과는 시스템 장애가 발생하더라도 영구적으로 기록되어야 합니다. 로그 파일 등을 통해 복구가 가능한 상태를 말합니다.
---
@@ -0,0 +1,49 @@
---
id: "DHCP(Dynamic Host Configuration Protocol) 20260428"
created: "2026-04-28 14:21"
tags:
aliases:
---
## 💡 생각
이곳에 하나의 생각 또는 아이디어를 작성합니다.
---
## 📑 개념
네트워크 안에 있는 장치들에게 IP 주소를 자동으로 할당해 주는 통신 규약입니다.
매번 사람이 직접 장치마다 IP를 입력하는 번거로움을 없애고, IP 충돌 같은 네트워크 사고를 방지하기 위해 사용됩니다.
## DHCP가 하는 일
네트워크에 새로운 기기(노트북, 스마트폰 등)가 연결되면, DHCP 서버는 다음과 같은 정보를 자동으로 제공합니다.
- **IP 주소:** 기기의 고유 식별 주소
- **서브넷 마스크:** 네트워크 범위를 결정하는 값
- **기본 게이트웨이:** 외부 인터넷으로 나가는 통로 주소
- **DNS 서버 주소:** 도메인 이름을 IP로 변환해 주는 서버 주소
## DHCP 사용의 장점
- **관리의 편리함:** 관리자가 일일이 IP를 할당하지 않아도 서버가 알아서 빈 주소를 찾아줍니다.
- **효율적인 IP 자원 관리:** 사용 중이지 않은 IP는 회수하여 다른 기기에 줄 수 있으므로 한정된 IP 자원을 아낄 수 있습니다. (이를 **임대 시간/Lease Time**이라고 합니다.)
- **설정 오류 방지:** 오타나 중복된 IP 입력으로 인한 네트워크 연결 오류를 방지할 수 있습니다.
## 임대(Lease)와 갱신(Renewal)
DHCP는 IP를 영구적으로 주는 것이 아니라, 특정 시간 동안 **빌려주는(Lease)** 개념입니다.
- **임대 시간:** IP를 사용할 수 있는 유효 기간입니다.
- **갱신:** 보통 임대 시간의 50%가 지나면 클라이언트는 서버에 "이 IP를 계속 써도 될까요?"라고 물어보고 사용 시간을 연장합니다. 만약 기기가 네트워크를 떠나면 임대 시간이 만료된 후 해당 IP는 다시 서버로 회수되어 다른 기기가 쓸 수 있게 됩니다.
> [!note] 우리가 흔히 쓰는 공유기가 바로 이 DHCP 서버 역할을 수행하여 집 안의 여러 기기에 IP를 나눠주고 있습니다.
>
---
+45
View File
@@ -0,0 +1,45 @@
---
id: "NoSQL 20260420"
created: "2026-04-20 10:07"
tags:
aliases:
---
## 💡 생각
결국 NoSQL은 빠른속도로 데이터베이스를 구축해서 사용하는 경우에 유용하다.
---
## 📑 개념
'Not Only SQL'의 약자로, 전통적인 [[관계형 데이터베이스(RDBMS)의 한계]]를 극복하기 위해 만들어진 **비관계형 데이터베이스**를 의미합니다.
표(Table) 형태의 엄격한 스키마를 따르지 않고, 데이터의 형태에 따라 유연하게 저장 구조를 선택할 수 있다는 것이 가장 큰 특징입니다.
## NoSQL의 특징
- **유연한 스키마 (Schema-less):** 고정된 테이블 구조가 없습니다. 데이터의 필드를 언제든지 추가하거나 변경할 수 있어, 형태가 일정하지 않은 로그 데이터나 SNS 포스트 등을 저장하기에 유리합니다.
- **수평적 확장성 (Scalability):** RDBMS가 주로 서버의 사양을 높이는 수직 확장(Scale-up)에 집중한다면, NoSQL은 여러 대의 저렴한 서버를 클러스터로 묶어 데이터를 분산 저장하는 **수평 확장(Scale-out)** 에 최적화되어 있습니다.
- **고성능:** 단순한 데이터 모델을 사용하여 읽기/쓰기 성능이 매우 빠릅니다. 복잡한 JOIN 연산을 지양하기 때문에 대규모 데이터를 처리할 때 유리합니다.
---
## NoSQL의 4가지 주요 유형
| **유형** | **특징** | **대표적인 DB** |
| ----------------- | --------------------------- | ---------------------- |
| **Key-Value** | 가장 단순한 형태. 키와 값의 쌍으로 저장 | Redis, Amazon DynamoDB |
| **Document** | JSON이나 XML 같은 문서 형식으로 저장 | **MongoDB**, CouchDB |
| **Column-family** | 행이 아닌 열(Column) 단위로 데이터를 저장 | Cassandra, HBase |
| **Graph** | 데이터 간의 관계를 노드와 간선으로 표현 | Neo4j |
## NoSQL의 트랜잭션 (BASE)
RDBMS의 [[ACID]]와 대조적으로, NoSQL은 보통 **BASE** 원칙을 따릅니다.
- **Basically Available (기본적 가용성):** 언제든 접근 가능해야 함.
- **Soft State (소프트 상태):** 외부의 개입 없어도 정보가 변경될 수 있음 (일시적 불일치 허용).
- **Eventually Consistent (결과적 일관성):** 일시적으로 정합성이 깨질 수 있지만, 시간이 지나면 결국 모든 노드의 데이터가 일치하게 됨.
## 데이터 중복(Data Redundancy)
NoSQL에서 **데이터 중복(Data Redundancy)** 은 실수가 아니라 **성능을 위해 의도적으로 선택하는 핵심 전략**입니다.
RDBMS에서는 데이터 중복을 죄악시하며 정규화(Normalization)를 통해 중복을 제거하지만, NoSQL은 그 반대인 **비정규화(Denormalization)** 를 지향합니다.
+50
View File
@@ -0,0 +1,50 @@
---
id: RDBMS 20260420
created: 2026-04-20 08:43
tags:
aliases:
---
## 💡 생각
데이터간의 관계를 고민하고 관계를 이용해서 중복된 데이터가 들어가는것을 최소화하는 DB를 일컫는다고 보면 된다. 왜냐하면 데이터 정합성은 사실 RDBMS든 NoSQL이든 무조건 지켜주는게 좋은 부분이니까 이걸 RDBMS와 NoSQL의 차이다 라고 하기에는 좀 과하다고 생각된다.
---
## 📑 개념
관계형 DB의 가장 큰 특징은 데이터를 **Table(표)** 형태로 관리하고, 테이블 간의 **Relation(관계)** 을 정의한다는 점입니다.
## 📌 상세
- **스키마(Schema):** 데이터의 구조와 제약 조건을 정의한 설계도입니다.
- **기본키(PK)와 외래키(FK):** 테이블 간의 연결 고리이자 데이터의 유일성을 보장하는 핵심 장치입니다.
- **무결성(Integrity):** 데이터가 정확하고 일관되게 유지되도록 하는 규칙들입니다.
[[ACID]] [[트랜잭션(Transaction)|트렌젝션]]을 지킴으로 인해 DB에서 가장 중요한 덕목인 [[데이터 정합성(Data Consistency)]] 지키는데 특화됨.
![[ACID#📌 상세]]
### 성능 최적화: 인덱스와 정규화
실무에서 가장 많이 고민하게 되는 부분입니다.
- **정규화(Normalization):** 데이터 중복을 최소화하고 구조를 체계화하는 과정입니다. (1NF, 2NF, 3NF 등)
- **인덱스(Index):** 책의 색인처럼 데이터를 빠르게 찾기 위한 구조입니다. B-Tree 구조가 대표적이죠.
- **실행 계획(Execution Plan):** 작성한 SQL이 내부적으로 어떻게 실행되는지 분석하여 병목을 찾아내는 도구입니다.
---
## 주의
> [!warning] 하지만 데이터 정합성의 경우 RDBMS의 고유한 특징이라고 하기엔 무리가 있다.
왜냐하면 DB라면 데이터 정합성을 지켜야하는게 당연하기 때문이다.
( 얼마나 정합성을 강하게 지켜서 성능에서 손해를 보느냐, 약간 덜 엄격하게 지키고 성능에서 이점을 얻느냐가 차라리 더 중요하다. )
## RDBMS의 본질
> [!note] RDBMS의 본질: "구조적 설계를 통한 중복 제어"
- **정규화(Normalization):** 데이터 간의 관계를 분석해 원자 단위로 쪼개고, 중복을 원천 차단하는 프로세스입니다.
- **무결성 제약 조건:** DB 엔진 차원에서 외래키(FK), 유니크(Unique) 제약 등을 통해 "중복되거나 잘못된 관계가 맺어지는 것"을 물리적으로 막습니다.
- **저장 효율성:** 중복을 최소화하기 때문에 저장 공간을 효율적으로 쓰고, 데이터 수정 시 한 곳만 고치면 되는 구조를 만듭니다.
+72
View File
@@ -0,0 +1,72 @@
---
id: RS-232 vs 이더넷 20260504
created: 2026-05-04 09:58
tags:
aliases:
---
## 💡 생각
결과적으로 RS-232와 이더넷사이에는 약 8,000배의 속도차이가 발생된다고 한다.
설치비용도 이더넷이 훨씬 더 저렴하다고 한다.
이래도 RS-232를 쓴다고?
[[RS-232가 이더넷을 따라잡을 수 없는 이유]]
---
> [!question]
> Q. 왜 rs-232랑 이더넷은 속도의 차이가 나는거야? 어차피 둘다 똑같이 전기적인 신호의 전달인거 아니야?
> A. 정말 좋은 질문입니다! 본질적으로는 둘 다 구리선 안에서 전압의 변화(전기 신호)를 이용하는 것은 맞지만, 그 전기를 **얼마나 정교하고 빠르게 제어하느냐**에서 결정적인 차이가 발생합니다.
---
### 1. 전압의 폭과 물리적 부담 (관성)
전압을 바꾸는 것은 마치 수도꼭지를 틀고 잠그는 것과 비슷합니다.
- **[[RS-232]]:** 전압의 진폭이 큽니다(보통 -15V에서 +15V 사이). 전압을 이만큼 높였다 낮췄다 하려면 시간이 걸립니다. 즉, 신호를 한 번 바꿀 때마다 물리적인 '관성'이 큽니다.
- **이더넷:** 아주 낮은 전압(약 1V~2.5V 내외)을 사용합니다. 전압 폭이 작기 때문에 아주 미세하고 빠르게 전압을 튀길 수 있습니다. 덕분에 1초에 훨씬 많은 신호를 보낼 수 있는 것이죠.
***** 즉, 수도꼭지를 아주 조금만 틀고잠궈도 되는 이더넷이 많이 틀고 많이 잠궈야하는 RS-232보다 물리적인 부담이 훨씬 적다.
### 2. 노이즈를 처리하는 방식 (차동 신호)
멀리, 그리고 빠르게 신호를 보내려면 주변의 전기적 잡음(노이즈)을 이겨내야 합니다.
- **[[RS-232]] (싱글 엔디드):** 선 하나에 전기를 흘리고 그 전압 값만 측정합니다. 주변에서 노이즈가 끼어들면 신호가 쉽게 변조됩니다. 그래서 속도를 높이면 에러가 너무 많이 납니다.
- **이더넷 ([[차동 신호(Differential Signaling)]]):** 선 두 개를 꼬아서 사용합니다. 한쪽 선에 `+`를 보내면 다른 쪽엔 `-`를 보냅니다. 노이즈가 발생해도 두 선에 동시에 영향을 주므로, 두 신호의 '차이'를 계산하면 노이즈만 쏙 제거됩니다. 이 기술 덕분에 노이즈 걱정 없이 엄청난 속도로 신호를 쏠 수 있습니다.
***** 노이즈 발생 걱정 없이 데이터를 송,수신 할 수 있다.
### 3. 신호를 만드는 '언어'의 정교함
전압을 단순히 `높다(1)`, `낮다(0)`로만 구분하는지, 아니면 더 복잡하게 약속하는지의 차이입니다.
- **RS-232:** 단순합니다. 전압이 높으면 0, 낮으면 1(혹은 그 반대) 식으로 아주 기초적인 규칙만 씁니다.
- **이더넷:** 전압의 변화뿐만 아니라 위상(Phase) 등을 조합한 고도의 인코딩 방식을 씁니다. 한 번의 전기 신호 변화에 여러 비트의 데이터를 담는 '압축 기술'이 들어가 있어 같은 전기 신호라도 실어나르는 데이터 양이 훨씬 많습니다.
> [!question]
> Q. 신호를 만드는 '언어'의 정교함 이거는 만약에 rs-232도 고도로 발달한 인코딩 방식을 개발해서 사용했다면 어느정도는 따라갈 수 있는 부분이었을까?
> A. 매우 날카로운 질문입니다! 결론부터 말씀드리면, **인코딩 기술을 도입하면 RS-232도 지금보다는 훨씬 빨라질 수 있습니다.** 하지만 근본적으로 이더넷을 **'완벽히'** 따라잡기는 어렵습니다.
> [!note]
결국 **똑같은 전기**를 쓰더라도, 더 적은 힘으로(저전압), 더 영리하게 노이즈를 방어하면서(차동 신호), 더 정교한 규칙(인코딩)으로 소통하기 때문에 이더넷이 압도적으로 빠른 것입니다.
>
### 왜 RS-232는 차동 신호가 안 될까요?
RS-232는 선 하나($A$)와 접지(Ground, $0V$)를 비교합니다.
- **보낼 때:** $A$선에 $10V$를 보냅니다. (기준은 $0V$니까 차이는 $10V$)
- **노이즈 발생:** $A$선에만 $+5V$ 노이즈가 낍니다. ($15V$가 됨)
- **받을 때:** 받는 쪽은 여전히 $0V$를 기준으로 측정하므로, 데이터가 $15V$로 변질된 채 들어옵니다. 노이즈를 걸러낼 방법이 없습니다.
+57
View File
@@ -0,0 +1,57 @@
---
id: "RS-232 20260504"
created: "2026-05-04 09:37"
tags:
aliases:
---
## 💡 생각
SECS 통신에서 사용하는 그것을 말함.
아직도 RS-232를 쓰는곳이 종종 있음.
---
## 📑 개념
컴퓨터와 주변 장치(모뎀, 마우스, 산업용 장비 등) 간에 데이터를 주고받기 위해 만들어진 **직렬(Serial) 통신 표준**입니다. 1960년대에 처음 등장했음에도 불구하고, 신뢰성이 높고 구조가 간단하여 오늘날까지도 산업 현장에서 널리 사용되고 있습니다.
---
## 📌 주요 특징
- **직렬 통신:** 데이터를 한 번에 1비트씩 순차적으로 전송합니다. 병렬 통신에 비해 배선이 단순하다는 장점이 있습니다.
- **전압 기반 신호:** 논리 상태를 전압의 차이로 구분합니다.
- **논리 0 (Space):** $+3\text{V} \sim +15\text{V}$
- **논리 1 (Mark):** $-3\text{V} \sim -15\text{V}$ (휴지 상태)
- **전송 거리:** 표준상으로는 약 15m(50피트) 정도까지 권장되지만, 통신 속도를 낮추면 더 먼 거리도 가능합니다.
- **커넥터 형태:** 과거에는 25핀(DB-25)이 쓰였으나, 현재는 9핀(DE-9 또는 DB-9) 형태가 가장 흔합니다.
## 통신 방식 (프레임 구조)
RS-232는 **비동기식(Asynchronous)** 통신을 주로 사용합니다. 즉, 송신측과 수신측이 공통된 클록(Clock)을 공유하지 않고, 약속된 속도(Baud Rate)에 맞춰 데이터를 해석합니다.
(Baud Rate: 송신자와 수신자가 미리 **초당 몇 비트를 보낼지** 약속한 것)
1. **Start Bit:** 통신의 시작을 알리는 1비트 (Low 전압).
2. **Data Bits:** 실제 데이터 (보통 7~8비트).
3. **Parity Bit:** 오류 검출을 위한 옵션 비트.
4. **Stop Bit:** 통신의 종료를 알리는 비트 (1~2비트, High 전압).
RS-232는 보통 **전이중(Full-Duplex)** 방식입니다. 즉, 보내는 선(TX)과 받는 선(RX)이 분리되어 있습니다.
- 상대방이 데이터를 다 보낼 때까지 기다렸다가 내가 보내는 방식(Half-Duplex)도 가능하지만,
- 하드웨어적으로 선이 따로 있기 때문에 **상대방이 데이터를 보내는 중에도 내가 보낼 데이터가 있다면 동시에 Start Bit를 던지고 데이터를 보낼 수 있습니다.**
## 요약
- **Start Bit:** 수신기의 타이머를 가동시키는 스위치.
- **데이터 읽기:** 약속된 보레이트의 '절반' 지점마다 전압을 체크해서 0인지 1인지 결정.
- **Stop Bit:** 다음 데이터의 Start Bit를 제대로 인식할 수 있도록 선로를 대기 상태(High)로 복귀시키는 최소한의 여유 시간.
![[Pasted image 20260504100456.png]]
@@ -0,0 +1,49 @@
---
id: "RS-232가 이더넷을 따라잡을 수 없는 이유 20260504"
created: "2026-05-04 10:16"
tags:
aliases:
---
## 💡 생각
가성비를 위해 고안된 RS-232에 이더넷에서 사용하는 고도의 인코딩기술 등을 적용하려면 RS-232의 가장 큰 장점이었던 가성비가 사라지게 된다.
기술적으로도 싱글 엔디드(선 하나로 측정)방식에서 어떻게 할 수 없는 노이즈 현상이 RS-232의 고도화에 가장 큰 걸림돌이기도 하다.
---
### 1. 인코딩으로 얻을 수 있는 이득 (언어의 효율성)
RS-232도 현대적인 인코딩(예: QAM 등)을 사용한다면, 한 번의 전기 변화에 1비트가 아니라 4비트, 8비트를 담을 수 있습니다. 실제로 과거 전화선을 쓰던 **다이얼업 모뎀**이 이런 방식으로 속도를 높여왔습니다.
- 하지만 인코딩을 고도화할수록 **신호가 아주 미세한 차이**를 구분해야 합니다.
- 예를 들어, 전압을 0V/5V 두 개로 나누던 걸 0.1V 단위로 쪼개서 50개의 신호를 만든다고 가정해 보세요.
### 2. 발목을 잡는 '물리적 노이즈' (도로의 상태)
여기서 앞서 공부한 **노이즈** 문제가 다시 등장합니다.
- 고도의 인코딩은 '미세한 전압 차이'를 읽어내는 기술입니다.
- 그런데 RS-232는 노이즈에 취약한 **싱글 엔디드(선 하나로 측정)** 방식이죠.
- 주변에서 노이즈가 조금만 튀어도 0.1V 단위로 쪼개놓은 정교한 신호들이 순식간에 뭉개져 버립니다.
즉, **아무리 고급 언어(인코딩)를 개발해도, 전달 매체(전선)가 너무 시끄러우면(노이즈) 상대방이 알아들을 수가 없는 것**입니다.
### 3. '차동 신호'라는 인프라의 차이
이더넷이 고도의 인코딩을 마음껏 쓸 수 있는 이유는 [[차동 신호(Differential Signaling)]] 덕분에 바닥에 깔린 노이즈를 싹 제거하여 **깨끗한 도화지** 상태를 만들었기 때문입니다.
- **이더넷:** 도화지가 깨끗하니 아주 얇은 펜으로 정밀하게 글씨(인코딩)를 써도 잘 읽힙니다.
- **[[RS-232]]:** 도화지에 이미 연필 자국(노이즈)이 가득해서, 굵은 매직으로 크게 써야만 겨우 읽을 수 있는 상태입니다.
### 4. 하드웨어 설계의 단순성 (경제성)
RS-232는 애초에 "싸고 단순하게 만들자"가 목적이었습니다.
- 복잡한 인코딩을 처리하려면 CPU나 전용 칩셋이 신호를 실시간으로 계산해서 복원해야 합니다.
- RS-232 장치에 그런 비싼 칩을 넣을 바에는, 차라리 그 돈으로 **이더넷 칩**을 하나 다는 게 훨씬 싸고 빠릅니다. 이미 이더넷은 대량 생산으로 가격이 매우 낮아졌으니까요.
@@ -0,0 +1,58 @@
---
id: 게이트웨이(Gateway) 20260428
created: 2026-04-28 14:25
tags:
- network
aliases:
---
## 💡 생각
서로 다른 네트워크간의 통신은 무조건 게이트웨이를 통해 진행된다.
내부를 먼저 확인하고 내부에 그 ip에 해당되는 녀석이 없으면 게이트웨이를 통해 외부로 나아간다.
이 때 가장 먼저 확인하는게 [[라우팅 테이블(Routing Table)]]이다.
---
## 📑 개념
서로 다른 네트워크를 연결해 주는 '출입구' 역할을 하는 장치나 소프트웨어를 말합니다.
컴퓨터 네트워크는 서로 다른 통신 프로토콜(규약)을 사용하거나 구조가 다른 경우가 많은데, 게이트웨이는 이들 사이에서 데이터를 주고받을 수 있도록 **통역사** 역할을 수행합니다.
## ## 1. 게이트웨이의 핵심 역할
네트워크의 경계에 위치하여 다음과 같은 기능을 수행합니다.
- **프로토콜 변환:** 서로 다른 방식의 네트워크가 소통할 수 있도록 신호를 변환합니다.
- **데이터 전달:** 내부 네트워크에서 외부(인터넷)로 나가는 모든 데이터는 반드시 게이트웨이를 통과해야 합니다.
- **보안:** 외부로부터 들어오는 허가되지 않은 접속을 차단하는 벽의 역할을 하기도 합니다.
---
## 2. 실생활 예시: 아파트 현관문
게이트웨이를 가장 쉽게 이해하는 방법은 **아파트의 현관문**에 비유하는 것입니다.
- **내부 네트워크:** 우리 집 안 (가족끼리 자유롭게 대화하고 이동 가능)
- **외부 네트워크:** 집 밖 (복도, 엘리베이터, 거리)
- **게이트웨이:** 현관문 (집 밖으로 나가거나 외부인이 들어올 때 반드시 거쳐야 하는 유일한 통로)
컴퓨터가 인터넷상의 웹사이트에 접속하려고 할 때, 먼저 자신의 네트워크 안에 해당 주소가 있는지 확인합니다. 없다면 일단 기본 게이트웨이(Default Gateway)로 데이터를 보낸 뒤 외부 세계로 나가게 됩니다.
## 3. 기본 게이트웨이 (Default Gateway)
우리가 사용하는 PC나 스마트폰 설정에서 흔히 볼 수 있는 용어입니다.
- 보통 가정에서는 유무선 공유기(루터)의 IP 주소가 기본 게이트웨이 주소가 됩니다.
- 내부망에서 해결할 수 없는 목적지(예: 구글, 네이버 등)로 가는 데이터는 무조건 이 기본 게이트웨이 주소로 전달됩니다.
보통 0.0.0.0에 위치하며 보통은 [[라우터(Router)]]를 가리킨다.
앞서봤듯 통신연결 시도가 발생되면 가장먼저 내부의 같은 네트워크망에 그 ip주소에 해당되는 요소가 있는지 확인하고 없으면 라우팅 테이블을 확인해본다. 거기도 없을 경우 기본 게이트웨이로 가게 되는데 보통 기본 게이트웨이는 라우터로 설정되어 있다.
[[라우터(Router)]]를 통해 연결시도 한 ip로 접근이 되는지 확인해보고 최대한 통신 연결을 시도해보다가 성공,실패하게 된다.
---
@@ -0,0 +1,42 @@
---
id: 관계형 데이터베이스(RDBMS)의 한계 20260420
created: 2026-04-20 10:08
tags:
aliases:
---
## 💡 생각
서버의 수평적확장이 어려움 + 관계가 복잡해지면 조인연산이 느려질 수 있음
---
## 1. 유연하지 못한 스키마 (Rigid Schema)
RDBMS는 데이터를 저장하기 전에 미리 테이블 구조(Schema)를 정의해야 합니다.
- **변경의 어려움:** 서비스 운영 중에 데이터 구조를 변경하려면 `ALTER TABLE`과 같은 작업을 수행해야 하는데, 데이터 양이 많을 경우 시스템 부하가 크고 서비스 중단이 발생할 수 있습니다.
- **비정형 데이터 처리:** SNS 포스트, 로그 파일, 이미지 메타데이터 등 구조가 일정하지 않은 데이터를 담기에는 부적합합니다.
## 2. 수평적 확장(Scaling-out)의 어려움
RDBMS는 기본적으로 단일 서버의 성능을 높이는 **수직적 확장(Scale-up)** 에 최적화되어 있습니다.
- **분산 저정의 복잡성:** 여러 대의 서버에 데이터를 나누어 저장(Sharding)할 수 있지만, 이 경우 데이터 간의 일관성을 유지하고 조인(Join) 연산을 수행하는 것이 매우 까다로워집니다.
- **비용 문제:** 고성능의 단일 서버를 구축하는 비용은 서버를 여러 대 늘리는 비용보다 기하급수적으로 비싸집니다.
## 3. 복잡한 관계와 조인(Join) 성능 저하
데이터 간의 관계가 복잡해질수록 여러 테이블을 연결하는 **조인 연산**이 많아집니다.
- **성능 병목:** 수백만 건 이상의 데이터가 포함된 테이블들을 빈번하게 조인하면 쿼리 실행 속도가 급격히 느려집니다.
- **객체-관계 불일치 (Impedance Mismatch):** 객체지향 프로그래밍 언어의 구조와 RDBMS의 테이블 구조가 서로 달라, 이를 변환하는 과정(ORM 등)에서 복잡성이 증가하고 성능 손실이 발생합니다.
## 4. 대용량 데이터 처리 속도
초당 수만 건 이상의 쓰기 작업이 발생하는 실시간 서비스나 테라바이트(TB) 단위의 데이터를 분석하는 환경에서는 RDBMS의 ACID 트랜잭션 보장 기능이 오히려 독이 될 수 있습니다.
- **잠금(Locking) 현상:** 데이터의 일관성을 위해 특정 행이나 테이블을 잠그는 과정에서 대기 시간이 발생하여 전체적인 처리량이 떨어집니다.
@@ -0,0 +1,30 @@
---
id: "데이터 정합성(Data Consistency) 20260420"
created: "2026-04-20 08:48"
tags:
aliases:
---
## 💡 생각
저장된 데이터가 얼마나 정확하냐를 생각하면 될 것 같음
정합성이 깨진건 뭔가 데이터가 정확하지 않다고 간단하게 생각하자.
---
## 📑 개념
데이터베이스나 시스템 내의 데이터들이 서로 모순 없이 일관되게 유지되는 상태를 의미합니다. 쉽게 말해, **어디에서 데이터를 조회하더라도 값이 같고 논리적으로 어긋남이 없는 상태**를 말하죠.
단순히 데이터가 정확한지(무결성)를 넘어, 분산된 시스템이나 여러 테이블 간의 관계에서 **데이터가 일치하는가**에 초점을 맞춥니다.
## 정합성이 중요한 이유
### **신뢰도 저하 방지**
사용자가 내 정보 페이지에서는 '주소 A'를 보는데, 주문 결제 페이지에서는 옛날 주소인 '주소 B'가 나온다면 시스템에 대한 신뢰가 깨지게 됩니다.
### **비즈니스 로직 오류 차단**
재고 수량 데이터의 정합성이 맞지 않으면, 실제 물건은 없는데 주문이 접수되는 등의 실무적인 문제가 발생합니다.
## 정합성을 지키는 방법: [[트랜잭션(Transaction)]]
데이터베이스에서는 [[ACID]] 원칙을 통해 [[데이터 정합성(Data Consistency)]]을 보장합니다. 그중 핵심은 [[트랜잭션(Transaction)|트렌젝션]]입니다.
( [[ACID]]원칙을 지키면 정합성이 보장된다. )
---
@@ -0,0 +1,43 @@
---
id: 데이터 조인이 느린 이유 20260420
created: 2026-04-20 10:55
tags:
aliases:
---
## 💡 생각
조인은 무거운 연산이 맞고 인덱스를 잘 걸어야 그나마 좀 빠릿빠릿하게 동작한다.
---
## 📑 개념
관계형 데이터베이스(RDBMS)에서 **조인(Join)** 이 무거운 연산으로 취급되는 이유는 단순히 데이터를 합치는 것을 넘어, 컴퓨터 자원(CPU, Memory, I/O)을 집약적으로 사용하기 때문입니다.
## 📌 상세
### 1. 데이터의 곱집합(Cartesian Product) 기반 탐색
기본적으로 조인은 두 테이블의 행들을 조합하는 과정입니다. 최악의 경우, 한쪽 테이블의 행 개수가 $M$이고 다른 쪽이 $N$이라면 $M \times N$만큼의 연산이 필요할 수 있습니다.
- **비교 횟수:** 적절한 인덱스가 없다면, 시스템은 모든 경우의 수를 하나하나 대조해야 합니다. 데이터가 커질수록 이 비교 횟수는 기하급수적으로 늘어납니다.
### 2. 디스크 I/O 발생
데이터베이스 성능의 가장 큰 병목은 **디스크 읽기**입니다.
- 조인을 수행하기 위해 서로 다른 테이블의 데이터 블록을 메모리(Buffer Pool)로 끌어올려야 합니다.
- 데이터가 너무 커서 메모리 공간이 부족하면, 중간 결과를 다시 디스크에 썼다가 읽는 **Temporary I/O**가 발생하여 속도가 급격히 느려집니다.
> [!question]
> Q. Temporary I/O가 일종의 스왑메모리같은 그런 느낌인거야?
> A. 네, 정확한 비유입니다. **Temporary I/O**는 데이터베이스 입장에서 일종의 **'디스크 기반 스왑(Swap)'** 역할을 한다고 이해하시면 됩니다.
데이터를 처리하려면 메모리에 올려야하는데 처리해야하는 데이터가 너무 커서 db에 할당된 메모리 크기를 초과할 경우 DB는 Temporary I/O 처리를 하게된다.
이게 결국 하드디스크에 데이터를 기록해뒀다가 다시 메모리로 올리는 작업을 의미하기 때문에 속도에 굉장히 큰 악영향을 미치게 된다.
### 3. 인덱스 관리 및 랜덤 액세스
인덱스를 타고 데이터를 찾는 과정에서도 비용이 발생합니다.
- **랜덤 액세스:** 인덱스를 통해 테이블의 실제 데이터 위치를 찾아갈 때, 디스크의 여기저기를 흩어져서 읽어야 하는 '랜덤 액세스'가 발생하며 이는 연속된 데이터를 읽는 것보다 훨씬 느립니다.
---
+37
View File
@@ -0,0 +1,37 @@
---
id: "동기(Synchronous) 20260504"
created: "2026-05-04 09:32"
tags:
aliases:
---
## 💡 생각
영어단어인 싱크의 뜻을 생각하자. 상호간의 싱크를 맞춘다 는 의미로 받아들이면 된다.
그게 통신에서의 수신자,송신자 사이던, 프로그래밍에서의 호출자,함수 사이에서든..
---
## 📑 개념
**송신자와 수신자, 혹은 호출자와 실행자가 같은 시간축 위에서 발을 맞춘다**는 뜻
( 상호간에 싱크를 맞춘다 )
---
## 1. 통신에서의 동기: "우리 같은 박자에 맞추자"
말씀하신 대로 **내가 보낼 때 네가 정확히 들어야 한다**는 의미입니다.
- 이를 위해 두 장치는 똑딱거리는 **클럭(Clock)** 신호를 공유합니다.
- 클럭이 '탁' 올라갈 때 송신자는 데이터를 던지고, 수신자는 그 짧은 순간에 데이터를 낚아챕니다.
- **비유:** 오케스트라 지휘자(클럭)의 손짓에 맞춰 연주자들이 동시에 소리를 내는 것과 같습니다.
---
## 2. 프로그래밍에서의 동기: "너 끝날 때까지 나 아무것도 안 해"
말씀하신 **다른 거 하지 말고 기다려라**라는 해석이 완벽합니다. 전문 용어로는 이를 블로킹(Blocking)이라고도 부릅니다.
- 함수가 호출되면 제어권이 그 함수로 넘어가고, 그 함수가 값을 반환(Return)할 때까지 호출한 쪽의 실행 흐름이 멈춰 있습니다.
- **비유:** 편의점 계산대에서 앞 사람이 계산을 마칠 때까지 뒷사람이 줄을 서서 가만히 대기하는 상황입니다.
+61
View File
@@ -0,0 +1,61 @@
---
id: 라우터(Router) 20260428
created: 2026-04-28 14:32
tags:
- network
aliases:
---
## 💡 생각
랜선으로 연결된 인터넷에서 다음 목적지가 어디인지 알려주는 중간 거점의 역할을 하는 장치
---
## 📑 개념
라우터(Router)는 서로 다른 네트워크를 연결하고, 데이터 패킷이 목적지까지 가는 **최적의 경로(Route)를 찾아주는** 길잡이 역할을 하는 네트워크 장비입니다.
## 1. 라우터의 핵심 기능
라우터의 역할은 크게 두 가지로 나뉩니다.
- **경로 결정 (Routing):** 목적지 IP 주소를 확인하고, 자신의 [[라우팅 테이블(Routing Table)]]을 참조하여 "어떤 길로 가야 가장 빠르고 정확한지" 판단합니다. 내비게이션과 같은 역할입니다.
- **패킷 전달 (Forwarding):** 경로가 결정되면 해당 데이터를 다음 인터페이스(출구)로 실제로 옮겨줍니다.
## 2. 라우터의 작동 원리
라우터는 내부에 라우팅 테이블(Routing Table)이라는 일종의 지도를 가지고 있습니다.
1. **패킷 수신:** 데이터(패킷)가 라우터에 도착합니다.
2. **주소 확인:** 라우터는 패킷에서 목적지 IP 주소를 읽어냅니다.
3. **경로 검색:** 라우팅 테이블에서 이 IP로 가려면 어디로 가야 하는지 찾습니다.
4. **전송:** 가장 적합한 경로로 패킷을 밀어 넣어줍니다.
## 3. 게이트웨이 vs 라우터: 차이점이 뭐야?
질문하신 흐름에서 헷갈릴 수 있는 부분인데, 실무에서는 거의 같은 의미로 쓰이기도 합니다.
- **라우터:** 장비 그 자체를 부르는 이름입니다. (하드웨어적 관점)
- **게이트웨이:** 네트워크의 출입구라는 '역할'을 부르는 이름입니다. (기능적 관점)
> [!info] 우리가 집에서 쓰는 **공유기**는 '라우터' 장비이면서, 동시에 우리 집 네트워크의 '기본 게이트웨이' 역할을 수행하고 있는 것입니다.
## 4. 왜 라우터가 필요한가요?
라우터가 없다면 우리는 옆방에 있는 컴퓨터와는 통신할 수 있어도, 멀리 떨어진 구글이나 네이버 서버와는 소통할 수 없습니다.
- **네트워크 분리:** 너무 많은 기기가 하나의 네트워크에 있으면 트래픽이 몰려 속도가 느려집니다. 라우터는 네트워크를 적절히 쪼개 관리 효율을 높입니다.
- **보안:** 외부 네트워크와 내부 네트워크를 분리하여 1차적인 방어선 역할을 합니다.
> [!question]
> Q. 라우터는 물리적인 장치야? 아니면 소프트웨어야?
> A. 정답부터 말씀드리면, **라우터는 하드웨어(물리적 장치)이기도 하고 소프트웨어이기도 합니다.**
일단은 라우터는 하나의 장치다고 생각하자. (소프트웨어가 탑제된 장치 그 자체)
---
@@ -0,0 +1,54 @@
---
id: "라우팅 테이블(Routing Table) 20260428"
created: "2026-04-28 14:16"
tags:
aliases:
---
## 💡 생각
[[라우팅(Routing)]]이 뭔지 알면 라우팅 테이블도 같이 알 수 있다.
---
## 📑 개념
네트워크에서 라우팅 테이블(Routing Table)은 데이터 패킷이 목적지까지 가장 효율적인 경로로 전달될 수 있도록 경로 정보를 저장해둔 이정표와 같은 데이터베이스입니다.
라우터나 컴퓨터와 같은 네트워크 장비는 패킷을 받으면 이 테이블을 참조하여 다음 어디로 보낼지 결정합니다.
## 1. 라우팅 테이블의 주요 구성 요소
라우팅 테이블은 보통 다음과 같은 정보들을 포함하고 있습니다.
- **목적지(Destination):** 패킷이 최종적으로 도달해야 할 IP 주소나 네트워크 대역입니다.
- **서브넷 마스크(Netmask):** 목적지 주소의 범위를 정의합니다.
- **게이트웨이(Gateway) / 다음 홉(Next Hop):** 목적지에 가기 위해 거쳐야 하는 다음번 장치의 IP 주소입니다.
- **인터페이스(Interface):** 패킷을 내보낼 물리적 또는 논리적 포트(예: eth0, Wi-Fi 등)입니다.
- **메트릭(Metric):** 경로의 우선순위를 정하는 값입니다. 여러 경로가 있을 경우 이 값이 낮을수록 더 좋은 경로로 판단합니다.
---
## 2. 경로 결정 방식 (작동 원리)
패킷이 도착하면 라우터는 다음과 같은 과정을 거칩니다.
1. **가장 구체적인 경로 탐색 (Longest Prefix Match):** 목적지 IP와 가장 많이 일치하는 서브넷 마스크를 가진 경로를 먼저 선택합니다.
2. **디폴트 게이트웨이(Default Gateway):** 테이블에 일치하는 특정 경로가 없을 경우, 모든 외부 트래픽을 처리하는 0.0.0.0 경로(기본 관문)로 보냅니다.
3. **패킷 전달:** 결정된 인터페이스를 통해 패킷을 다음 지점으로 송신합니다.
---
## 3. 라우팅 테이블의 관리 방식
라우팅 테이블에 경로가 추가되는 방식은 크게 두 가지로 나뉩니다.
- **정적 라우팅 (Static Routing):** 관리자가 직접 경로 정보를 입력하는 방식입니다. 보안성이 높고 리소스 소모가 적지만, 네트워크 변화에 자동으로 대응하지 못합니다.
- **동적 라우팅 (Dynamic Routing):** RIP, OSPF, BGP 같은 라우팅 프로토콜을 통해 라우터끼리 서로 정보를 교환하며 테이블을 자동으로 업데이트하는 방식입니다.
---
+23
View File
@@ -0,0 +1,23 @@
---
id: 라우팅(Routing) 20260428
created: 2026-04-28 14:15
tags:
- network
- route
aliases:
---
## 💡 생각
이곳에 하나의 생각 또는 아이디어를 작성합니다.
---
## 📑 개념
네트워크에서 **라우팅**이란 패킷(데이터의 전송 단위)이 출발지에서 목적지까지 갈 수 있는 **최적의 경로를 설정하고, 그 경로를 따라 데이터를 전달하는 과정**을 의미합니다.
## 📌 상세
라우팅은 단순히 길을 찾는 것에 그치지 않고, 다음과 같은 핵심적인 작업을 수행합니다.
- **경로 결정 (Path Determination):** [[라우팅 테이블(Routing Table)]]이라는 지도 정보를 참조하여, 수많은 갈림길 중 어떤 길로 데이터를 보낼지 결정합니다.
- **패킷 포워딩 (Packet Forwarding):** 결정된 경로에 따라 실제로 패킷을 다음 장비(넥스트 홉, Next Hop)로 넘겨주는 물리적인 동작입니다.
---
@@ -0,0 +1,10 @@
| **대상** | **금액 조건** | **결제 라인 (순서)** | **합의 담당자** |
| ----------- | --------- | ----------------------------------- | ------------- |
| **1. 팀원** | 30만원 이하 | 본인 → PM/영업대표 → 팀장 → 사업부장 | 문새별, 김성민 |
| | 30만원 초과 | 본인 → PM/영업대표 → 팀장 → 사업부장 → **대표이사** | 문새별, 김성민, 이훈주 |
| **2. 팀장** | 30만원 이하 | 본인 → 사업부장 | 문새별, 김성민 |
| | 30만원 초과 | 본인 → 사업부장 → **대표이사** | 문새별, 김성민, 이훈주 |
| **3. 사업부장** | 전액 | 본인 → **대표이사** | 문새별, 김성민, 이훈주 |
게시판 경영기획실 및 경영지원실 업무분장 및 결재라인 안내(2026. 01. 01) 참고하시면 됩니다.
- 날짜는 달라졌을수도 있음
+32
View File
@@ -0,0 +1,32 @@
---
id: "부가세여부 20260427"
created: "2026-04-27 13:16"
tags:
aliases:
---
---
## 📑 개념
회계 전표를 생성할 때 **부가세 여부**(또는 매입세액 공제 여부)는 해당 지출이 부가가치세 신고 시 **세금을 공제(환급)받을 수 있는 항목인지**를 결정하는 아주 중요한 설정입니다.
단순히 금액에 부가세가 포함되어 있느냐 아니냐를 넘어, 다음과 같은 의미를 갖습니다.
## 📌 상세
일반적으로 '부가세 여부'에 체크를 하거나 '여'로 선택한다는 것은, **해당 거래에서 발생한 부가세를 별도의 부가세대급금(자산) 계정으로 분리하겠다**는 뜻입니다.
- **체크한 경우:** "이 지출은 사업과 관련이 있고, 세법상 공제가 가능한 항목이므로 나중에 세무서에서 부가세를 돌려받겠다."라고 선언하는 것입니다.
- **체크하지 않은 경우(불공제/면세):** 부가세가 포함된 결제더라도 사업과 무관하거나(접대비 등), 면세 항목이라서 공제를 받지 못할 때 사용합니다. 이 경우 부가세는 별도로 분리하지 않고 전액 비용(예: 복리후생비)으로 처리합니다.
### 실무적인 판단 기준 (어떨 때 체크하나요?)
모든 결제에 체크하는 것은 아닙니다. 아래 기준을 참고해 보세요.
- **체크해야 하는 경우 (공제):** 식대(직원용), 사무용품 구입, 업무용 택시비, 소모품비 등 사업 운영에 직접 필요한 지출.
- **체크하지 않는 경우 (불공제):**
- **접대비:** 거래처 선물이나 식사 비용.
- **면세 항목:** 꽃 배달(화환), 농산물 구입, 도서 구입 등(애초에 부가세가 0원임).
- **비영업용 승용차 관련:** 일반 승용차의 기름값이나 수리비(경차나 9인승 이상 제외).
+79
View File
@@ -0,0 +1,79 @@
---
id: 분개(分介) 20260413
created: 2026-04-13 11:08
tags:
aliases:
---
## 💡 생각
돈이 나가고 들어오는것을 나누어서 기록하자. (누락없이 정확하게 기록하기 위해서)
---
## 📑 개념
### 분개(分介): "나누어서 기록하기"
**분개**를 한자로 풀면 **나눌 분(分)**, **낄 개(介)** 자를 씁니다. 즉, 하나의 거래를 **두 부분(왼쪽과 오른쪽)** 으로 나누어 장부에 끼워 넣는다는 뜻이에요.
## 📌 상세
- **쉽게 생각하면?** 거래가 일어났을 때 **원인**과 **결과**를 양쪽에 적어주는 과정입니다.
- 예: 편의점에서 1,000원짜리 물을 샀다면?
- **결과:** 내 손에 물이 생겼다.
- **원인:** 내 주머니에서 1,000원이 나갔다.
- 이렇게 양쪽을 다 기록해야 나중에 돈이 어디로 새 나갔는지 정확히 알 수 있거든요.
### . 차변과 대변: 그냥 "왼쪽"과 "오른쪽"
차변(借邊)과 대변(貸邊)이라는 단어 자체에 너무 의미를 두지 마세요. 그냥 회계 나라의 약속입니다.
- **차변 (왼쪽):** 나에게 **들어온 것** (자산의 증가, 비용의 발생)
- **대변 (오른쪽):** 나에게서 **나간 것** (자산의 감소, 수익의 발생)
---
> [!example]
### 예시 이미지
![[Pasted image 20260413110952.png]]
보여주신 이미지는 아주 전형적인 **분개전표**의 입력 화면입니다. 앞서 말씀드린 차변과 대변이 어떻게 쓰이는지 이 표를 통해 하나씩 짚어드릴게요.
---
### 1. 한 세트의 거래 (행번호 1번과 2번)
이 표에서 가장 중요한 점은 **1번 행과 2번 행이 합쳐져서 하나의 사건**을 나타낸다는 것입니다. 기차표를 사고 40,500원을 쓴 상황을 회계적으로 기록한 것이죠.
### 2. 차변금액 (왼쪽) - 행번호 1번
- **금액:** 40,500원
- **계정과목:** 여비교통비
- **의미:** 내가 돈을 **어디에 썼는지(이유)** 를 나타냅니다.
- **해석:** 출입관리 업무협의를 위해 기차표를 사는 데 40,500원이라는 **비용이 발생**했으므로 왼쪽에 적었습니다.
### 3. 대변금액 (오른쪽) - 행번호 2번
- **금액:** 40,500원
- **계정과목:** 여비교통비 (보통 이 자리에는 현금, 보통예금, 미지급금 등이 들어오지만, 이미지에서는 항목 정리를 위해 같은 과목을 쓰신 것 같네요.)
- **의미:** 돈이 **어디서 나갔는지(출처)** 를 나타냅니다.
- **해석:** 40,500원이라는 **자산이 빠져나갔기** 때문에 오른쪽에 적었습니다.
### 4. 왜 똑같은 금액을 양쪽에 적었나요? (대차평균의 원리)
이미지의 하단을 보시면 **차변 합계**와 **대변 합계**가 둘 다 40,500원으로 똑같아야 합니다.
- 만약 차변은 40,500원인데 대변이 0원이라면? "돈은 썼는데 어디서 났는지 모른다"는 뜻이 되어 오류가 발생합니다.
- 이렇게 양쪽의 무게를 맞춰줌으로써 **장부에 실수가 없음을 증명**하는 것입니다.
+45
View File
@@ -0,0 +1,45 @@
---
id: "분개전표 20260413"
created: "2026-04-13 11:04"
tags:
aliases:
---
## 💡 생각
전표는 돈이 빠져나간 이력만 적혀있으니까 상세하게 알 수가 없음.
전표에 차변과 대변이라는 두가지 구분을 더해 전표를 좀 더 상세하게 적는 방법을 의미
그냥..
5만원이 기차표값으로 빠졌다. (차변)
5만원이 카드결제대금으로 나갈거다. (대변)
둘을 합치면 카드결제대금으로 5만원이 나갈건데 그 5만원은 기차표값이다.
를 나눠서 적어놓은거라고 보면 될 듯
---
## 📑 개념
**[[분개(分介)]]전표**는 앞서 설명해 드린 [[전표]]의 한 종류로, **회계상의 거래를 차변(Debit)과 대변(Credit)으로 나누어 기록하는 서식**을 말합니다.
일반적인 [[전표]]가 단순히 돈이 나가고 들어온 사실에 집중한다면, 분개전표는 그 거래가 회계적으로 어떤 의미를 갖는지 상세하게 분석해서 적는 것이 특징입니다.
## 📌 상세
### 1. 분개전표의 핵심 구성
분개전표에는 반드시 **[[분개(分介)]](Journalizing)** 과정이 포함됩니다.
- **차변 (왼쪽):** 자산의 증가, 부채의 감소, 비용의 발생 등을 기록합니다.
- **대변 (오른쪽):** 자산의 감소, 부채의 증가, 수익의 발생 등을 기록합니다.
- **적요:** 이 거래가 구체적으로 무엇인지 설명을 적습니다. (예: 3월분 사무실 임차료 지급)
### 2. 왜 분개전표를 쓸까?
대부분의 기업은 **복식부기** 원리에 따라 장부를 정리합니다. 단순히 현금이 나갔다(출금전표)는 정보만으로는 부족할 때가 많기 때문입니다.
- **복합 거래 처리:** 현금과 카드를 섞어서 결제하거나, 외상 거래를 기록할 때 유용합니다.
- **오류 방지:** 차변 합계와 대변 합계가 항상 일치해야 하므로(대차평균의 원리), 기록 과정에서의 실수를 바로 잡아낼 수 있습니다.
- **회계 소프트웨어의 기초:** 요즘 사용하는 경리 프로그램(ERP)에 전표를 입력하면, 시스템이 이 분개전표를 바탕으로 재무제표를 자동으로 만들어 줍니다.
---
@@ -0,0 +1,52 @@
---
id: "서브넷 마스크(Subnet Mask) 20260428"
created: "2026-04-28 14:40"
tags:
aliases:
---
## 💡 생각
IP 주소라는 전체 주소 중에서 어디까지가 **동네 이름**이고, 어디서부터가 **집 번호**인지를 알려주는 구분선
---
## 📑 개념
서브넷 마스크(Subnet Mask)는 IP 주소에서 '네트워크 부분'과 '호스트(개별 기기) 부분'을 나누는 기준이 되는 숫자입니다.
## ### 1. 왜 필요한가요?
[[IP]] 주소만 봐서는 이 컴퓨터가 어느 그룹에 속해 있는지 알 수 없습니다. [[서브넷(Subnet)]] 마스크는 이를 논리적으로 쪼개어 다음과 같은 역할을 합니다.
- **그룹화:** 같은 네트워크에 있는 기기들을 하나로 묶습니다.
- **통신 대상 판단:** 데이터를 보낼 때, 대상이 나와 같은 동네(내부망)에 있는지 아니면 [[게이트웨이(Gateway)]]를 통해 밖으로 나가야 하는 다른 동네(외부망)인지 판단하는 기준이 됩니다.
서브넷이 다른 경우 서로 다른 네트워크망에 있는것으로 간주함.
예를들어 서브넷 마스크가 255.255.255.0 인 네트워크에서
IP: 192.168.100.228 와 IP: 192.168.100.229 두 서버는 서로 같은 네트워크망에 있는것이다.
228서버와 229서버는 서로 통신할 때 [[라우팅(Routing)]]이나 [[게이트웨이(Gateway)]]를 거치지않고 다이렉트로 통신이 가능하다.
### 2. 어떻게 작동하나요?
서브넷 마스크는 IP 주소와 똑같이 32비트(4개 덩어리)로 구성되며, 보통 `255``0`을 조합해서 사용합니다.
- **255 (1로 채워진 부분):** "이 자리는 네트워크(동네 이름)를 나타내니 건드리지 마!"라는 뜻입니다.
- **0 (0으로 채워진 부분):** "이 자리는 호스트(개별 기기)를 나타내니 자유롭게 번호를 매겨!"라는 뜻입니다.
> **예시: IP가 `192.168.0.10`이고 서브넷 마스크가 `255.255.255.0`이라면?**
>
> - 앞의 세 덩어리 `192.168.0`은 이 기기가 속한 **네트워크 이름**입니다.
>
> - 마지막 한 덩어리 `10`은 그 네트워크 안에서의 **기기 고유 번호**입니다.
>
### 3. 표기법 (CIDR)
서브넷 마스크는 `255.255.255.0`처럼 길게 쓰기도 하지만, 슬래시(`/`) 뒤에 숫자를 붙여서 짧게 쓰기도 합니다. 이를 **CIDR 표기법**이라고 합니다.
- **`/24`:** 앞에서부터 24비트(3덩어리)가 네트워크 주소라는 뜻입니다. (`255.255.255.0`과 같습니다.)
- **`/16`:** 앞에서부터 16비트(2덩어리)가 네트워크 주소라는 뜻입니다. (`255.255.0.0`과 같습니다.)
---
+46 -3
View File
@@ -5,7 +5,7 @@
> 거대한 네트워크인 [[VPC(Virtual Private Cloud)]]를 더 효율적이고 안전하게 관리하기 위해 **더 작은 단위로 쪼갠 가상 네트워크** > 거대한 네트워크인 [[VPC(Virtual Private Cloud)]]를 더 효율적이고 안전하게 관리하기 위해 **더 작은 단위로 쪼갠 가상 네트워크**
**참고로 VPC도 서브넷도 모두 논리적인 개념, 물리적인 동작은 가용 영역에서 이루어짐** **참고로 VPC도 서브넷도 모두 논리적인 개념, 물리적인 동작은 가용 영역에서 이루어짐**
서브넷(Subnet)은 'Sub-network'의 줄임말로, 하나의 거대한 네트워크를 효율적으로 관리하기 위해 **더 작고 논리적으로 쪼개놓은 부분 네트워크**를 의미합니다.
## 📌 서브넷을 나누는 이유 ## 📌 서브넷을 나누는 이유
> [!check] > [!check]
> - **보안 (Security):** 인터넷에 연결될 공간과 외부로부터 완전히 격리될 공간을 분리하기 위해서입니다. > - **보안 (Security):** 인터넷에 연결될 공간과 외부로부터 완전히 격리될 공간을 분리하기 위해서입니다.
@@ -29,5 +29,48 @@
| **연결 방식** | **인터넷 게이트웨이(IGW)**와 연결됨 | 인터넷 게이트웨이와 연결되지 않음 | | **연결 방식** | **인터넷 게이트웨이(IGW)**와 연결됨 | 인터넷 게이트웨이와 연결되지 않음 |
| **배치 자원** | 로드 밸런서(ALB), 배스천 호스트(Bastion) | **백엔드 서버(.NET)**, 데이터베이스(DB) | | **배치 자원** | 로드 밸런서(ALB), 배스천 호스트(Bastion) | **백엔드 서버(.NET)**, 데이터베이스(DB) |
| **비유** | 아파트 정문 안내소 (누구나 방문 가능) | 아파트 내부의 안방 (가족만 접근 가능) | | **비유** | 아파트 정문 안내소 (누구나 방문 가능) | 아파트 내부의 안방 (가족만 접근 가능) |
## 🔗 지식 연결
- **태그:** #zettelkasten #knowledge ## 1. 왜 서브넷을 만드나요? (서브네팅의 이유)
네트워크를 쪼개지 않고 하나로 크게 쓰면 다음과 같은 문제가 생깁니다.
- **트래픽 과부하:** 모든 기기가 한 공간에 있으면, 불필요한 방송 신호(브로드캐스트)가 너무 많아져 네트워크가 느려집니다.
- **보안 취약:** 한 곳이 뚫리면 전체 네트워크의 모든 기기가 위험에 노출됩니다.
- **관리의 어려움:** 장치가 수만 대라면 어디서 문제가 생겼는지 찾기 매우 힘듭니다.
그래서 서브네팅(Subnetting)을 통해 네트워크를 목적이나 위치에 맞게 작게 분리하여 성능과 보안을 높입니다.
---
## 2. 서브넷은 어떻게 구분하나요? (서브넷 마스크)
IP 주소는 원래 하나처럼 보이지만, 서브넷 개념이 들어가면 두 부분으로 나뉩니다.
1. **네트워크 주소 (Network ID):** 어떤 동네(서브넷)인지 알려주는 주소
2. **호스트 주소 (Host ID):** 그 동네 안의 몇 호(기기)인지 알려주는 주소
이때 어디까지가 동네 주소이고, 어디서부터가 기기 주소인지를 구분해주는 기준점이 바로 서브넷 마스크(Subnet Mask)입니다.
- 예를 들어, `255.255.255.0`이라는 서브넷 마스크는 "앞의 세 덩어리(24비트)는 동네 이름이고, 마지막 한 덩어리만 너의 고유 번호야"라고 지정해주는 역할을 합니다.
## 3. 실생활 예시: 회사 네트워크
한 회사에 100명의 직원이 있을 때, 서브넷을 적용하면 다음과 같이 나눌 수 있습니다.
|**서브넷 이름**|**역할**|**접근 권한**|
|---|---|---|
|**서브넷 A**|개발팀|서버 및 개발 환경 접근 가능|
|**서브넷 B**|인사팀|개인정보 및 급여 시스템 접근 가능|
|**서브넷 C**|방문객용 Wi-Fi|인터넷만 가능, 내부 서버 접근 불가|
이렇게 나누면 개발팀 직원이 실수로 인사팀의 민감한 파일을 들여다보는 일을 물리적으로 차단할 수 있습니다.
## 4. 서브넷 간의 통신
- **같은 서브넷 안:** [[게이트웨이(Gateway)]] 없이 직접 소통합니다. (같은 동네니까요!)
- **서로 다른 서브넷:** 반드시 [[라우터(Router)]](또는 [[게이트웨이(Gateway)]])를 거쳐야 합니다. (다른 동네로 넘어가야 하니까요!)
@@ -0,0 +1,64 @@
---
id: 시리얼 통신(Serial Communication) 20260504
created: 2026-05-04 09:22
tags:
aliases:
- 직렬통신
---
## 💡 생각
구식 통신연결방식이다 생각하면 됨. 옛날꺼니까 단점이 많음
이미 serial로 연결해서 사용중이던 장비를 다뤄야 하는 경우에나 보게되거나 사용하게 됨.
[[RS-232]]는 생각보다 꽤 범용적으로 사용했던거라 아직까지도 남아있는 경우가 있음
---
## 📑 개념
데이터를 하나의 선(Channel)을 통해 **한 번에 1비트씩 순차적으로 전송**하는 방식입니다.
현대의 USB, 이더넷, 그리고 임베디드 시스템에서 널리 쓰이는 RS-232, RS-485 등이 모두 여기에 속합니다.
---
## 1. 핵심 개념: 직렬 vs 병렬
데이터를 보낼 때 여러 개의 선을 사용하는 병렬 통신과 달리, 시리얼 통신은 최소한의 선으로 데이터를 보냅니다.
- **직렬(Serial):** 한 줄로 서서 차례대로 이동 (비용 저렴, 장거리 유리)
- **병렬(Parallel):** 여러 줄로 동시에 이동 (단거리 고속, 케이블 복잡)
## 2. 주요 통신 방식 (동기 vs 비동기)
### 비동기식 통신 (Asynchronous)
클럭(Clock) 신호를 공유하지 않고, 데이터 앞뒤에 **Start Bit**와 **Stop Bit**를 붙여 데이터의 시작과 끝을 구분합니다.
- **대표 사례:** UART (RS-232, RS-485)
- **장점:** 선의 개수가 적음
- **단점:** 통신 속도(Baud Rate)가 양쪽 모두 일치해야 함
### [[동기(Synchronous)]]식 통신
별도의 **클럭 신호선**을 사용하여 송수신 타이밍을 맞춥니다.
- **대표 사례:** SPI, I2C
- **장점:** 데이터 전송 효율이 높고 속도가 빠름
- **단점:** 클럭을 위한 추가 선이 필요함
## 주요 설정 파라미터 (UART 기준)
시리얼 통신을 설정할 때 반드시 맞춰야 하는 4가지 요소입니다.
1. **Baud Rate (보오율):** 초당 전송되는 비트 수 (예: 9600, 115200)
2. **Data Bits:** 한 번에 보낼 데이터의 길이 (보통 8비트)
3. **Parity Bit:** 오류 검출을 위한 비트 (None, Even, Odd)
4. **Stop Bits:** 데이터의 끝을 알리는 비트 (1 또는 2)
---
+40
View File
@@ -0,0 +1,40 @@
---
id: "전표 20260413"
created: "2026-04-13 11:01"
tags:
aliases:
---
## 💡 생각
거래내역을 증빙하는 증빙자료 정도로 생각하면 될듯.. 영수증 이라고 봐도 될거같고
---
## 📑 개념
**전표**는 기업이나 가게에서 거래가 발생했을 때, 그 내용을 증빙하고 기록하기 위해 작성하는 서식입니다. 쉽게 말해 **거래의 핵심 정보를 담은 쪽지**라고 생각하면 됩니다.
## 상세
### 1. 전표에 들어가는 내용
전표에는 나중에 누가 봐도 거래 내용을 알 수 있게 필수적인 정보들이 기록됩니다.
- **거래 날짜**
- **거래 내용** (무엇을 사고팔았는지)
- **거래 금액**
- **거래 상대방**
- **계정과목** (회계상 어떤 항목인지, 예: 복리후생비, 임차료 등)
### 2. 전표의 종류
가장 흔히 쓰이는 3가지 구분법입니다.
- **입금전표**: 현금이 들어왔을 때 작성 (빨간색 테두리인 경우가 많음)
- **출금전표**: 현금이 나갔을 때 작성 (파란색 테두리인 경우가 많음)
- **대체전표**: 현금이 직접 오가지 않는 거래(카드 결제, 계좌 이체, 외상 등)일 때 작성
---
@@ -0,0 +1,72 @@
---
id: 차동 신호(Differential Signaling) 20260504
created: 2026-05-04 10:07
tags:
aliases:
---
## 💡 생각
[[RS-232]]나 이더넷통신의 경우 전압의 차이의 해석이 핵심인데 이 전압에 여러 노이즈가 낄 수 있음.
근데 이 노이즈도 결국 전압의 차이이고 노이즈가 +로 끼든 -로 끼든 상관없이 보정할 수 있는 방법이 바로 차동 신호기법인 것임.
---
## 📑 개념
차동 신호는 **두 개의 신호선**을 사용하여 하나의 정보를 전달하는 전기적 신호 전송 방식입니다. 주로 고속 데이터 통신이나 노이즈가 많은 환경에서 신호의 무결성을 유지하기 위해 사용됩니다.
---
## ### 1. 기본 원리
일반적인 '싱글 엔디드(Single-ended)' 방식이 하나의 신호선과 접지(Ground) 사이의 전압 차를 이용한다면, 차동 신호는 **서로 반대되는 위상을 가진 두 신호**를 이용합니다.
- **V+ (Positive):** 원래의 신호
- **V- (Negative):** 원래 신호와 크기는 같지만 극성이 반대인 신호
수신 측에서는 이 두 신호의 차이($V_{diff} = V_+ - V_-$)를 측정하여 데이터를 복원합니다.
> [!note] 차동 신호(Differential Signaling)의 핵심 원리
> ### 1. 신호를 보낼 때 (송신)
>
> 데이터 `10`을 보내고 싶다고 가정해 보겠습니다. 이더넷은 선 두 개($A$선, $B$선)에 신호를 **반대로** 실어 보냅니다.
>
> - **$A$선 (정위상):** $+10V$
>
> - **$B$선 (역위상):** $-10V$
>
> - 이때 두 선의 차이는 $10 - (-10) = \mathbf{20V}$가 됩니다. 이것이 우리가 보낸 진짜 데이터의 크기입니다.
>
>
> ### 2. 중간에 노이즈가 끼어들 때 (간섭)
>
> 랜선이 지나가는데 옆에 커다란 모터가 돌아서 **$+5V$만큼의 노이즈**가 발생했다고 칩시다. 중요한 건 이 노이즈는 **두 선에 똑같이** 영향을 준다는 점입니다. (선이 꼬여있기 때문이죠.)
>
> - **$A$선:** $10V \text{(데이터)} + 5V \text{(노이즈)} = \mathbf{15V}$
>
> - **$B$선:** $-10V \text{(데이터)} + 5V \text{(노이즈)} = \mathbf{-5V}$
>
>
> ### 3. 신호를 받을 때 (수신 - 뺄셈의 마법)
>
> 데이터를 받는 쪽에서는 $A$선에서 $B$선을 뺍니다.
>
> $$(A \text{선}) - (B \text{선}) = 15V - (-5V) = \mathbf{20V}$$
>
> 보이시나요? **결과값이 처음에 보냈던 차이값인 $20V$와 똑같이 나옵니다.** 노이즈 $+5V$가 양쪽에서 똑같이 더해졌기 때문에, 뺄셈을 하는 순간 서로 상쇄되어 사라져 버린 것입니다.
### 2. 왜 차동 신호를 사용하는가? (주요 장점)
#### 외부 노이즈에 강함 (Common-Mode Rejection)
차동 신호의 가장 큰 장점입니다. 두 신호선이 서로 밀착되어 전송되기 때문에, 외부에서 전기적 노이즈가 유입될 때 두 선 모두에 거의 동일한 양의 노이즈가 더해집니다. 이를 공통 모드 노이즈(Common-Mode Noise)라고 합니다.
- 수신단에서 두 신호를 빼는 과정($V_+ + Noise) - (V_- + Noise)$을 거치면, 동일하게 유입된 노이즈는 서로 상쇄되어 사라지고 순수한 신호만 남게 됩니다.
#### 전자기 방해(EMI) 감소
두 선에 흐르는 전류의 방향이 서로 반대이므로, 각 선에서 발생하는 자기장이 서로를 상쇄합니다. 결과적으로 주변 기기에 끼치는 전자기적 간섭이 줄어듭니다.
#### 낮은 전압으로도 고속 전송 가능
접지(Ground)를 기준으로 삼는 방식보다 신호의 스윙 폭을 작게 가져가도 노이즈에 강하기 때문에, 더 낮은 전압에서 더 빠르게 상태를 전환할 수 있습니다. 이는 전력 소모를 줄이고 속도를 높이는 데 유리합니다.
@@ -0,0 +1,25 @@
---
id: 트랜잭션(Transaction) 20260420
created: 2026-04-20 08:50
tags:
aliases:
- 트렌젝션
- 트렌잭션
- 트랜젝션
---
## 💡 생각
하나 이상의 쿼리를 묶은 최소 작업 단위
---
## 📑 개념
이터베이스 관리 시스템(DBMS)에서 **하나의 논리적 기능을 수행하기 위한 작업의 단위**입니다. 쉽게 말해, 여러 개의 SQL 문들을 하나의 묶음으로 처리하여 "성공하면 모두 반영, 실패하면 모두 취소"를 보장하는 장치입니다.
## 📌 상세
## 트랜잭션의 4가지 핵심 특성 (ACID)
트랜잭션이 안전하게 수행되기 위해서는 아래 네 가지 성질을 반드시 만족해야 합니다. 이를 [[ACID]]라고 부릅니다.
![[ACID#📌 상세]]
즉 [[데이터 정합성(Data Consistency)]]을 지키기 위해 1개 이상의 쿼리작업을 하나의 트랜잭션으로 묶어서 처리한다.
---
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

+1 -2
View File
@@ -11,6 +11,7 @@ aliases:
## 📑 개념 ## 📑 개념
여기에 이 메모가 다루는 개념을 한 문장으로 정의하세요. (예: 제텔카스텔의 원자성이란 지식의 최소 단위를 의미한다.) 여기에 이 메모가 다루는 개념을 한 문장으로 정의하세요. (예: 제텔카스텔의 원자성이란 지식의 최소 단위를 의미한다.)
---
## 📌 상세 ## 📌 상세
1. **특징 1**: 내용을 입력하세요. 1. **특징 1**: 내용을 입력하세요.
2. **특징 2**: 내용을 입력하세요. 2. **특징 2**: 내용을 입력하세요.
@@ -23,5 +24,3 @@ aliases:
> >
> - 본인의 언어로 풀어서 쓰는 것이 제텔카스텔의 핵심입니다. > - 본인의 언어로 풀어서 쓰는 것이 제텔카스텔의 핵심입니다.
> >
---