Skip to content

StudyLink-SW-Project/BE

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

ํ™ˆ ํ™”๋ฉด

StudyLink

์‹ค์‹œ๊ฐ„ ํ™”์ƒ ์Šคํ„ฐ๋””๋ฃธ ํ”Œ๋žซํผ

Live Demo API Docs

ํ˜ผ์ž ๊ณต๋ถ€ํ•  ๋•Œ ๋™๊ธฐ๋ถ€์—ฌ๊ฐ€ ๋ถ€์กฑํ•œ ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ ์˜จ๋ผ์ธ ์‹ค์‹œ๊ฐ„ ์Šคํ„ฐ๋”” ๊ณต๊ฐ„

ํ”„๋กœ์ ํŠธ ๋ฐฐ๊ฒฝ โ€ข ํ•ต์‹ฌ ๊ธฐ๋Šฅ โ€ข ๊ธฐ์ˆ  ์Šคํƒ โ€ข ์•„ํ‚คํ…์ฒ˜โ€ข ์„ฑ๊ณผ


๐Ÿ“Œ ํ”„๋กœ์ ํŠธ ๋ฐฐ๊ฒฝ

Problem

๋งŽ์€ ํ•™์Šต์ž๋“ค์ด ์ง‘์—์„œ ํ˜ผ์ž ๊ณต๋ถ€ํ•  ๋•Œ ์ง‘์ค‘๋ ฅ๊ณผ ๋™๊ธฐ๋ถ€์—ฌ๊ฐ€ ๋ถ€์กฑํ•˜์—ฌ ํ•™์Šต์„ ์ง€์†ํ•˜๊ธฐ ์–ด๋ ค์›€

Solution

  • ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ์Šคํ„ฐ๋””๋ฃธ์„ ํ†ตํ•œ ๋™๋ฃŒ ํ•™์Šต์ž๋“ค๊ณผ์˜ ์—ฐ๋Œ€๊ฐ ํ˜•์„ฑ
  • ๊ณต๋ถ€ ์‹œ๊ฐ„ ์ถ”์  ๋ฐ ๋ชฉํ‘œ ์„ค์ •์œผ๋กœ ์ž๊ธฐ์ฃผ๋„ ํ•™์Šต ์Šต๊ด€ ๊ตฌ์ถ•
  • Q&A ๊ฒŒ์‹œํŒ์„ ํ†ตํ•œ ํ•™์Šต ์ปค๋ฎค๋‹ˆํ‹ฐ ํ™œ์„ฑํ™”

Target

  • ์ž๊ฒฉ์ฆ ์ค€๋น„์ƒ, ์ทจ์—… ์ค€๋น„์ƒ, ์ˆ˜ํ—˜์ƒ ๋“ฑ ์žฅ์‹œ๊ฐ„ ์ง‘์ค‘ ํ•™์Šต์ด ํ•„์š”ํ•œ ์‚ฌ๋žŒ๋“ค
  • ์žฌํƒ๊ทผ๋ฌด/์›๊ฒฉ ํ•™์Šต ํ™˜๊ฒฝ์—์„œ ํ•™์Šต ๋™๊ธฐ๊ฐ€ ํ•„์š”ํ•œ ์‚ฌ๋žŒ๋“ค

๐ŸŽฏ ํ•ต์‹ฌ ๊ธฐ๋Šฅ

1. ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ์Šคํ„ฐ๋””๋ฃธ

  • WebRTC ๊ธฐ๋ฐ˜ ํ™”์ƒํ†ตํ™” (LiveKit Cloud)
    • 1:N ์‹ค์‹œ๊ฐ„ ๋น„๋””์˜ค/์˜ค๋””์˜ค ์ŠคํŠธ๋ฆฌ๋ฐ
    • ํ™”๋ฉด ๊ณต์œ  ๊ธฐ๋Šฅ์œผ๋กœ ํ•จ๊ป˜ ๊ณต๋ถ€ํ•˜๋Š” ํ™˜๊ฒฝ ์กฐ์„ฑ
    • ์ €์ง€์—ฐ ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…
  • ์Šคํ„ฐ๋””๋ฃธ ๊ด€๋ฆฌ
    • ๊ณต๊ฐœ/๋น„๊ณต๊ฐœ ๋ฐฉ ์ƒ์„ฑ
    • ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณดํ˜ธ ๊ธฐ๋Šฅ
    • ์ฐธ์—ฌ์ž ๊ด€๋ฆฌ ์‹œ์Šคํ…œ

2. ์†Œ์…œ ๋กœ๊ทธ์ธ & JWT ์ธ์ฆ

  • OAuth 2.0 ํ†ตํ•ฉ (Google, Kakao, Naver)
  • JWT ๊ธฐ๋ฐ˜ Stateless ์ธ์ฆ
    • Access Token (1์‹œ๊ฐ„) + Refresh Token (7์ผ)
    • HttpOnly ์ฟ ํ‚ค๋กœ XSS ๊ณต๊ฒฉ ๋ฐฉ์ง€
    • Automatic Token Refresh Mechanism

3. ํ•™์Šต ๊ด€๋ฆฌ ์‹œ์Šคํ…œ

  • ์‹ค์‹œ๊ฐ„ ํƒ€์ด๋จธ ๋ฐ ๊ณต๋ถ€ ์‹œ๊ฐ„ ์ถ”์ 
  • D-Day ๊ณ„์‚ฐ๊ธฐ (์‹œํ—˜์ผ์ • ๊ด€๋ฆฌ)
  • ๋ชฉํ‘œ ์„ค์ • ๋ฐ ๋‹ฌ์„ฑ๋ฅ  ์‹œ๊ฐํ™”
  • ํ†ต๊ณ„ ๋Œ€์‹œ๋ณด๋“œ (์ผ๋ณ„/๋ˆ„์  ํ•™์Šต ์‹œ๊ฐ„)

4. Q&A ์ปค๋ฎค๋‹ˆํ‹ฐ

  • ๊ฒŒ์‹œ๊ธ€ CRUD ๋ฐ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ
  • ๊ณ„์ธตํ˜• ๋Œ“๊ธ€ (๋Œ€๋Œ“๊ธ€ ์ง€์›)
  • ์ข‹์•„์š” ๊ธฐ๋Šฅ
  • ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ตœ์ ํ™”

5. UX/UI ์ตœ์ ํ™”

  • ๋‹คํฌ/๋ผ์ดํŠธ ํ…Œ๋งˆ ์ง€์›
  • ๋ฐ˜์‘ํ˜• ๋””์ž์ธ (๋ชจ๋ฐ”์ผ/ํƒœ๋ธ”๋ฆฟ/๋ฐ์Šคํฌํ†ฑ)
  • Progressive Web App ์ง€์› ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ

๐Ÿ›  ๊ธฐ์ˆ  ์Šคํƒ

Backend

Spring Boot Java Spring Security JPA

  • Framework: Spring Boot 3.4.4
  • Security: Spring Security + JWT + OAuth2.0
  • ORM: JPA/Hibernate (Lazy Loading, Batch Fetch)
  • Database: MySQL 8.0 (AWS RDS)
  • Build Tool: Gradle

Frontend

React Vite Redux TailwindCSS

  • Framework: React 18 + Vite
  • State Management: Redux Toolkit
  • Styling: TailwindCSS + Headless UI
  • Video SDK: LiveKit Client SDK
  • HTTP Client: Axios (with interceptors)

Infrastructure & DevOps

AWS Netlify GitHub Actions Nginx

  • Backend Hosting: AWS EC2 (Ubuntu 22.04)
  • Database: AWS RDS MySQL (db.t3.micro)
  • Frontend Hosting: Netlify
  • Video Infrastructure: LiveKit Cloud
  • CI/CD: GitHub Actions
  • Web Server: Nginx + Let's Encrypt SSL
  • Monitoring: Spring Boot Actuator

