
관리자 페이지는 서비스 운영자가 데이터를 등록하고 조회하며 수정하거나 삭제하는 내부 화면입니다. 이런 네 가지 기본 작업을 각각 생성(Create), 조회(Read), 수정(Update), 삭제(Delete)라고 하며, 앞글자를 묶어 CRUD라고 부릅니다.
페스티봄에도 축제 정보를 관리하는 화면이 필요했습니다. 처음에는 정해진 형식의 JSON을 만들어 직접 입력했지만, 축제와 티켓 정보를 하나씩 옮기다 보니 시간이 오래 걸렸어요. 일부 내용을 놓치거나 같은 정보를 중복해서 넣는 일도 생겼죠.
문제는 최초 등록으로 끝나지 않았습니다. 티켓은 여러 차례에 걸쳐 판매되고 아티스트 라인업도 순서대로 공개됩니다. 새로운 발표가 나올 때마다 기존 데이터와 비교해 필요한 내용만 추가해야 했습니다.
이번 글에서는 Next.js와 Supabase로 만든 페스티봄 관리자 페이지의 기능을 살펴봅니다. JSON 가져오기, 아티스트 중복 확인, 검수 대기와 최종 승인 기능이 어떤 방식으로 연결되는지 설명하고, 직접 운영하면서 자동화하지 못한 부분도 함께 정리했습니다.
관리자 페이지란? 데이터 등록·수정·삭제 기능 알아보기
공개 페이지가 방문자에게 축제 정보를 보여주는 화면이라면, 관리자 페이지는 그 정보를 준비하고 관리하는 작업 공간입니다. 운영자는 이곳에서 새 축제를 등록하고 기존 내용을 고치며, 잘못된 자료를 확인합니다.
- 생성(Create): 새로운 축제, 티켓, 아티스트 정보를 등록합니다.
- 조회(Read): 저장된 정보와 검수 대기 중인 작업을 불러옵니다.
- 수정(Update): 새로 발표된 티켓이나 라인업을 기존 축제에 반영합니다.
- 삭제(Delete): 잘못 만든 임시 작업이나 필요 없는 데이터를 정리합니다.
Supabase 프로젝트에는 Postgres 데이터베이스가 제공됩니다. 대시보드의 테이블 편집기나 SQL 편집기에서도 데이터를 관리할 수 있고, 웹앱에서는 Data API와 클라이언트 라이브러리를 이용해 같은 작업을 실행할 수 있습니다.[1]
다만 운영할 때마다 Supabase 대시보드에서 행을 직접 찾는 방식은 오래 유지하기 어려웠습니다. 필드 이름과 테이블 관계를 알고 있어야 하고, 관련된 여러 정보를 빠뜨리지 않고 함께 바꿔야 하기 때문입니다. 그래서 페스티봄에서 자주 하는 작업만 모은 별도의 관리자 화면을 만들게 됐어요.
Supabase CRUD로 축제 정보를 관리하는 방식
Next.js 관리자 화면에서 입력한 값은 Supabase로 전달됩니다. 예를 들어 축제명, 시작일, 종료일을 입력하고 등록 버튼을 누르면 화면이 값을 확인한 뒤 데이터베이스 함수를 호출합니다.
아래 코드는 페스티봄의 실제
createFestival함수에서 축제 등록에 해당하는 부분을 줄여 옮긴 것입니다.
const { data, error } = await supabase.rpc(
"create_festival_with_audit",
{ p_festival: festivalData }
);
rpc는 Supabase에서 데이터베이스 함수를 호출하는 방법입니다. 입력값을 festivalData라는 묶음으로 전달하면 함수가 축제 정보를 저장합니다. 일반적인 데이터 추가에는 insert(), 수정에는 update()를 사용할 수도 있습니다.[2][3]
처음부터 이런 구조를 알고 만든 것은 아닙니다. 한 단계짜리 등록 기능을 먼저 만들고, 필요한 기능이 생길 때마다 추가했습니다. 이후 서로 떨어진 기능을 합치고 다시 정리하는 과정을 여러 차례 반복했어요. 어디까지 구현할 수 있는지 몰랐고 방법도 알지 못했기 때문에, 완성된 관리자 시스템을 한 번에 설계하기가 불가능했습니다.
축제·티켓과 아티스트 관리 기능을 분리한 이유
페스티봄 관리자 기능은 축제·티켓 관리와 아티스트 관리를 나눴어요. 축제와 티켓은 한 화면의 작업 흐름에서 처리하지만, 기존 아티스트 정보는 아티스트 관리 페이지에서만 수정하도록 제한했습니다.
아티스트가 중복되면 같은 사람이 서로 다른 아티스트로 저장될 수 있습니다. 출연 축제와 일정도 두 곳으로 나뉘기 때문에, 이름이 비슷하다는 이유만으로 자동 등록하거나 기존 정보를 바로 고치면 문제가 커집니다.
신규 페스티벌을 등록할 때는 작업 흐름 안에서 새로운 아티스트를 추가할 수 있습니다. 반면 기존 축제를 수정할 때 새 아티스트가 필요하면 먼저 아티스트 관리 페이지에 등록한 뒤 연결합니다. 기존 아티스트의 이름과 식별값, 별칭도 등록 화면에서 직접 바꾸지 않습니다.
기능을 나누니 한 단계가 늘어나는 불편은 있었습니다. 대신 축제 정보를 고치다가 아티스트 원본까지 함께 바꾸는 실수를 줄일 수 있었어요. 관리자 페이지의 편의성뿐 아니라 어떤 화면에 수정 권한을 둘지도 중요하다는 점을 이 과정에서 배웠습니다.
JSON 가져오기로 여러 정보를 한 번에 등록하는 기능
JSON 가져오기는 축제, 아티스트, 티켓처럼 서로 관련된 정보를 정해진 모양으로 묶어 전달하는 기능입니다. 입력 칸을 하나씩 채우는 대신 JSON 초안을 읽어 관리자 화면의 각 단계에 값을 배치합니다.
{
"festival": {
"name": "2026 축제명",
"start_date": "2026-09-01",
"end_date": "2026-09-02"
},
"artists": [],
"tickets": []
}
여기서 JSON은 곧바로 운영 데이터가 되는 파일이 아닙니다. 페스티봄에서는 검수 전 임시자료로만 사용합니다. 날짜가 빠졌거나 포스터 글자를 잘못 읽었을 수 있으므로, 자동 생성된 값을 먼저 작업함에 저장하고 관리자가 확인한 뒤 최종 반영합니다.
초기에는 이 JSON도 제가 직접 만들었습니다. 수동 입력보다 형식은 일정해졌지만 정보를 모으고 옮기는 시간은 그대로 들었어요. 티켓 판매처나 라인업 일부를 빠뜨릴 가능성도 남아 있었고요. JSON 형식을 사용하는 것과 JSON을 자동으로 만드는 것은 별개의 문제였습니다.
디스코드 봇과 이미지 인식으로 JSON 초안을 만드는 과정
수동 작업을 줄이기 위해 디스코드 봇을 연결했어요. 제가 인스타그램 게시물 링크를 보내면 봇이 게시물의 이미지와 캡션을 확인하고, 이미지에서 축제 정보를 추출해 JSON 초안을 만듭니다.
인스타그램 링크 전송
→ 게시물 이미지·캡션 확인
→ 이미지에서 축제 정보 추출
→ 축제·아티스트·티켓 JSON 생성
→ 기존 데이터와 비교
→ 관리자 검수 작업 생성
실제 코드에서는 이미지에서 보이는 정보만 사용하고, 알 수 없는 시간이나 무대는 빈 값으로 남기도록 지시합니다. 포스터에 적힌 원문도 보존합니다. 자동화 과정에서 그럴듯한 값을 채우는 것보다 검수할 근거를 남기는 편이 중요했죠.
봇은 생성한 초안을 Supabase의 임시 작업 테이블에 저장하고 관리자 링크를 돌려줍니다. 예전에는 JSON을 직접 만들고 화면에 입력해야 했지만, 이제는 링크를 한 번 보내면 검수 단계 전까지 자동으로 진행돼요.
검수 대기와 승인 기능으로 데이터 오류를 막는 방식
자동으로 만든 JSON을 바로 공개 데이터에 넣지는 않았습니다. 신규 축제와 기존 축제 수정 작업을 임시 상태로 저장한 뒤, 관리자 화면에서 내용을 단계별로 확인합니다.
- 추출된 아티스트가 기존 아티스트인지 신규인지 확인합니다.
- 전체 라인업을 다시 비교합니다.
- 축제 기본정보와 티켓을 검토합니다.
- 공연 날짜·시간·무대 정보를 확인합니다.
- 마지막 요약을 확인하고 최종 승인합니다.
최종 승인 전에는 운영 데이터가 바뀌지 않습니다. 마지막 단계에서 축제, 신규 아티스트, 라인업과 티켓을 한 번에 반영하고, 하나라도 실패하면 중간 결과를 남기지 않는 구조로 만들었습니다.
이 과정이 필요한 이유는 자동 추출 결과가 항상 정확하지 않기 때문입니다. 아티스트 이름의 다른 표기, 여러 날짜에 걸친 일정, 티켓 회차처럼 문맥을 보고 판단해야 하는 값이 있습니다. 관리자 페이지는 자동 입력 화면이면서 동시에 잘못된 입력을 운영 데이터와 분리하는 검수 장치였습니다.
중복 아티스트를 막기 위한 별도 관리 기능
아티스트 중복 확인은 이름을 눈으로 비교하는 것보다 복잡했습니다. 영문 표기, 한글 독음과 특수문자 차이 때문에 같은 아티스트가 다르게 보일 수 있습니다.
페스티봄에서는 비교용 normalized_name이 정확히 일치할 때만 기존 아티스트를 자동 연결합니다. 이름이나 별칭이 비슷한 후보는 보여주되 관리자가 직접 선택하도록 했습니다. 자동 연결 기준을 느슨하게 만들면 다른 아티스트를 한 사람으로 합칠 위험이 있기 때문입니다.
처음에는 등록 화면에서 필요한 것을 모두 수정할 수 있으면 편하다고 생각했습니다. 기능이 늘어난 뒤에는 편집 범위를 좁히는 쪽으로 바뀌었습니다. 기존 아티스트 정보는 한곳에서만 고치고, 축제 관리자에서는 연결 관계만 다루는 방식입니다.
티켓·라인업 변경 정보를 기존 데이터에 반영하는 방법
축제 정보 관리에서 예상보다 어려웠던 기능은 기존 데이터 수정이었습니다. 신규 축제 한 건을 등록하는 일은 시작과 끝이 비교적 분명합니다. 티켓과 라인업은 발표가 여러 번 이어져 현재 값과 새 값을 계속 비교해야 합니다.
새 게시물에 기존 정보가 없다고 해서 삭제된 것은 아닙니다. 1차 라인업 게시물에 있던 아티스트가 2차 발표 이미지에 나오지 않더라도 출연 취소라고 볼 수 없죠. 따라서 새 JSON에 없는 기존 아티스트와 티켓은 그대로 유지하고, 관리자가 선택한 추가·변경만 반영하도록 했습니다.
봇이 새 자료를 가져오면 축제 이름과 날짜를 이용해 신규 등록인지 기존 축제 수정인지 구분합니다. 이름이 비슷하지만 정확히 일치하지 않는 축제는 자동으로 합치지 않고 중복 검토 대상으로 보냅니다. 수정 작업에서는 기존 값과 새 값을 나란히 보여주고 반영할 항목을 선택합니다.
이 기능도 한 번에 완성하지 못했어요. 신규 등록 기능을 만든 뒤 기존 수정 기능을 더했고, 중복 확인과 임시저장, 단계별 승인 기능을 차례로 붙였습니다. 기능을 합친 다음 구조를 정리하고, 또 다른 문제가 발견되면 다시 분리하는 작업이 반복됐습니다.
인스타그램 자동 수집이 어려워 수동 확인이 남은 이유
관리자 시스템을 만들고 입력 과정을 자동화해도 정보 수집까지 완전히 해결되지는 않았습니다. 축제마다 티켓 판매와 라인업 발표 시점이 다르고, 같은 축제도 여러 게시물에 나누어 정보를 공개합니다.
인스타그램 게시물을 자동으로 계속 크롤링하는 방식은 구현하기 어려웠습니다. 결국 새로운 발표가 나왔는지는 제가 직접 인스타그램을 확인해야 합니다. 관련 게시물을 찾은 뒤 디스코드에 링크를 보내는 단계도 수동으로 남았어요.
대신 링크를 보낸 다음부터 검수 화면이 만들어지기 전까지는 자동으로 처리됩니다. 사람이 자료의 존재를 발견하고, 시스템이 반복 입력과 비교를 맡으며, 마지막 판단은 다시 사람이 하는 구조입니다.
직접 운영해보니 자동화는 사람을 완전히 빼는 기능이 아니었습니다. 반복해서 옮기던 작업을 줄이고, 사람이 확인해야 할 지점을 좁히는 쪽에 가까웠습니다. 페스티봄 관리자 페이지도 모든 정보를 알아서 모으는 시스템은 아니지만, 수동 JSON 입력에서 생기던 시간 낭비와 누락을 줄이는 운영 도구가 됐습니다.
참고 자료
- Supabase Database Overview — Supabase의 Postgres 데이터베이스와 관리 방법 설명에 참고했습니다.
- Supabase JavaScript Insert Data — 데이터 생성과 여러 행 등록 방식 설명에 참고했습니다.
- Supabase JavaScript Update — 조건에 맞는 데이터 수정 방식 설명에 참고했습니다.
함께 읽는 시리즈
비개발자의 바이브 코딩 도전기
-
1편
비개발자 바이브 코딩 후기: 어려웠던 이유 5가지
-
2편
LLM 코드 생성 원리: 2026 Codex는 코드를 어떻게 수정할까?
-
3편
2026 비전공자의 첫 바이브 코딩 MVP 만들기: 페스티봄 핵심 기능과 범위 정하기
-
4편
컴포넌트란? 2026 바이브 코딩 컴포넌트 비개발자가 부딪히며 배운 코드 재사용 방법
-
5편
데이터베이스 설계 방법: 2026 비개발자가 축제와 아티스트를 연결한 과정
-
6편 · 현재 글
2026 Next.js·Supabase 관리자 페이지 만들기: JSON 등록과 승인 기능 구현
-
7편
2026 비개발자 Next.js 캘린더 만들기: 라이브러리 없이 페스티벌 일정 구현하기
-
8편
리팩토링이란? 2026 비개발자가 바이브 코딩 코드 구조를 나눈 방법
-
9편
Next.js Supabase 보안 설정: 2026 비개발자가 RLS·MFA·서비스 테스트까지 한 과정