프로젝트 문서

Gin Song·2025년 3월 24일



프로젝트 정의서

개요

프로젝트명

목표

사용자 정의

요구사항


요구사항 정의서 참고

시스템 아키텍처


아키텍처 개요

  • 프론트엔드:
  • 백엔드:
  • 데이터베이스:

모듈 구성

  • 프론트엔드:
  • 백엔드:
  • 데이터베이스:

인터페이스 설계

  • 프론트엔드-백엔드 인터페이스:
  • 백엔드-데이터베이스 인터페이스:

설계 상세


사용자 스토리

구현 계획


개발 환경

  • 프론트엔드: React, TypeScript,
  • 백엔드:
  • 데이터베이스:
  • 도구: Visual Studio Code, Git

개발 일정

  • 요구사항 분석 및 설계
  • UI/UX 디자인
  • 백엔드 개발
  • 프론트엔드 개발
  • 통합 및 테스트
  • 배포 및 유지보수

자원 계획

  • 프론트엔드 개발자: 3명

테스트 계획

품질 보증

코드 리뷰, 자동화 테스트(E2E)

배포 계획

배포 전략

스테이징 환경에서 충분한 테스트 후 프로덕션 환경에 배포

유지보수 계획

버그 수정 및 기능 개선을 위한 정기 업데이트

문서화

사용자 매뉴얼

시스템 사용법을 상세히 설명하는 매뉴얼 작성

개발자 문서

시스템 아키텍처, API 명세서, 코드 설명서 작성

용어 정의

주요 용어와 약어 정의


API 및 인프라 협업 가이드라인

프론트엔드

  • API 호출 및 상태 관리
    - api 호출하기 전에 무조건 useEffect 폭주하는 거 없는지 확인하고 호출해주세요. (서버가 아파해요)
    • 불필요한 API 호출을 피하기 위해 useEffect 등 훅 사용 시 의존성 배열을 신중하게 관리해주세요
    • 빠른 연속 호출(예: 버튼 클릭 시)에는 디바운스(또는 스로틀)를 적용하여 서버 과부하를 방지해주세요
  • 응답 데이터 캐싱
    - 코드 내 직접 캐싱보다는 react-query와 같은 라이브러리의 응답 캐싱 기능을 활용하여 최신 데이터를 하지 말아주세요. ( 에디터 부분 한정 )
    - 에디터 같은 동시 편집도구에서 캐시하면 동기화 문제가 발생할 수 있어요.
  • 파일 업로드 구현
    - presigned URL 사용하니 백엔드 문서 참고해서 업로드 기능 구현해주세요.
  • 배포 및 CDN 활용
    - 배포 시 CloudFront + S3 또는 Cloudflare와 같은 CDN 솔루션을 활용해주세요.
    - 기존의 EC2 + Nginx 방식에 의존하지 않는 것이 좋을 것 같습니다. (자신있으면 해도 상관없어요! ex) 모니터링, 로그 분석 등등등 )