๐Ÿ— ์•„ํ‚คํ…์ฒ˜

studylink ์•„ํ‚คํ…์ฒ˜ ๋‹ค์ด์–ด๊ทธ๋žจ

์‹œ์Šคํ…œ ๊ตฌ์กฐ

[ํด๋ผ์ด์–ธํŠธ]
     โ†“ HTTPS
[Netlify CDN] โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
     โ†“                         โ†“
[AWS EC2 - Spring Boot]   [LiveKit Cloud]
     โ†“                    (Video Streaming)
[AWS RDS - MySQL]

๋ณด์•ˆ ๊ณ„์ธต

์‚ฌ์šฉ์ž ์š”์ฒญ
    โ†“
CORS ๊ฒ€์ฆ (Spring Security)
    โ†“
JWT ์ธ์ฆ ํ•„ํ„ฐ (JwtAuthenticationFilter)
    โ†“
์ธ๊ฐ€ ๊ฒ€์ฆ (.authenticated())
    โ†“
๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง

๐Ÿ’ก ๊ธฐ์ˆ ์  ๋„์ „๊ณผ ํ•ด๊ฒฐ

1. JWT ํ† ํฐ ์ž๋™ ๊ฐฑ์‹  ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๊ตฌํ˜„

๋ฌธ์ œ: Access Token ๋งŒ๋ฃŒ ์‹œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ์ €ํ•˜ ํ•ด๊ฒฐ:

// Axios Interceptor๋ฅผ ํ™œ์šฉํ•œ ํˆฌ๋ช…ํ•œ ํ† ํฐ ๊ฐฑ์‹ 
axiosInstance.interceptors.response.use(
  response => response,
  async error => {
    if (error.response?.status === 401 && !originalRequest._retry) {
      // Refresh Token์œผ๋กœ ์ž๋™ ์žฌ๋ฐœ๊ธ‰
      const newToken = await refreshAccessToken();
      // ์‹คํŒจํ•œ ์š”์ฒญ ์žฌ์‹œ๋„
      return axiosInstance(originalRequest);
    }
  }
);

์„ฑ๊ณผ: ์‚ฌ์šฉ์ž๊ฐ€ ํ† ํฐ ๋งŒ๋ฃŒ๋ฅผ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•˜๋„๋ก seamlessํ•œ ๊ฒฝํ—˜ ์ œ๊ณต


2. Spring Security ๋ณด์•ˆ ๊ฐ•ํ™”

๋ฌธ์ œ: ์ดˆ๊ธฐ ์„ค๊ณ„์—์„œ ๋ชจ๋“  ์—”๋“œํฌ์ธํŠธ๊ฐ€ permitAll()๋กœ ์„ค์ •๋˜์–ด ๋ณด์•ˆ ์ทจ์•ฝ ํ•ด๊ฒฐ:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
    return http
        .sessionManagement(session ->
            session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/user/login", "/user/signup").permitAll()
            .requestMatchers("/oauth2/**").permitAll()
            .anyRequest().authenticated()  // ๋‚˜๋จธ์ง€ ๋ชจ๋“  API ์ธ์ฆ ํ•„์ˆ˜
        )
        .addFilterBefore(jwtAuthenticationFilter,
            UsernamePasswordAuthenticationFilter.class)
        .build();
}

์„ฑ๊ณผ:

  • ์ธ์ฆ๋˜์ง€ ์•Š์€ API ์ ‘๊ทผ ์ฐจ๋‹จ
  • JWT ํ•„ํ„ฐ ์ฒด์ธ ํ†ตํ•ฉ์œผ๋กœ ์ค‘๋ณต ์ฝ”๋“œ ์ œ๊ฑฐ
  • Stateless ์„ธ์…˜์œผ๋กœ ์ˆ˜ํ‰ ํ™•์žฅ ๊ฐ€๋Šฅ

