개발 프로젝트/[외주 프로젝트] 첫 외주 웹사이트 제작기: 기획부터 배포까지

후기 기능 만들기: 계정 없이 등록하고 비밀번호로 삭제하기

namerong 2026. 6. 16. 17:32

이번 프로젝트에서 후기 기능을 만들면서 가장 먼저 고민한 것은 “회원가입을 넣을 것인가?”였다.
후기 기능만 놓고 보면 회원가입, 로그인, 마이페이지까지 붙이는 방식도 가능하다.
사용자를 식별하기 쉽고, 본인이 작성한 후기를 관리하기도 편하다.

하지만 이 프로젝트의 사용자 흐름을 생각해보면 회원가입은 오히려 부담이 될 수 있다고 판단했다.
사이트에 들어온 사용자는 서비스를 둘러보고, 견적을 확인하고, 필요하다면 후기를 남기는 정도의 행동을 하게 된다.
이런 상황에서 단순히 후기 하나를 작성하기 위해 회원가입을 요구하면 사용자는 쉽게 이탈할 수 있다.

그래서 후기 기능은 계정 없이 작성할 수 있도록 만들었다.
대신 아무 제약 없이 작성하게 두면 도배나 의미 없는 글이 등록될 수 있기 때문에, 이름과 후기 전용 비밀번호를 입력하도록 했다.

회원가입 없이 후기를 작성하게 한 이유

후기 기능의 목표는 복잡한 커뮤니티 기능이 아니었다.

사용자가 서비스를 이용한 뒤 간단히 경험을 남길 수 있는 구조가 필요했다. 따라서 로그인 기반의 무거운 기능보다는, 빠르게 작성할 수 있는 가벼운 구조가 더 적합하다고 생각했다.

처음에 정리한 방향은 이랬다.

회원가입은 받지 않는다
이름은 화면에 표시한다
비밀번호는 본인 삭제용으로만 사용한다
관리자는 전체 후기를 관리할 수 있다

이 방식은 사용자 입장에서 진입 장벽이 낮다.
후기를 작성하려면 이름, 비밀번호, 후기 내용만 입력하면 된다. 계정 생성, 이메일 인증, 로그인 같은 과정이 없다.

하지만 최소한의 식별 정보는 남긴다. 동명이인이 있을 수는 있지만, 본인이 작성할 때 입력한 비밀번호를 모르면 삭제할 수 없도록 했다.

즉, “회원 시스템은 없지만 본인 확인을 위한 최소한의 장치”를 둔 것이다.

이름, 비밀번호, 후기 내용 구조

후기 데이터는 복잡하지 않게 설계했다.

필요한 정보는 다음과 같았다.

id
name
passwordHash
content
createdAt

각 필드의 역할은 명확하다.

name은 화면에 표시되는 작성자 이름이다. 사용자가 입력한 이름이 후기 목록에 함께 노출된다.
content는 후기 내용이다. 사용자가 남긴 실제 후기 본문이다.
createdAt은 작성 시간이다. 최신순으로 후기를 보여주기 위해 필요했다.
중요한 필드는 passwordHash다. 사용자가 입력한 비밀번호를 그대로 저장하지 않고, 해시 처리한 값만 저장하기 위한 필드다.

처음에는 단순히 비밀번호를 저장하고 비교하면 구현이 빠를 수 있다.
하지만 운영되는 서비스에서 비밀번호를 평문으로 저장하는 것은 좋지 않다.

비록 이 비밀번호가 사이트 계정 비밀번호는 아니더라도, 사용자가 습관적으로 다른 곳에서 쓰는 비밀번호를 입력할 가능성이 있다.
그래서 후기 삭제용 비밀번호라고 해도 안전하게 저장하는 것이 맞다고 판단했다.

비밀번호를 해시로 저장한 이유

후기 삭제용 비밀번호는 사용자가 본인의 글을 삭제할 때만 사용된다.
하지만 서버나 DB 입장에서 보면 이것도 사용자의 민감한 입력값이다.
그래서 DB에는 원문 비밀번호를 저장하지 않고 해시 값으로 저장했다.

흐름은 다음과 같다.

사용자가 후기 작성
-> 비밀번호 입력
-> 서버에서 비밀번호 해시 처리
-> DB에는 해시된 비밀번호만 저장