백엔드

  • 입력 데이터 검증
    - 프론트엔드에서 전달받은 데이터에 대해 반드시 철저한 검증을 실시하여 보안을 강화.
  • REST API 규칙
    - HATEOAS 등 과도한 규칙 적용보다는 기본 REST 규칙을 준수.
    - 응답 상태코드는 상황에 맞게 200, 201, 204, 400, 401, 403, 404, 429(필요시 415 등)로 명확히 구분.
    - GET 요청은 Body 없이 처리할 것.
    - PUT 요청은 멱등성 원칙을 고려하되, 과도한 오버엔지니어링은 피할 것.
  • API 응답 구조 (flat vs. nested)
    - 프론트엔드와의 협의 하에 필요한 데이터만 전달하여 불필요한 네트워크 부하를 줄이고 캐시 관리에 용이하도록 설계.
    - 혼합 방식 사용 시 프론트엔드에서 과도한 API 호출 없이 단일 응답으로 필요한 정보를 받을 수 있도록 고려.
  • API 응답 포맷 (Response 배열, 페이지 처리)
    - 응답 형식은 프론트엔드와 협의하여 단일 API 호출로 필요한 데이터를 제공할 수 있도록 설계할 것.
    • 예: 단일 객체 내에 blogs: [] 배열 및 페이지 정보를 포함.
  • 읽기 전용 API 설계
    - 모듈 분리 후 읽기 전용 엔티티를 별도로 설계하여 성능 및 확장성을 고려할 것.
    - Jooq, CQRS, 또는 replica DB 활용 등 읽기 전용 환경 구축 방안을 적극 검토.
    200, { [ {}, {} ] }
    vs
    200, { "result": [ {}, {} ] }
  • ResponseEntity 사용
    - 기본적으로 ResponseEntity를 사용할 필요가 없으나, 특별한 케이스(예외 처리 등)에서 유용하게 활용할 수 있음.
  • Service Entity 반환
    - OSIV 사용 여부와 관계없이, 직접 Service의 Entity를 반환하는 것은 문제가 될 수 있지만 적용함.
    - OSIV를 비활성화한 경우라 하더라도 반환 객체의 범위를 명확히 관리할 것.
  • 보안 및 인증 (JWT)
    - JWT 기반 인증을 기본으로 하고, Access/Refresh Token 관리 정책(예: RefreshToken은 Cookie, AccessToken은 Response Body)에 따라 구현.
    - 필요 시 Redis 등 캐시 솔루션을 활용하여 세션 및 토큰 관리를 최적화.
  • 파일 업로드 처리
    - 서버 리소스 절감을 위해 멀티파트 파일 업로드 대신 presigned URL 방식을 적극 활용.
    - 파일 업로드의 단계(초기화, 중간 발송, 확인, 중단, 삭제)를 구현하며 관련 기술 블로그 참고.
  • S3 및 이미지 관리
    - S3 관리 주체(백엔드/프론트엔드)와 역할 분담을 명확히 하고, 이미지 압축 작업의 책임 범위를 결정.
    - 이미지 업로드는 presigned URL을 통한 직접 업로드를 적용하며, 서버에서 최종 검증 및 ID 연동 처리.
  • 캐싱 및 트래픽 관리
    - 캐시 전략(캐시 쇄도, 지터 등) 관련 이슈를 사전에 논의하여 전체 시스템에 영향을 주지 않는 방향으로 설정.
    - 캐시 트래픽 관련 참고 자료를 기반으로 최적 방안을 마련.




API 명세서