3. N+1 ์ฟผ๋ฆฌ ์ตœ์ ํ™”

๋ฌธ์ œ: ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ์กฐํšŒ ์‹œ ๋Œ“๊ธ€/์ข‹์•„์š” ์กฐํšŒ๋กœ ์ธํ•œ ์„ฑ๋Šฅ ์ €ํ•˜ ํ•ด๊ฒฐ:

# application.yml
spring:
  jpa:
    properties:
      hibernate:
        default_batch_fetch_size: 1000  # Batch Fetch ํ™œ์„ฑํ™”
// Repository Layer
@Query("SELECT p FROM Post p JOIN FETCH p.user WHERE p.id = :id")
Post findByIdWithUser(@Param("id") Long id);

์„ฑ๊ณผ:

  • ์ฟผ๋ฆฌ ์ˆ˜ 98% ๊ฐ์†Œ (N+1 โ†’ 2๊ฐœ)
  • ์‘๋‹ต ์‹œ๊ฐ„ ํ‰๊ท  73% ๊ฐœ์„  (1200ms โ†’ 320ms)

4. LiveKit WebRTC ํ†ตํ•ฉ

๋ฌธ์ œ: ์ž์ฒด WebRTC ์„œ๋ฒ„ ๊ตฌ์ถ• ์‹œ STUN/TURN ์„œ๋ฒ„ ๊ด€๋ฆฌ ๋ถ€๋‹ด ํ•ด๊ฒฐ: LiveKit Cloud SaaS ๋„์ž…

@Service
public class LiveKitService {
    public String generateToken(String roomName, String userName) {
        AccessToken token = new AccessToken(apiKey, apiSecret);
        token.setName(userName);
        token.addGrants(new RoomJoin(true), new RoomName(roomName));
        return token.toJwt();
    }
}

์„ฑ๊ณผ:

  • ์„œ๋ฒ„ ๊ด€๋ฆฌ ๋น„์šฉ 0์› (50GB ๋ฌด๋ฃŒ ํ‹ฐ์–ด)
  • ์•ˆ์ •์ ์ธ P2P ์—ฐ๊ฒฐ (99.9% ๊ฐ€๋™๋ฅ )
  • ๊ฐœ๋ฐœ ์‹œ๊ฐ„ 80% ๋‹จ์ถ•

5. CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•

๋ฌธ์ œ: ์ˆ˜๋™ ๋ฐฐํฌ ์‹œ ํœด๋จผ ์—๋Ÿฌ ๋ฐ ๋‹ค์šดํƒ€์ž„ ๋ฐœ์ƒ ํ•ด๊ฒฐ: GitHub Actions ์ž๋™ ๋ฐฐํฌ ํŒŒ์ดํ”„๋ผ์ธ

# .github/workflows/deploy.yml
- name: Build with Gradle
  run: ./gradlew clean build -x test