삭제할 때는 반대로 입력값을 검증한다.

사용자가 삭제 버튼 클릭
-> 비밀번호 입력
-> 서버에서 입력 비밀번호와 저장된 해시 비교
-> 일치하면 삭제
-> 일치하지 않으면 실패 응답

이 구조의 장점은 DB를 직접 보더라도 사용자의 원래 비밀번호를 알 수 없다는 점이다.

물론 후기 삭제용 비밀번호라서 로그인 시스템만큼 복잡한 인증 구조는 아니지만, 최소한의 보안 기준은 지키고 싶었다.

외주 프로젝트라고 해서 “작은 기능이니까 대충 저장해도 된다”는 식으로 접근하면 안 된다고 느꼈다.
작은 기능이라도 실제 사용자가 입력하는 데이터라면 보호할 수 있는 만큼 보호해야 한다.

사용자 삭제와 관리자 삭제를 나누기

후기 삭제는 두 가지 흐름으로 나누었다.

첫 번째는 사용자가 본인 후기를 삭제하는 경우다.
사용자는 후기 작성 시 입력했던 비밀번호를 다시 입력해야 한다. 비밀번호가 일치하면 해당 후기를 삭제할 수 있고, 틀리면 삭제되지 않는다.

사용자 삭제 조건
-> 해당 후기에 설정한 비밀번호가 일치해야 함

두 번째는 관리자가 삭제하는 경우다.
관리자는 모든 후기를 관리할 수 있어야 했다. 부적절한 후기나 테스트 글이 올라왔을 때, 작성자 비밀번호를 몰라도 삭제할 수 있어야 하기 때문이다.

관리자 삭제 조건
-> 관리자 비밀번호 인증 후 전체 후기 삭제 가능

이렇게 사용자 권한과 관리자 권한을 분리했다.

사용자는 본인 후기에 대해서만 삭제 권한을 갖고, 관리자는 전체 후기 관리 권한을 갖는다.
이 구조는 단순하지만 실제 운영에는 충분했다.

페이지네이션을 넣은 이유

후기 목록은 최신순으로 보여주도록 했다.

처음에는 모든 후기를 한 번에 불러오는 방식도 가능했다.
하지만 후기가 많아질수록 화면이 길어지고, 한 번에 불러오는 데이터도 많아진다.

그래서 페이지네이션을 적용했다.

사용자 화면에서는 한 페이지에 일정 개수의 후기만 보여주고, 그 이상은 다음 페이지로 넘기도록 했다.
관리자 화면도 마찬가지로 전체 후기를 관리하되, 일정 개수 이상은 페이지를 나누어 보도록 했다.

무한 스크롤도 고려할 수 있었지만, 이번 프로젝트에서는 페이지네이션이 더 적합하다고 판단했다.

이유는 단순했다.

구현과 관리가 명확하다
현재 몇 페이지를 보고 있는지 알기 쉽다
관리자 화면에서 특정 후기를 찾기 쉽다
데이터를 한 번에 너무 많이 불러오지 않아도 된다

특히 관리자 페이지에서는 무한 스크롤보다 페이지 번호가 있는 구조가 더 안정적이라고 생각했다.

긴 텍스트로 인한 레이아웃 깨짐 처리

후기 기능에서 놓치기 쉬운 부분이 긴 텍스트 처리였다.

사용자가 짧은 문장만 입력한다는 보장은 없다. 띄어쓰기 없이 긴 문자열을 입력하거나, 예상보다 긴 후기를 남길 수도 있다.
이 경우 텍스트가 카드 영역 밖으로 삐져나오면 화면이 깨져 보인다.

그래서 후기 내용에는 글자 수 제한과 줄바꿈 처리를 함께 적용했다.

후기 내용은 최소 입력 기준을 둔다
너무 긴 입력은 제한한다
카드 영역을 넘어가는 텍스트는 줄바꿈 처리한다

프론트에서는 긴 텍스트가 박스 밖으로 나가지 않도록 스타일을 잡았고, 백엔드에서도 입력값 검증을 두어 너무 긴 데이터가 저장되지 않도록 했다.

이런 부분은 기능 자체보다 UX에 가까운 작업이지만, 실제 운영 사이트에서는 중요하다.