/api/v1/projects/{id}

  • GET
    • 설명: 지정된 ID를 가진 프로젝트의 세부 정보를 조회합니다. 프로젝트 이름, 활성 상태, 데이터, 버전 등의 정보를 반환합니다.
    • 파라미터: id (path, 필수, int64) - 조회할 프로젝트의 고유 ID
    • 응답: 200 OK - ProjectDetailResponse
      {
        "id": 1,
        "name": "Sample Project",
        "active": true,
        "data": "{\\"key\\": \\"value\\"}", // 미정
        "version": 2,
        "lastAccessedAt": "2025-03-19T10:00:00Z",
        "createdAt": "2025-01-01T09:00:00Z",
        "updatedAt": "2025-03-18T15:30:00Z"
      }
      
  • PUT
    • 설명: 지정된 ID를 가진 프로젝트의 정보를 업데이트합니다. 이름이나 데이터 등의 필드를 수정할 수 있습니다.
    • 파라미터: id (path, 필수, int64) - 업데이트할 프로젝트의 고유 ID
    • 요청 본문: ProjectUpdateRequest
      {
        "name": "Updated Project",
        "data": "{\\"newKey\\": \\"newValue\\"}"
      }
      
    • 응답: 200 OK - ProjectDetailResponse
      {
        "id": 1,
        "name": "Updated Project",
        "version": 3,
        "createdAt": "2025-01-01T09:00:00Z",
        "updatedAt": "2025-03-19T12:00:00Z"
      
    • 응답: 409 Conflict - 버전 충돌이 발생한 경우 (버전 3→2 또는 2→4 등)
      {
          "message": "meeor message",
          "exceptionCode": "error code"
      }
  • DELETE
    • 설명: 지정된 ID를 가진 프로젝트를 삭제합니다.
    • 파라미터: id (path, 필수, int64) - 삭제할 프로젝트의 고유 ID
    • 응답: 200 OK - 응답 본문 없음

/api/v1/templates/suggest

  • POST
    • 설명: 주어진 텍스트(예: 기사)를 기반으로 적합한 템플릿을 추천합니다. 템플릿 추천 시스템을 활용한 기능입니다.
    • 요청 본문: TemplateSuggestRequest
      {
        "article": "This is a sample article about technology."
      }
      
    • 응답: 200 OK - TemplateSuggestResponse
      {
        "items": [
          {
            "id": 101,
            "priority": 1,
            "data": {
              "name": "Tech Template",
              "category": "Social",
              "size": {
                "width": 1920,
                "height": 1080
              },
              "background": {
                "id": 10,
                "name": "Tech BG",
                "priority": 1,
                "type": "Image",
                "fileUrl": "<http://example.com/tech-bg.jpg>",
                "size": {
                  "width": 1920,
                  "height": 1080
                },
                "createdAt": "2025-01-01T00:00:00Z",
                "updatedAt": "2025-01-01T00:00:00Z"
              },
              "avatar": {
                "id": 20,
                "name": "Tech Avatar",
                "priority": 2,
                "fileUrl": "<http://example.com/tech-avatar.png>",
                "createdAt": "2025-01-01T00:00:00Z",
                "updatedAt": "2025-01-01T00:00:00Z"
              }
            },
            "createdAt": "2025-01-01T00:00:00Z",
            "updatedAt": "2025-01-01T00:00:00Z"
          }
        ],
        "_info": {
          "category": {
            "id": 1,
            "name": "Social"
          }
        }
      }
      

/api/v1/tasks/{taskId}/retry

  • POST
    • 설명: 지정된 작업(task)을 재시도합니다. 실패한 작업을 다시 실행하거나 재처리할 때 사용됩니다.
    • 파라미터: taskId (path, 필수, int64) - 재시도할 작업의 고유 ID
    • 응답: 200 OK - TaskResponse
      {
        "id": 50,
        "projectId": 1,
        "jobId": "job-12345",
        "type": "VIDEO",
        "status": "PENDING",
        "output": {},
        "retryCount": 2,
        "createdAt": "2025-03-18T10:00:00Z",
        "updatedAt": "2025-03-19T12:00:00Z"
      }
      

/api/v1/projects

  • GET
    • 설명: 모든 프로젝트 목록을 조회합니다. 프로젝트의 기본 정보(이름, 활성 상태 등)를 반환합니다.
    • 응답: 200 OK - ListResponseProjectResponse
      {
        "data": [
          {
            "id": 1,
            "name": "Project A",
            "active": true,
            "version": 1,
            "lastAccessedAt": "2025-03-19T10:00:00Z",
            "createdAt": "2025-01-01T09:00:00Z",
            "updatedAt": "2025-03-18T15:00:00Z"
          },
          {
            "id": 2,
            "name": "Project B",
            "active": false,
            "version": 2,
            "lastAccessedAt": "2025-03-15T14:00:00Z",
            "createdAt": "2025-02-01T09:00:00Z",
            "updatedAt": "2025-03-16T10:00:00Z"
          }
        ]
      }
      
  • POST
    • 설명: 새로운 프로젝트를 생성합니다. 생성된 프로젝트의 세부 정보를 반환합니다.
    • 응답: 200 OK - ProjectDetailResponse
      {
        "id": 3,
        "name": "New Project",
        "active": true,
        "data": "{\\"key\\": \\"value\\"}",
        "version": 1,
        "lastAccessedAt": "2025-03-19T12:00:00Z",
        "createdAt": "2025-03-19T12:00:00Z",
        "updatedAt": "2025-03-19T12:00:00Z"
      }
      

/api/v1/auth/refresh

  • POST
    • 설명: 리프레시 토큰을 사용하여 새로운 액세스 토큰을 발급받습니다. 인증 연장을 위해 사용됩니다.
    • 응답: 200 OK - LoginResponse
      {
        "accessToken": "new-access-token-123",
        "refreshToken": "new-refresh-token-456"
      }
      

/api/v1/auth/logout

  • POST
    • 설명: 현재 사용자의 세션을 종료하고 로그아웃합니다.
    • 응답: 204 No Content - 응답 본문 없음

/api/v1/auth/login

  • POST
    • 설명: 사용자 이름과 비밀번호를 사용하여 로그인하고 인증 토큰을 발급받습니다.
    • access token과 refesh token을 응답으로 반환하며 쿠키에 refresh token을 설정합니다.
    • 요청 본문: LoginRequest
      {
        "username": "user@example.com",
        "password": "securepassword123"
      }
      
    • 응답: 200 OK - LoginResponse
      {
        "accessToken": "access-token-789",
        "refreshToken": "refresh-token-101"
      }
      

/api/v1/account/register

  • POST
    • 설명: 새로운 사용자 계정을 등록합니다. 이메일, 비밀번호, 이름 등의 정보를 받아 계정을 생성합니다.
    • 요청 본문: RegisterRequest
      {
        "email": "newuser@example.com",
        "code": "ABC123",
        "password": "newpassword456",
        "name": "John Doe",
        "nickname": "johndoe",
        "phone": "123-456-7890"
      }
      
    • 응답: 200 OK - RegisterResponse
      {
        "memberId": 1001
      }
      

/api/v1/account/register/verify-email

  • POST
    • 설명: 계정 등록 시 이메일 인증을 수행합니다. 이메일과 인증 코드를 확인합니다.
    • 요청 본문: VerifyEmailRequest
      {
        "email": "newuser@example.com",
        "code": "ABC123"
      }
      
    • 응답: 204 No Content - 응답 본문 없음

/api/v1/account/register/check-email

  • POST
    • 설명: 이메일 인증을 시도합니다. 요청한 이메일로 인증 메일을 보냅니다.
    • 요청 본문: CheckEmailRequest
      {
        "email": "newuser@example.com"
      }
      
    • 응답: 204 No Content - 응답 본문 없음

/api/v1/templates

  • GET
    • 설명: 모든 템플릿 목록을 조회합니다. 카테고리 ID를 선택적으로 지정하여 필터링할 수 있습니다.
    • 파라미터: categoryId (query, 선택, int32) - 필터링할 카테고리 ID
    • 응답: 200 OK - ListResponseTemplateResponse
      {
        "data": [
          {
            "id": 101,
            "priority": 1,
            "data": {
              "name": "Social Media Template",
              "category": "Social",
              "size": {
                "width": 1080,
                "height": 1080
              },
              "background": {
                "id": 10,
                "name": "Social BG",
                "priority": 1,
                "type": "Image",
                "fileUrl": "<http://example.com/social-bg.jpg>",
                "size": {
                  "width": 1080,
                  "height": 1080
                },
                "createdAt": "2025-01-01T00:00:00Z",
                "updatedAt": "2025-01-01T00:00:00Z"
              },
              "avatar": {
                "id": 20,
                "name": "Social Avatar",
                "priority": 2,
                "fileUrl": "<http://example.com/social-avatar.png>",
                "createdAt": "2025-01-01T00:00:00Z",
                "updatedAt": "2025-01-01T00:00:00Z"
              }
            },
            "createdAt": "2025-01-01T00:00:00Z",
            "updatedAt": "2025-01-01T00:00:00Z"
          }
        ]
      }
      

/api/v1/templates/{id}

  • GET
    • 설명: 지정된 ID를 가진 템플릿의 세부 정보를 조회합니다.
    • 파라미터: id (path, 필수, int64) - 조회할 템플릿의 고유 ID
    • 응답: 200 OK - TemplateResponse
      {
        "id": 101,
        "priority": 1,
        "data": {
          "name": "Social Media Template",
          "category": "Social",
          "size": {
            "width": 1080,
            "height": 1080
          },
          "background": {
            "id": 10,
            "name": "Social BG",
            "priority": 1,
            "type": "Image",
            "fileUrl": "<http://example.com/social-bg.jpg>",
            "size": {
              "width": 1080,
              "height": 1080
            },
            "createdAt": "2025-01-01T00:00:00Z",
            "updatedAt": "2025-01-01T00:00:00Z"
          },
          "avatar": {
            "id": 20,
            "name": "Social Avatar",
            "priority": 2,
            "fileUrl": "<http://example.com/social-avatar.png>",
            "createdAt": "2025-01-01T00:00:00Z",
            "updatedAt": "2025-01-01T00:00:00Z"
          }
        },
        "createdAt": "2025-01-01T00:00:00Z",
        "updatedAt": "2025-01-01T00:00:00Z"
      }
      

/api/v1/templates/categories

  • GET
    • 설명: 템플릿 카테고리 목록을 조회합니다. 카테고리 ID와 이름을 반환합니다.
    • 응답: 200 OK - ListResponseTemplateCategoryDto
      {
        "data": [
          {
            "id": 1,
            "name": "Social"
          },
          {
            "id": 2,
            "name": "Politic"
          },
          {
            "id": 3,
            "name": "Economy"
          }
        ]
      }
      

/api/v1/tasks

  • GET
    • 설명: 모든 작업(task) 목록을 조회합니다. 작업 상태, 출력물 등의 정보를 포함합니다.
    • 응답: 200 OK - ListResponseTaskResponse
      {
        "data": [
          {
            "id": 50,
            "projectId": 1,
            "jobId": "job-12345",
            "type": "VIDEO",
            "status": "SUCCESS",
            "output": {},
            "retryCount": 0,
            "createdAt": "2025-03-18T10:00:00Z",
            "updatedAt": "2025-03-18T12:00:00Z"
          },
          {
            "id": 51,
            "projectId": 2,
            "jobId": "job-67890",
            "type": "VIDEO",
            "status": "FAILED",
            "output": {},
            "retryCount": 1,
            "createdAt": "2025-03-18T14:00:00Z",
            "updatedAt": "2025-03-19T10:00:00Z"
          }
        ]
      }
      

/api/v1/tasks/{taskId}

  • GET
    • 설명: 지정된 ID를 가진 작업의 세부 정보를 조회합니다.
    • 파라미터: taskId (path, 필수, int64) - 조회할 작업의 고유 ID
    • 응답: 200 OK - TaskResponse
      {
        "id": 50,
        "projectId": 1,
        "jobId": "job-12345",
        "type": "VIDEO",
        "status": "SUCCESS",
        "output": {},
        "retryCount": 0,
        "createdAt": "2025-03-18T10:00:00Z",
        "updatedAt": "2025-03-18T12:00:00Z"
      }
      

/api/v1/members/my

  • GET
    • 설명: 현재 로그인한 사용자의 프로필 정보를 조회합니다. 회원 ID와 이메일을 반환합니다.
    • 응답: 200 OK - MyProfileResponse
      {
        "memberId": 1001,
        "email": "user@example.com"
      }
      

위 내용은 각 엔드포인트에 대한 설명과 응답의 JSON 포맷 예시를 포함합니다. 요청 본문이 필요한 경우에는 그에 맞는 예시도 추가했습니다. 추가적인 수정이나 더 구체적인 예시가 필요하면 말씀해주세요!






0개의 댓글