본문 바로가기

웹 개발을 ‘구조’로 이해하면 갑자기 쉬워집니다 – 구조부터 협업까지

728x90

웹 개발 한 번에 이해하기

― 비개발자를 위한 웹 개발 한 번에 이해하기, 웹 서비스 구조 완전 가이드

기획자·운영자가 반드시 알아야 할 웹 개발 핵심 구조, 웹 개발을 처음 배우는 사람에게

웹 서비스란 무엇인가요?

웹 서비스는 한 문장으로 정리하면 다음과 같습니다.

인터넷을 통해 사용자에게 기능과 정보를 제공하는 프로그램

예시

  • 네이버, 쿠팡, 카카오톡 웹
  • 사내 관리자 페이지
  • 쇼핑몰, 예약 시스템, 대시보드 등

👉 중요한 포인트는 “웹 서비스 = 화면 + 동작 + 데이터 + 서버”의 결합이라는 점입니다.

웹 서비스 전체 구조 한 장으로 이해하기

[사용자] ↓ (클릭, 입력) [웹 브라우저] ↓ (요청) [프론트엔드] ↓ (API 요청) [백엔드 서버] ↓ [데이터베이스]

이 구조를 역할 중심으로 나누면 다음과 같습니다.

구분역할
사용자 클릭, 입력, 조회
프론트엔드 화면 표시, 사용자 동작 처리
백엔드 로직 처리, 권한 판단, 데이터 가공
데이터베이스 데이터 저장/조회

프론트엔드(Frontend) – “사용자가 보는 모든 것”

프론트엔드란?

사용자가 직접 보고, 클릭하고, 입력하는 화면 영역

구성 요소

  1. HTML – 구조
  2. CSS – 디자인
  3. 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

  1. Vercel 로그인(“Continue with GitHub”)
  2. New Project → Git Repo Import
  3. 프레임워크/빌드 설정 자동 감지(필요 시 수정)

Vercel은 Git Repo Import 후 “push마다 Preview / production branch 변경 시 Production” 흐름을 공식으로 안내합니다.

환경(Environments)과 환경변수 운영

Vercel 기본 환경 3종

  • Local / Preview / Production
300x250

환경변수는 환경별로 분리 운영 가능하며, 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/화이트리스트 필요

“프로젝트 시작 템플릿” 운영안(추천)

표준 운영 흐름

  1. feature 브랜치 push → Preview 배포(URL 자동 생성)
  2. PR 생성 → 리뷰 + 자동 테스트 통과(Required checks)
  3. main 머지 → Production 자동 배포
  4. 장애 시 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) 관리가 핵심입니다.
  • 운영상 “승인제/금지 규칙/코드 스캔”이 있으면 둘 다 안전하게 운영 가능합니다.
728x90
그리드형(광고전용)

댓글