사용자가 어떤 값을 입력하더라도 화면이 깨지지 않게 만드는 것이 완성도에 영향을 준다.

하드 딜리트와 소프트 딜리트 고민

후기 삭제 방식도 고민했다.

삭제에는 크게 두 가지 방식이 있다.

하드 딜리트: DB에서 데이터를 실제로 삭제
소프트 딜리트: DB에는 남기고 삭제 상태만 표시

소프트 딜리트는 데이터를 복구할 수 있다는 장점이 있다.
예를 들어 게시판이나 주문 내역처럼 나중에 기록 확인이 필요한 데이터라면 소프트 딜리트가 더 적합할 수 있다.

하지만 이번 후기 기능에서는 삭제된 후기를 반드시 보관해야 할 이유가 크지 않았다.

후기는 사용자가 직접 작성한 공개용 글이고, 사용자가 본인 비밀번호로 삭제했다면 실제로 사라지는 것이 자연스럽다고 판단했다.
관리자도 부적절한 후기를 삭제하는 목적이므로 굳이 DB에 남겨둘 필요가 크지 않았다.

그래서 이번 프로젝트에서는 하드 딜리트 방식으로 구현했다.

삭제 요청 성공
-> DB에서 해당 후기 데이터 삭제
-> 목록에서 즉시 사라짐

물론 운영 정책에 따라 나중에는 소프트 딜리트로 바꿀 수도 있다.
하지만 현재 프로젝트 규모와 요구사항에서는 하드 딜리트가 더 단순하고 적합하다고 판단했다.

구현하면서 신경 쓴 점

후기 기능은 겉으로 보면 단순하다.

이름 쓰고, 비밀번호 쓰고, 후기 쓰고, 등록하면 된다. 하지만 실제로 구현하면서는 생각보다 확인할 것이 많았다.

비밀번호는 평문으로 저장하지 않는가
후기 등록 후 바로 목록에 반영되는가
비밀번호가 틀리면 안내가 나오는가
긴 문장이 레이아웃을 깨지 않는가
후기가 많아졌을 때 페이지 처리가 되는가
관리자는 전체 후기를 삭제할 수 있는가
사용자는 본인 후기만 삭제할 수 있는가

이런 작은 조건들이 모여야 실제로 사용할 수 있는 기능이 된다.

특히 외주 프로젝트에서는 클라이언트가 기능을 사용할 때 “왜 안 되지?”라는 느낌을 받지 않도록 흐름을 단순하게 만드는 것이 중요하다고 느꼈다.

이번 기능을 만들며 배운 점

이번 후기 기능을 만들면서 가장 크게 느낀 점은 “회원가입이 없다고 해서 인증 고민이 사라지는 것은 아니다”라는 점이었다.

로그인 기능이 없으면 단순해 보이지만, 대신 사용자를 어떻게 식별할지, 삭제 권한은 어떻게 확인할지, 관리자는 어떤 권한을 가질지 정해야 한다.

이번 프로젝트에서는 이름과 후기 전용 비밀번호라는 가벼운 방식으로 해결했다.
이 방식은 완전한 회원 시스템은 아니지만, 프로젝트의 규모와 사용자 특성에는 잘 맞는 선택이었다고 생각한다.

회고

후기 기능은 처음에는 작은 기능처럼 보였다. 하지만 직접 구현해보니 데이터 저장, 비밀번호 보안, 삭제 권한, 페이지네이션, 긴 텍스트 처리까지 여러 요소가 연결되어 있었다.

특히 사용자의 편의성과 운영자의 관리 권한 사이에서 균형을 잡는 것이 중요했다.
회원가입을 넣으면 관리가 쉬워질 수 있지만 사용자에게는 부담이 된다.
반대로 아무 제약 없이 작성하게 하면 운영 리스크가 생긴다.

이번에는 그 중간 지점으로, 계정 없이 작성하되 비밀번호로 본인 삭제를 허용하는 방식을 선택했다.

다음에 비슷한 기능을 만들게 된다면 처음부터 “이 기능에 정말 회원가입이 필요한가?”를 먼저 질문해볼 것 같다.
기능의 무게를 프로젝트 목적에 맞게 조절하는 것도 개발자의 중요한 역할이라는 걸 배웠다.