
웹 개발 한 번에 이해하기
― 비개발자를 위한 웹 개발 한 번에 이해하기, 웹 서비스 구조 완전 가이드
― 기획자·운영자가 반드시 알아야 할 웹 개발 핵심 구조, 웹 개발을 처음 배우는 사람에게
웹 서비스란 무엇인가요?
웹 서비스는 한 문장으로 정리하면 다음과 같습니다.
인터넷을 통해 사용자에게 기능과 정보를 제공하는 프로그램
예시
- 네이버, 쿠팡, 카카오톡 웹
- 사내 관리자 페이지
- 쇼핑몰, 예약 시스템, 대시보드 등
👉 중요한 포인트는 “웹 서비스 = 화면 + 동작 + 데이터 + 서버”의 결합이라는 점입니다.
웹 서비스 전체 구조 한 장으로 이해하기
[사용자] ↓ (클릭, 입력) [웹 브라우저] ↓ (요청) [프론트엔드] ↓ (API 요청) [백엔드 서버] ↓ [데이터베이스]
이 구조를 역할 중심으로 나누면 다음과 같습니다.
구분역할
| 사용자 | 클릭, 입력, 조회 |
|---|---|
| 프론트엔드 | 화면 표시, 사용자 동작 처리 |
| 백엔드 | 로직 처리, 권한 판단, 데이터 가공 |
| 데이터베이스 | 데이터 저장/조회 |
프론트엔드(Frontend) – “사용자가 보는 모든 것”
프론트엔드란?
사용자가 직접 보고, 클릭하고, 입력하는 화면 영역
구성 요소
- HTML – 구조
- CSS – 디자인
- JavaScript – 동작
비유로 이해하기
- HTML → 집의 뼈대
- CSS → 집의 인테리어
- JavaScript → 전기·스위치·자동문
HTML 예시 (구조)
<h1>로그인</h1> <input type="text" placeholder="아이디"> <input type="password" placeholder="비밀번호"> <button>로그인</button>
👉 “무엇이 있는지”만 정의
👉 디자인·동작 없음
CSS 예시 (디자인)
button { background-color: blue; color: white; }
👉 버튼을 파랗게 보이게 함
JavaScript 예시 (동작)
button.onclick = function() { alert("로그인 버튼 클릭"); }
👉 클릭 시 무엇이 일어날지 정의
기획/운영자가 알아야 할 포인트
- 프론트엔드는 보안 판단을 하면 안 됨
- 모든 입력값은 서버에서 다시 검증 필요
- “화면에서 막았어요”는 보안이 아님
백엔드(Backend) – “보이지 않는 핵심 엔진”
백엔드란?
- 서버에서 실행되는 프로그램
- 비즈니스 로직, 인증, 권한, 데이터 처리 담당
백엔드에서 하는 일
- 로그인 처리
- 권한 확인 (관리자인지?)
- 데이터 저장/조회
- 정책 적용 (차단, 제한, 조건)
백엔드 예시 (개념)
if user.password == input_password: login_success() else: login_fail()
👉 실제 서비스 규칙은 반드시 백엔드에 있음
보안 관점 핵심
- 인증/인가 로직은 반드시 서버
- 프론트엔드는 신뢰 불가
- 로그는 서버에서 남김
API – 프론트엔드와 백엔드를 잇는 다리
API란?
프론트엔드가 백엔드에게 “이거 처리해 주세요”라고 요청하는 공식 통로
API 요청 예시
POST /api/login { "id": "user1", "password": "1234" }
API 응답 예시
{ "result": "success", "token": "abc.def.ghi" }
비유
- API = 주문서
- 프론트엔드 = 손님
- 백엔드 = 주방
👉 손님이 직접 주방에 들어가면 안 됨
보안 체크 포인트
- 인증 없는 API 존재 여부
- 관리자 API 외부 노출 여부
- 입력값 검증 (SQL Injection, Command Injection)
JSON – 시스템 간 데이터 언어
JSON이란?
- 데이터 전달을 위한 표준 포맷
- 사람이 읽기 쉬움
- 시스템 간 통신에 최적
JSON 예시
{ "user_id": 1001, "role": "admin", "active": true }
👉 프론트 ↔ 백엔드 ↔ 외부 시스템 공통 언어
운영 시 주의
- 민감정보(JSON)에 포함 금지
- 로그에 그대로 남지 않도록 주의
데이터베이스(DB) – 서비스의 기억장치
역할
- 사용자 정보
- 주문 내역
- 로그
- 설정 값
종류
구분예
| 관계형(RDB) | MySQL, PostgreSQL |
|---|---|
| 비관계형(NoSQL) | MongoDB, Redis |
SQL 예시
SELECT * FROM users WHERE id = 1001;
보안 관점
- 직접 접근 차단
- 최소 권한 원칙
- 암호화 (비밀번호, 개인정보)
로그인 & 인증 흐름 전체 예시
1. 사용자 로그인 입력 2. 프론트엔드 → API 요청 3. 백엔드 → DB 조회 4. 인증 성공 시 토큰 발급 5. 이후 요청 시 토큰 확인
👉 화면 = 표시만
👉 판단 = 서버
배포와 운영
배포란?
- 개발한 서비스를 실제 서버에 올리는 작업
일반 구성
- 웹 서버 (Nginx)
- 백엔드 서버
- DB 서버
- 로그/모니터링
운영 시 체크리스트
- 장애 시 로그 확인 가능?
- 관리자 접근 통제?
- 외부 노출 포트 최소화?
- 백업 존재?
기획·운영자가 꼭 기억해야 할 핵심 요약
✔️ 구조 관점
- 화면 ≠ 로직
- 프론트 ≠ 보안
- API는 항상 통제 대상
✔️ 협업 관점
- “이건 화면 문제인가, 서버 문제인가?”
- “권한은 어디서 판단하나요?”
- “로그는 어디 남나요?”
✔️ 보안 관점
- 입력값은 무조건 의심
- 서버 기준 정책 수립
- 로그·권한·인증은 백엔드 중심
웹 개발은 ‘보여주는 것(프론트)’과 ‘판단하는 것(백엔드)’을 명확히 분리해 이해하는 것이 핵심입니다.
프로젝트 표준 방향
- 프론트 프레임워크 선택
- React(TSX/JSX): “JS 안에서 UI를 표현” → 복잡한 UI 로직/조합에 강함
- Vue(SFC): “템플릿+스크립트+스타일 분리” → 선언적/가독성/협업에 강함
- 코드 구조 표준
- “메뉴(라우트) 파일 1개에 다 넣기” 금지
- 페이지는 얇게, 섹션/컴포넌트/훅/서비스로 분리
- 배포 표준
- GitHub에 push/PR → Vercel이 자동 빌드/배포
main= Production, 그 외 = Preview (기본 개념)
- 보안 표준
main브랜치 보호(PR+리뷰+상태체크 필수)- Preview는 기본적으로 외부 URL이 생기므로 Deployment Protection(Auth/Password/IP 등) 필수 고려
- Secret은 Git에 두지 말고 Vercel Environment Variables로 환경별 분리
JSX(React/TSX) vs Vue(SFC) 비교분석(프로젝트 설계 관점)
개발 방식(표현 철학)
- JSX/TSX(React)
- UI를 “JS 표현식”으로 구성(조건/반복/컴포지션이 자유)
- 장점: 복잡한 UI 로직을 함수처럼 조합하기 쉬움
- 주의: 규칙 없이 쓰면 컴포넌트가 거대해지기 쉬움(=> 분리 전략이 중요)
- Vue(SFC)
<template>에서 선언적으로 UI를 작성하고,<script>로 로직 분리- 장점: 가독성과 역할 분리가 자연스럽고 협업(마크업 중심)에 유리
- 주의: 템플릿 문법/반응성 규칙을 잘 지켜야 성능/가독성 유지
팀/협업 관점 선택 힌트
- React(TSX)가 유리한 경우
- 복잡한 대시보드/워크플로 UI, 컴포넌트 조합이 많음
- JS/TS 숙련도가 높고, 패턴/규칙을 팀이 강하게 운영 가능
- Vue가 유리한 경우
- 화면 중심 CRUD, 템플릿 기반 협업이 많음
- “표준 방식으로 빠르게 합의”하고 일관되게 가고 싶음
“큰 메뉴/페이지 TSX 분리” 프로젝트 표준(스레드 핵심)
원칙: 라우트(메뉴) 엔트리는 얇게
- 라우트 파일은 “권한/데이터 로딩 트리거/레이아웃 조립”만
- UI 섹션은 별도 파일로 분리(= include 역할은 import 컴포넌트로 대체)
권장 폴더 구조(React 기준, Vue도 유사 적용)
src/
pages/ # 라우트 엔트리(얇게)
Orders/OrdersPage.tsx
features/ # 도메인 기능(실제 코드)
orders/
sections/
components/
hooks/
services/
types.ts
utils.ts
shared/ # 공통 컴포넌트/유틸(진짜 공통만)
분리 패턴 예시(React/TSX)
(1) 라우트 엔트리(얇게)
// pages/Orders/OrdersPage.tsx
import { OrdersScreen } from "@/features/orders/sections/OrdersScreen";
export default function OrdersPage() {
return <OrdersScreen />;
}
(2) 섹션(Screen)에서 화면 구성
// features/orders/sections/OrdersScreen.tsx
import { OrdersFilterBar } from "../components/OrdersFilterBar";
import { OrdersTable } from "../components/OrdersTable";
import { useOrdersScreen } from "../hooks/useOrdersScreen";
export function OrdersScreen() {
const { rows, loading, filters, setFilters } = useOrdersScreen();
return (
<div>
<OrdersFilterBar value={filters} onChange={setFilters} />
<OrdersTable rows={rows} loading={loading} />
</div>
);
}
(3) 로직은 hook으로 분리
// features/orders/hooks/useOrdersScreen.ts
import { useEffect, useState } from "react";
import { fetchOrders } from "../services/ordersApi";
export function useOrdersScreen() {
const [filters, setFilters] = useState({ q: "", status: "ALL" });
const [rows, setRows] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
(async () => {
setLoading(true);
try { setRows(await fetchOrders(filters)); }
finally { setLoading(false); }
})();
}, [filters]);
return { rows, loading, filters, setFilters };
}
(4) 데이터 접근은 service로 분리
// features/orders/services/ordersApi.ts
export async function fetchOrders(filters: any) {
const qs = new URLSearchParams(filters).toString();
const res = await fetch(`/api/orders?${qs}`, { credentials: "include" });
if (!res.ok) throw new Error("fetch failed");
return res.json();
}
“컨텐츠가 많다”면 Lazy Load(코드 스플리팅)
무거운 탭/리포트/차트/에디터는 “열 때 로드”
import { lazy, Suspense, useState } from "react";
const HeavyReport = lazy(() => import("./HeavyReport"));
export function ReportsTab() {
const [open, setOpen] = useState(false);
return (
<>
<button onClick={() => setOpen(true)}>리포트 열기</button>
{open && (
<Suspense fallback={<div>로딩중...</div>}>
<HeavyReport />
</Suspense>
)}
</>
);
}
GitHub push → Vercel 자동 배포 구조(프로젝트 기본 배포 파이프라인)
개념(기본 동작)
Vercel은 Git 통합으로 다음을 기본 제공
- 브랜치에 push → 해당 브랜치 Preview 배포
- Production 브랜치(main 등)에 머지/푸시 → Production 배포
동작 흐름(표준)
git push / PR merge
→ Git Integration(Webhook 기반)
→ Vercel Build(install → build)
→ Deploy
→ Preview URL 또는 Production URL 갱신
“모든 브랜치 푸시/프로덕션 브랜치 변경”에 대해 자동 배포가 이뤄진다는 점이 핵심
실제 설정 방법(새 프로젝트 시작 체크리스트)
Vercel에서 Import
- Vercel 로그인(“Continue with GitHub”)
- New Project → Git Repo Import
- 프레임워크/빌드 설정 자동 감지(필요 시 수정)
Vercel은 Git Repo Import 후 “push마다 Preview / production branch 변경 시 Production” 흐름을 공식으로 안내합니다.
환경(Environments)과 환경변수 운영
Vercel 기본 환경 3종
- Local / Preview / Production
환경변수는 환경별로 분리 운영 가능하며, Preview 변수는 “Production 브랜치가 아닌 브랜치 배포”에 적용되는 방식이 문서에 명시돼 있습니다.
운영 규칙 예시
- Production: 운영 API/운영 DB
- Preview: 스테이징 API/테스트 DB
- Local: 개발용 최소 권한 키
브랜치 전략 + 품질 게이트(배포 안정성의 핵심)
권장 전략
feature/*→ Preview 배포로 리뷰/QA- PR 승인 후
main머지 → Production 배포
GitHub Branch Protection(필수)
GitHub는 브랜치 보호 규칙으로
- PR 리뷰 요구
- 상태 체크(테스트 등) 통과 요구
같은 워크플로를 강제할 수 있습니다.
보안/운영 체크리스트
- main 직접 push 금지(= PR 필수)
- 최소 리뷰 수(1~2) + CODEOWNERS(가능하면)
- Required status checks(테스트/린트) 필수
- (권장) stale review dismiss / up-to-date before merge 옵션 검토
보안 관점 가이드(“배포+프론트” 핵심)
Preview 배포는 “외부 URL 노출”이 기본 → 보호가 필요
Vercel은 Preview/Production URL을 보호하는 Deployment Protection을 제공하고, 환경별로 보호 방식을 다르게 적용할 수 있습니다.
대표 보호 방식
- Vercel Authentication(팀 멤버 로그인 기반)
- Password Protection
- 프로젝트 수준 보호 정책(환경별 적용)
점검포인트
- 내부 관리콘솔인데 Preview가 무보호 공개인가?
- Preview가 운영 API/운영 DB를 바라보는가?
- “보호 우회(바이패스) 방식/권한”을 누가 가지고 있는가? (감사 포인트)
Secrets 관리(절대 Git 커밋 금지)
.env, API Key, 토큰은 Git에 올리지 않고- Vercel Environment Variables로 관리 (환경별 분리)
점검포인트
- Preview 변수에 Production 키가 섞이지 않았나?
- 환경변수 수정 권한이 최소권한 원칙을 따르나?
프론트 보안(React/Vue 공통 핵심)
- React:
dangerouslySetInnerHTML최소화/승인제 - Vue:
v-html최소화/승인제 - 사용자 입력/외부 콘텐츠를 HTML로 렌더링하면 XSS 위험이 급증 → sanitize/화이트리스트 필요
“프로젝트 시작 템플릿” 운영안(추천)
표준 운영 흐름
- feature 브랜치 push → Preview 배포(URL 자동 생성)
- PR 생성 → 리뷰 + 자동 테스트 통과(Required checks)
- main 머지 → Production 자동 배포
- 장애 시 Vercel에서 이전 배포로 롤백(운영권한 통제)
페이지/컴포넌트 구조 표준
pages(라우트 엔트리) = 얇게features= 섹션/컴포넌트/훅/서비스로 분리- “큰 메뉴 TSX 하나로 몰아넣기” 금지(리뷰/보안/성능 모두 악화)
자주 터지는 FAQ(스레드 기반 + 실무형)
Q1. TSX를 메뉴당 하나로 강제하면 안 되나요?
- 가능은 하지만 금방 비대해져서 유지보수/리뷰/테스트가 어려워집니다.
- 라우트 파일은 얇게, 섹션/훅/서비스로 분리하는 것이 표준입니다.
Q2. GitHub에 push하면 자동 배포되는 게 위험하지 않나요?
- 위험한 건 자동배포가 아니라 main 보호 없이 운영하는 것입니다.
- Branch protection으로 PR/리뷰/상태체크를 강제하세요.
Q3. Preview URL이 외부에 노출되면 어떡하죠?
- Deployment Protection을 켜서 인증/비번 등으로 막는 게 정석입니다.
Q4. Preview에서 운영 데이터가 보이면 큰일 아닌가요?
- 맞습니다. Preview는 스테이징/모킹으로 분리해야 합니다.
- 환경변수를 Preview/Production으로 분리 운영하세요.
Q5. React vs Vue, 보안 차이가 큰가요?
- 프레임워크 자체보다 HTML 주입 지점(
dangerouslySetInnerHTML/v-html) 관리가 핵심입니다. - 운영상 “승인제/금지 규칙/코드 스캔”이 있으면 둘 다 안전하게 운영 가능합니다.
댓글