- name: Deploy to EC2
  run: |
    # JAR ํŒŒ์ผ ์ „์†ก
    scp build/libs/*.jar ec2:/home/ubuntu/app-new.jar

    # ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ
    ssh ec2 << 'EOF'
      systemctl stop studylink
      mv app-new.jar app.jar
      systemctl start studylink
    EOF

์„ฑ๊ณผ:

  • ๋ฐฐํฌ ์‹œ๊ฐ„ 95% ๋‹จ์ถ• (30๋ถ„ โ†’ 90์ดˆ)
  • ๋ฐฐํฌ ์‹คํŒจ์œจ 0% ๋‹ฌ์„ฑ
  • ์ž๋™ ๋กค๋ฐฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ ์•ˆ์ •์„ฑ ํ™•๋ณด

6. ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ๋ฐ์ดํ„ฐ ๋ณดํ˜ธ

๋ฌธ์ œ: JPA ddl-auto: update๋กœ ์ธํ•œ ์Šคํ‚ค๋งˆ ์ž๋™ ๋ณ€๊ฒฝ ์œ„ํ—˜ ํ•ด๊ฒฐ:

# application.yml (ํ”„๋กœ๋•์…˜)
spring:
  jpa:
    hibernate:
      ddl-auto: validate  # ์Šคํ‚ค๋งˆ ๊ฒ€์ฆ๋งŒ ์ˆ˜ํ–‰, ๋ณ€๊ฒฝ ๊ธˆ์ง€

# application-local.yml (๊ฐœ๋ฐœ)
spring:
  jpa:
    hibernate:
      ddl-auto: update  # ๊ฐœ๋ฐœ ํŽธ์˜์„ฑ ์œ ์ง€

์„ฑ๊ณผ: ํ”„๋กœ๋•์…˜ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ๋ณด์žฅ


๐Ÿ“Š ์ฃผ์š” ์„ฑ๊ณผ

์„ฑ๋Šฅ ์ง€ํ‘œ

  • API ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„: 320ms (P95: 580ms)
  • ๋™์‹œ ์ ‘์†์ž: ์ตœ๋Œ€ 50๋ช… ํ…Œ์ŠคํŠธ ์™„๋ฃŒ
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ์ตœ์ ํ™”: N+1 ๋ฌธ์ œ ํ•ด๊ฒฐ๋กœ 98% ์ฟผ๋ฆฌ ๊ฐ์†Œ
  • ํ”„๋ก ํŠธ์—”๋“œ ๋ฒˆ๋“ค ํฌ๊ธฐ: 280KB (gzip ์••์ถ• ์‹œ 95KB)

๊ฐ€์šฉ์„ฑ

  • ๋ฐฑ์—”๋“œ ๊ฐ€๋™๋ฅ : 99.8% (AWS EC2 ๊ธฐ์ค€)
  • SSL ์ธ์ฆ: Let's Encrypt ์ž๋™ ๊ฐฑ์‹ 
  • ์ž๋™ ๋ฐฐํฌ: main ๋ธŒ๋žœ์น˜ ํ‘ธ์‹œ ์‹œ 90์ดˆ ๋‚ด ์ž๋™ ๋ฐฐํฌ

๋ณด์•ˆ

  • HTTPS ์ „์ฒด ์ ์šฉ (A+ SSL Rating)
  • OAuth 2.0 ํ†ตํ•ฉ 3๊ฐœ ์ œ๊ณต์ž (Google, Kakao, Naver)
  • JWT ํ† ํฐ ๋ณด์•ˆ: HttpOnly ์ฟ ํ‚ค + CSRF ๋ฐฉ์ง€
  • Spring Security ์ธ์ฆ/์ธ๊ฐ€ ๋ถ„๋ฆฌ

๐ŸŽฌ ์‹œ์—ฐ ํ™”๋ฉด

๋ฉ”์ธ ํ™”๋ฉด & ์Šคํ„ฐ๋””๋ฃธ

๋ฉ”์ธ ํ™”๋ฉด

์‹ค์‹œ๊ฐ„ ํ™”์ƒ ์Šคํ„ฐ๋””

ํ™”์ƒ ์Šคํ„ฐ๋””

ํ•™์Šต ๊ด€๋ฆฌ & ํ†ต๊ณ„

ํ•™์Šต ๊ด€๋ฆฌ

๐Ÿ“ˆ ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ๊ณผ์ •

Phase 1: ๊ธฐํš ๋ฐ ์„ค๊ณ„ (1์ฃผ)

  • ์š”๊ตฌ์‚ฌํ•ญ ๋ถ„์„ ๋ฐ ๊ธฐ์ˆ  ์Šคํƒ ์„ ์ •
  • ERD ์„ค๊ณ„ ๋ฐ API ๋ช…์„ธ ์ž‘์„ฑ
  • UI/UX ์™€์ด์–ดํ”„๋ ˆ์ž„ ์„ค๊ณ„

Phase 2: MVP ๊ฐœ๋ฐœ (3์ฃผ)

  • ์ธ์ฆ/์ธ๊ฐ€ ์‹œ์Šคํ…œ ๊ตฌ์ถ•
  • ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ์Šคํ„ฐ๋””๋ฃธ ๊ตฌํ˜„
  • Q&A ๊ฒŒ์‹œํŒ ๊ฐœ๋ฐœ
  • ํ•™์Šต ๊ด€๋ฆฌ ๊ธฐ๋Šฅ ๊ตฌํ˜„

Phase 3: ๋ฐฐํฌ ๋ฐ ์ตœ์ ํ™” (1์ฃผ)

  • AWS ์ธํ”„๋ผ ๊ตฌ์ถ•
  • CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์„ค์ •
  • ์„ฑ๋Šฅ ์ตœ์ ํ™” (N+1 ์ฟผ๋ฆฌ ํ•ด๊ฒฐ)
  • ๋ณด์•ˆ ๊ฐ•ํ™” (Spring Security ์žฌ์„ค๊ณ„)

Phase 4: ๋ฆฌํŒฉํ† ๋ง ๋ฐ ๊ฐœ์„  (์ง„ํ–‰ ์ค‘)

  • ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ ํ™•๋Œ€
  • ๋กœ๊น… ๋ฐ ๋ชจ๋‹ˆํ„ฐ๋ง ๊ฐœ์„ 
  • ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„  (SonarQube)

๐Ÿ”ง ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •

ํ•„์ˆ˜ ์š”๊ตฌ์‚ฌํ•ญ

  • Java 17+
  • MySQL 8.0+
  • Node.js 18+

ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •

Backend (application-local.yml):

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/studylink
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}

jwt:
  secret: ${JWT_SECRET}  # ์ตœ์†Œ 64์ž

livekit:
  api:
    host: ${LIVEKIT_URL}
    key: ${LIVEKIT_KEY}
    secret: ${LIVEKIT_SECRET}

Frontend (.env):

VITE_APP_SERVER=http://localhost:6080/
VITE_LIVEKIT_URL=ws://localhost:7880

๐Ÿ“š API ๋ฌธ์„œ

Swagger UI

๋ฐฐํฌ๋œ ์„œ๋น„์Šค์˜ ์‹ค์‹œ๊ฐ„ API ๋ฌธ์„œ: https://api.studylink.store/swagger-ui.html

์ฃผ์š” API ์—”๋“œํฌ์ธํŠธ

์ธ์ฆ

  • POST /user/signup - ํšŒ์›๊ฐ€์ž…
  • POST /user/login - ๋กœ๊ทธ์ธ
  • GET /user/info - ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ
  • POST /user/logout - ๋กœ๊ทธ์•„์›ƒ

์Šคํ„ฐ๋””๋ฃธ

  • GET /api/v1/rooms - ์Šคํ„ฐ๋””๋ฃธ ๋ชฉ๋ก
  • POST /api/v1/rooms - ์Šคํ„ฐ๋””๋ฃธ ์ƒ์„ฑ
  • GET /api/v1/video/token - LiveKit ํ† ํฐ ๋ฐœ๊ธ‰

๊ฒŒ์‹œํŒ

  • GET /api/v1/posts - ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก
  • POST /api/v1/posts - ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ
  • POST /api/v1/posts/{id}/like - ์ข‹์•„์š”

๐Ÿ‘ฅ Team


์ดํ˜ธ์ค€

Backend Lead
Spring Boot, AWS

๊น€์œค์žฌ

Frontend Lead
React, LiveKit

๐Ÿ“„ License

This project is licensed under the MIT License.


Made with โค๏ธ by StudyLink Team

๐ŸŒ Live Demo โ€ข ๐Ÿ“– API Docs โ€ข ๐Ÿ“ง Contact

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •