Search

Vantech Event Finder - 로컬 IT 이벤트 탐색기

Tags
Typescript
NextJS
Prisma
Created
2023.05.16 - 2023.08.30

프로젝트명

Vantech Event Finder

제작기간

2023.05.16 - 2023.08.30

개발스택

프론트엔드 : Nextjs 13 / T3 / Typescript / Mantine
백엔드 : Postgres, Prisma, TRPC

프로젝트 기획 및 소개

Vantech Event Finder 프로젝트는 밴쿠버에서 열리는 다양한 IT 이벤트를 쉽게 찾을 수 있도록 돕기 위해 기획되었습니다. 밴쿠버는 각종 취미 소모임과 다양한 네트워킹 이벤트가 매달 개최됩니다. 그에 맞게 Meet Up 어플이나 Eventbrite 등 모임을 찾을 수 있는 어플도 다양합니다. 그 중에도 IT 에 관련된 이벤트를 한 곳에 모아 쉽게 검색하고 관리할 수 있는 도구를 만들어 보자는 생각으로 프로젝트가 시작되었습니다

개발 인원

프론트엔드 4명

주요 특징

T3 스택 기반 반응형 웹사이트
Google Map API를 활용한 위치 기반 IT 이벤트 탐색
Meetup API 연동 및 날짜별 이벤트 필터링
Prisma ORM과 PostgreSQL을 활용한 데이터 관리

프로젝트 담당

전체 시스템 설계 및 구현:

프로젝트 초기 단계에서 팀원들과 T3 스택 아키텍처를 학습하고 새로나온 Next.js 13 App Router 구조를 함께 설계했습니다. 또한 효율적인 협업 및 코드 품질 유지를 위해 Husky를 설치하여 커밋 전 타입 체크와 린팅이 자동으로 실행되도록 설정했습니다.

프론트엔드:

4명의 프론트엔드 개발자가 역할을 분담하여 프로젝트를 진행했습니다. 제가 맡은 부분은 Google Maps API 연동, 공통 UI 컴포넌트 개발 및 테마 설정이었으며 이후에 추가적으로 Railway에서 PostgreSQL 데이터베이스 설정도 진행했습니다. 개발 속도를 위해 T3 기본 스택인 Tailwind 대신 Mantine의 디자인 시스템을 사용했고 tRPC 부분은 서버 개발을 해본 팀원이 담당했습니다.

배포 및 운영:

프로젝트는 Netlify로 배포하여 코드 변경 시 자동으로 테스트 및 배포가 이루어지도록 했습니다. 데이터 관리는 T3의 기본 스택인 Prisma로 데이터베이스 스키마를 설계하고 타입 안전한 쿼리 작업을 수행했습니다. 실제 데이터는 Railway 클라우드 서비스에서 제공하는 PostgreSQL 데이터베이스에 저장하여 데이터 운영 환경을 만들었습니다.

프로젝트 Preview

메인 페이지
이벤트 지도 페이지
이벤트 목록 페이지
지도에 표시된 이벤트 + 즐겨찾기 기능
회원가입 페이지
즐겨찾기 항목

프로젝트 주요 기능

1. Google Map API

날짜, 위치, 카테고리 등 다양한 필터링 옵션을 제공하여 사용자가 원하는 이벤트를 빠르게 찾을 수 있도록 합니다. 주요 기능은 다음과 같습니다:
위치 기반 검색: 사용자가 현재 위치를 기준으로 주변 이벤트를 검색할 수 있습니다.
날짜별 검색: 특정 날짜나 기간 동안 열리는 이벤트를 검색할 수 있습니다.
이벤트 핀: 각 이벤트 위치에 핀을 표시하여 지도를 통해 이벤트 위치를 직관적으로 확인할 수 있습니다.
코드 예시
import { useState, useEffect } from "react"; import { useMantineColorScheme } from "@mantine/core"; import { mapTheme, loader } from "~/utils"; export const GoogleMaps = () => { const [map, setMap] = useState<google.maps.Map>(); const { colorScheme } = useMantineColorScheme(); useEffect(() => { const fetchMap = async () => { await loader.load().then(() => { navigator.geolocation.getCurrentPosition( (position) => { const { latitude, longitude } = position.coords; const mapOptions = { center: { lat: latitude, lng: longitude }, zoom: 16, styles: colorScheme === "dark" ? mapTheme.dark : mapTheme.light, }; const newMap = new window.google.maps.Map( document.getElementById("map") as HTMLElement, mapOptions ); const marker = new window.google.maps.Marker({ position: { lat: latitude, lng: longitude }, map: newMap, }); setMap(newMap); } }); }); }; void fetchMap(); }, [colorScheme]); return <div id="map" style={{ height: "100%", width: "100%" }}></div>; };
TypeScript
복사

2. next-auth 로 login & signup 기능 구현

로그인 기능은 next-auth를 사용하여 구현되었습니다. 사용자는 이메일과 비밀번호를 입력하여 로그인할 수 있으며 로그인 성공 시 홈 페이지로 리디렉션됩니다. 폼 유효성 검사 및 상태 관리를 위해 Mantine의 useForm 훅을 사용합니다. 로그인 요청은 signIn 함수를 통해 처리됩니다.
코드 예제
1.
next-auth 설정 파일 (app/api/auth/[...nextauth].ts)
import NextAuth from 'next-auth'; import Providers from 'next-auth/providers'; export default NextAuth({ providers: [ Providers.Credentials({ name: 'Credentials', credentials: { email: { label: "Email", type: "email" }, password: { label: "Password", type: "password" } }, async authorize(crd) { const user = await yourUserLoginFunction(crd.email, crd.password); return user || null ; } }) ], session: { jwt: true }, // ... });
TypeScript
복사
2.
로그인 페이지 (app/(auth)/login/page.tsx)
const LogIn: React.FC = () => { const { data: session } = useSession(); const router = useRouter(); const [error, setError] = useState(''); const theme = useMantineTheme(); const form = useForm({ initialValues: { email: '', password: '', rememberPassword: false, }, validateInputOnChange: true, validate: { password: (value) => (value.length < 1 ? 'Please input Password' : null), email: (value) => (value.length < 1 ? 'Please input email address' : null), }, }); const isDisabled = Object.keys(form.errors).length !== 0; const handleSubmit = async (values: { email: string; password: string; rememberPassword: boolean }) => { try { const result = await signIn('credentials', { redirect: false, email: values.email, password: values.password, }); if (!result?.error) { if (!session) { await signIn('credentials', { redirect: false, email: values.email, password: values.password, }); } form.reset(); router.push('/'); } else { form.reset(); throw new Error(); } } catch (error) { setError('Failed to login!'); } }; if (session) router.push('/'); }; export default LogIn;
TypeScript
복사

3. Prisma를 사용한 Postgres 데이터베이스 설정

Prisma를 사용하여 Postgres 데이터베이스를 설정하고, 데이터베이스와의 상호작용을 단순화하였습니다.
이 프로젝트의 데이터베이스 관리에는 Prisma가 사용되었습니다. Prisma를 사용하여 Postgres 데이터베이스를 설정하고 사용자, 세션, 계정 및 관련된 인증 토큰에 타입을 부여해서 개발 생산성을 높였습니다.
코드 예시
// This is your Prisma schema file, generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ----- App Schema ------ // model FavEvent { id String @id @default(cuid()) userId String date DateTime @default(now()) } model User { id String @id @default(cuid()) name String? email String? @unique password String emailVerified DateTime? image String? accounts Account[] sessions Session[] } // ...
TypeScript
복사

프로젝트 회고

What 무엇을 했나요?

NextJS의 App Routing을 이해하고 T3 스택을 활용한 풀스택 웹 애플리케이션을 구현했습니다.
Meetup API로 실시간 이벤트 데이터를 가져오고 Google Maps API로 이벤트 위치를 시각화했습니다.

How 어떻게 해결했나요?

직장인 팀원들의 시간적 제약을 고려해 비동기 코드리뷰와 2주 단위 온라인 회의를 진행했습니다.
Mantine UI 라이브러리를 활용하여 일관된 디자인 시스템을 구축하고 개발 속도를 향상시켰습니다.

Then 앞으로의 개선점?

이번 프로젝트에서는 프론트엔드 기술 위주로 개발을 진행했지만 tRPC에 대한 추가 학습을 통해 다음 프로젝트에서는 풀스택 개발에 도전해보고 싶습니다.
메인으로 돌아가기