[nextjs]중간정리/Interim Summary(myapp11~29)

👉🏻 이번에는 프로젝트를 추가하지 않고 지금까지 진행했던 과정을 한번 중간정리하는 시간을 가져보려고 합니다.
This time, instead of adding a new project, I’d like to take a moment to review and summarize the progress made so far.

👉🏻 프로젝트의 규모가 커지고 기능이 많아질 수록 프로젝트와 코드에 대한 이해가 무엇보다 중요합니다.
As a project grows in scale and complexity, understanding the project and the code becomes paramount.

👉🏻 지금까지의 과정에서 보듯이 하나의 기능이 추가되거나 수정될 때 관련된 다른 기능에 영향을 미치기 때문에 전체 코드를 살펴보고 수정해야 합니다.
As seen in the process so far, adding or modifying a single function affects other related functions, so the entire codebase must be reviewed and updated.

👉🏻 그래서 오늘은 프로젝트와 코드에 대해서 다시 한번 살펴보고 점검해보는 시간을 가지려고 합니다.
So, today I’d like to take some time to revisit and review the existing project and code.

👉🏻 전체 코드는 깃허브에서 확인 할 수 있습니다.
You can find the full code on GitHub.

https://github.com/gideonslife01/flm-nextjs

📁 전체 프로젝트 구조 / Overall Project Structure

myapp project/  
├── app/  (Next.js App Router)
│   ├── .well-known/webfinger/route.ts  -> webfinger
│   ├── api/follow/route.ts    -> Follow API
│   ├── api/announce/route.ts  -> Boost(Announcement)
│   ├── api/like/route.ts.     -> Like API
│   ├── api/posts/route.ts     -> Writing API
│   ├── api/timeline/route.ts  -> Timeline API
│   ├── users/[username]/
│   │   ├── statuses/[id]/route.ts -> Indivisual Post
│   │   ├── route.ts               -> Acotr Information
│   │   ├── followers/route.ts     -> Followers List
│   │   ├── following/route.ts     -> Following List
│   │   ├── inbox/route.ts         -> Inbox
│   │   └── outbox/route.ts        -> outbox
│   ├── usersui/[username]/
│   │   ├── page.tsx               -> Timeline UI
│   │   └── _components/themes/
│   │       ├── themeex/ThemeexTheme.tsx   -> Example Theme
│   │       ├── pinafore/PinaforeTheme.tsx -> Theme 1
│   │       ├── mastodon/MastodonTheme.tsx -> Theme 2
│   │       └── minimal/MinimaltTheme.tsx  -> Theme 3
│   ├── layout.tsx, page.tsx, globals.css
│   └── favicon.ico
├── lib/
│   ├── theme.tsx              -> Theme Provider
│   ├── watchThemes.ts         -> Check real-time theme changes
│   ├── ap.ts                  -> Follow Accept
│   └── db.ts                  -> DB connection
├── data/
│   └── keys/                  -> private.pem, public.pem
├── data.sqlite                -> Database
├── Caddyfile                  -> https 
├── instrumentation.ts         -> Background Server
└── package.json


📁 디렉토리 구조 및 파일 상세 설명
Detailed Description of Directory Structure and Files

✔️ app/.well-known/webfinger/route.ts

– 다른서버에서 내 서버를 검색 / Search for my server on another server

- `acct:user1@aloy-horizon.duckdns.org` 검색하면 내 actor 주소 알려줌
Searching for `acct:user1@aloy-horizon.duckdns.org` returns my actor address.

- Mastodon에서 `@user1@aloy-horizon.duckdns.org` 검색할 때 사용함.
Use this when searching for `@user1@aloy-horizon.duckdns.org` on Mastodon.

- 없으면 다른 서버에서 내 서버를 못 찾음.
Without it, other servers won't be able to find your server.

- 테스트/Test: https://aloy-horizon.duckdns.org/.well-known/webfinger?resource=acct:user1@aloy-horizon.duckdns.org

✔️ app/api/follow/route.ts – 내가 다른 서버 팔로우 / I follow other servers.

- POST: 팔로우 시작 -> sendFollow()함수로 상대 inbox에 Follow 전송
Start following -> Send a follow request to the recipient's inbox using the sendFollow() function.

- DELETE: 언팔로우 -> sendUndoFollow()함수로 상대 inbox로 Undo Follow 전송
Unfollow -> Send an "Undo Follow" to the other party's inbox using the `sendUndoFollow()` function.

✔️ app/api/like/route.ts – 좋아요 / Likes

- POST: 좋아요/Like -> sendLike()
- DELETE: 좋아요 취소/Cancle Like -> sendUndoLike()

✔️app/api/posts/route.ts – 글 조회,쓰기,수정,삭제 / View, write, edit, and delete posts

- GET: 내 글만 조회/View only my posts (SELECT * FROM posts WHERE username = ?)

- POST: 글 쓰기 -> DB 저장 + followers에게 sendNote()로 배달! 
Write a post -> Save to DB + Deliver to followers via sendNote()

- PUT: 글 수정 -> DB만 수정 
Edit post -> Update DB only 

- DELETE: 글 삭제 -> DB 삭제 + followers에게 sendDelete()로 삭제 전파
Delete post -> Delete from DB + propagate deletion to followers via sendDelete()

✔️ app/api/timeline/route.ts – posts(outbox) + inxbox_posts(inbox)

 - GET: posts(내 글) + inbox_posts(남이 쓴 글) 최신순으로 최신순으로 검색
Search posts (my posts) + inbox_posts (posts by others) by recency.

- /usersui/user1 타임라인 UI가 이 API를 호출함
/usersui/user1 The timeline UI calls this API.

✔️ app/users/[username]/route.ts – Actor 프로필 / Actor Porfile

- GET: 내 프로필 정보 (publicKey, inbox, outbox, followers, following URL 알려줌)
My profile information (provides publicKey, inbox, outbox, followers, and following URLs)

- 상대 서버가 내 서버를 조회할 때 사용함.
Used when a remote server queries my server.

- 테스트/Test: https://aloy-horizon.duckdns.org/users/user1

- 없으면 연방 자체가 안 됨!
Without it, the federation itself cannot function!

✔️ app/users/[username]/statuses/[id]/route.ts – 개별 글 / Individual Posts

- GET: 글 1개 상세보기 / View post details

- 역할/Role: 
    1. posts 테이블에서 내 글 찾기
       Find my posts in the 'posts' table
    2. inbox_posts 테이블에서 남의 글 찾기
       Finding posts by others in the inbox_posts table
    3. Note JSON으로 반환 (to, cc, content 등)
       Note: Returned as JSON (to, cc, content, etc.)

- 테스트/Test: /users/user1/statuses/e6c99652-572f-491a-9e61-05e67b0d58fc

- 없으면 Mastodon에서 내 글 클릭하면 404에러 발생함.
Without it, clicking on my post in Mastodon results in a 404 error.

✔️ app/users/[username]/following/route.ts

– 내가 팔로우 하는 사람 목록 / List of people I follow

GET: 내가 팔로우하는 사람들 목록
List of people I follow

✔️ app/users/[username]/inbox/route.ts

- POST: 상대 서버에서 오는 모든 Activity 받는 곳
Endpoint for receiving all activities from the remote server.

    -- Follow 받음 -> following 테이블 추가 + sendAccept()로 수락
       Upon receiving a follow request -> Add to the 'following' table + accept via `sendAccept()`.

    -- Accept 받음 -> followers 테이블 추가!
       Accept received -> Added to the 'followers' table!

    -- Create(Note) 받음 -> inbox_posts 테이블에 저장(타임라인에 뜸)
       Receive Create(Note) -> Save to `inbox_posts` table (appears on the timeline)

    -- Like 받음 -> likes 테이블 저장
       "Like" received -> Save to the 'likes' table

    -- Announce(Boost) 받음 -> announces 테이블 저장
       'Announce(Boost)' received -> Save to the 'announces' table!

    -- Delete 받음 -> inbox_posts에서 삭제
       Delete 'Received' -> Delete from inbox_posts

    -- Undo 받음 -> 해당 데이터 삭제
       Undo received -> Corresponding data deleted

- ActivityPub 연방 수신의 핵심 / The core of ActivityPub federal receiving

✔️ /users/[username]/outbox/route.ts – 내가 쓴 글 목록 / List of posts I’ve written

- GET: 내 글 목록을 ActivityPub 표준(OrderedCollection)으로 반환
Return the list of my posts in the ActivityPub standard (OrderedCollection) format.

- 상대 서버가 내 글을 가져갈 때 사용 함.
Used when a remote server retrieves my post.

- /api/posts랑 비슷하지만 outbox는 표준 포맷, /api/posts는 내 UI용
It's similar to /api/posts, but outbox is the standard format, while /api/posts is for my UI.

✔️ /usersui/[username]/page.tsx  – 타임라인 UI / Timeline UI

- 브라우저에서 보는 타임라인 화면(테마를 파일을 불러옴)
Timeline view in the browser (loading the theme file)

- /api/timeline 호출해서 글 보여줌
Calls /api/timeline to display posts.

- themes/ - Pinafore, Mastodon, Minimal 테마 3개
themes/ - 3 themes: Pinafore, Mastodon, and Minimal

✔️ lib/ap.ts

- 중요함수 모음
Collection of Important Functions

- getPrivateKey(): username별 개인키 로드
getPrivateKey(): Load private key by username

- signAndSend(): 모든 Activity 서명 + 전송
signAndSend(): Sign and send all activities.

- sendFollow, sendAccept, sendNote, sendLike, sendAnnounce, sendDelete...

— lib/ap.ts 전체 함수 / full function

1)공용함수 / Common function

    함수/Functions기능/features
    getPrivateKey(username)username별 개인키 로드. 
    data/keys/user1/private.pem 우선,
    없으면 data/keys/private.pem fallback
    signAndSend(inbox, doc, username)Activity JSON 서명(SHA-256 + RSA) + POST 전송. 모든 sendXXX가 이거 사용함.
    signedFetch(url, username)GET 요청에 HTTP Signature 붙여서 가져오기.
    상대방 actor 정보 조회할 때 사용함.

    2)Activity 전용 함수 / Activity-specific function

    함수/Functions전송/Transmission사용/Use
    sendAccept(toInbox, followActivity, username)Accept다른 사람이 날 팔로우했을 때, 팔로우 수락
    When someone follows me, accept the follow
    sendNote(toInbox, note, username, postId, content)Create + Note내가 글 썼을 때, 팔로워 inbox로 글 배달
    When I write a post, it gets delivered to my followers’ inboxes.
    sendFollow(toInbox, targetActor, username)Follow내가 다른 사람 팔로우할 때
    When I follow someone else
    sendUndoFollow(targetActor, username)Undo + Follow내가 언팔로우할 때
    When I unfollow
    sendLike(toInbox, postId, username)Like내가 다른 사람 글 좋아요할 때
    When I ‘like’ someone else’s post
    sendUndoLike(toInbox, likeId, postId, username)Undo + Like좋아요 취소할 때
    When cancelling a ‘Like’
    sendAnnounce(toInbox, postId, username)Announce부스트/리포스트 할 때
    When boosting/reposting
    sendUndoAnnounce(toInbox, announceId, postId, username)Undo + Announce부스트 취소할 때
    When canceling the boost
    sendDelete(toInbox, postId, username)Delete + Tombstone내 글 삭제했을 때 팔로워들에게 삭제 전파(추가 예정)
    Notify followers when my post is deleted (feature coming soon)

    3) inbox 주소추출 / Extract email addresses from the inbox

    함수 / function기능/features
    getActorData(actorUrl, username)상대방 https://mastodon.social/users/xxx 정보 가져와서 inbox 주소 추출
    Retrieve information for the user at https://mastodon.social/users/xxx and extract the inbox address.

    ✔️lib/db.ts

    - 데이터베이스 연결 ,테이블 및 인덱스 초기화
    Database connection, table and index initialization

    📁 컨텍스트 프로바이더 적용 부분
    Implementation of the Context Provider

    myapp project/
    ├── lib/
    │   ├── theme.tsx              -> Theme Provider (Context)
    │   ├── watchThemes.ts         -> Check real-time theme changes
    │   ├── ap.ts                  -> Follow Accept
    │   └── db.ts                  -> DB connection
    └── app/
        ├── usersui/[username]/
        │   ├── page.tsx           -> Timeline UI (Use Provider)
        │   └── _components/themes/
        └── layout.tsx             -> Apply the provider to the project

    ✔️/lib/theme.tsx – 테마 컨텍스트 프로바이더 / Theme context provider

    - 테마 상태 전역 저장
    Globally store the theme state. (useContext)
    
        - currentTheme
          /app/usersui/[username]/_components/themes/themeNames.tsx
    
        - localStorage에 저장해서 새로고침해도 테마 유지
          Save to localStorage to maintain the theme even after refreshing.

    ✔️ /lib/watchThemes.ts – 실시간 테마 감지 / Real-time theme detection

    - 테마를 서버 재시작 없이 적용하기 위해서 사용함.
    Used to apply the theme without restarting the server.
    
    - /app/usersui/[username]/_components/themes/ 폴더 파일 변경 실시간 감지
    Real-time detection of file changes in the /app/usersui/[username]/_components/themes/ folder
    
    - chokidar로 파일 변경 감지
    Detect file changes with chokidar
    
    - instrumentation.ts에서 백그라운드로 실행
    Run in the background in instrumentation.ts
    
    - app/usersui/[username]/ 디렉토리내 index.ts 및 themeNames.ts파일 생성 및 업데이트
    Create and update the index.ts and themeNames.ts files in the app/usersui/[username]/ directory.
    
    - index.ts 및 themeNames.ts는 usersui/[username]/page.tsx에서 불러올 테마파일 경로가 기록됨.
    `index.ts` and `themeNames.ts` contain the file paths for the themes to be imported in `usersui/[username]/page.tsx`.
    

    ✔️ /app/layout.tsx  – 프로바이더 루트 / Provider root

    — <ThemeProvider>로 전체 앱 감싸서 모든 곳에 theme변수 적용
    Wrap the entire app with <ThemeProvider> to apply the theme variable everywhere.

    import { ThemeProvider } from "@/lib/theme"; // ✅ myapp26
    ... ...  
    return (
        <html
          lang="en"
          className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
        >
          <body className="min-h-full flex flex-col">
            <ThemeProvider>
              {children}
            </ThemeProvider>
            </body>
        </html>
      );

    ✔️ /app/usersui/[username]/page.tsx – 테마호출 페이지 / Theme Call Page

    - /api/timeline 호출해서 글도 가져오고, 테마도 적용
    Call /api/timeline to fetch posts and apply the theme.
    
    - 프로바이더에서 주입된 theme변수로 테마파일을 불러옵니다.
    Load the theme file using the `theme` variable injected by the provider.
    
    - 또는 pinafore디렉토리나 자동생성된 index.ts에서 테마파일을 불러옵니다.
    Alternatively, import the theme file from the `pinafore` directory or the automatically generated `index.ts`.
    
    
    - Code 
    
      const props = { timeline, username, onBoost: handleBoost, onLike: handleLike };
      
      // getThemeComponent : import { themeRegistry, getThemeComponent } from './_components/themes'; --> index.ts
      const ActiveTheme = getThemeComponent(theme as any) || themeRegistry.pinafore?.component || themeRegistry[themeNames[0]]?.component;
      if (!ActiveTheme) return <div>No themes found</div>;
    
      return <ActiveTheme {...props} />;

    ✔️ /app/usersui/[username]/_components/themes/ – 테마 / Theme

    - 테마 파일이 있는 디렉토리
    Directory containing theme files
    
    1) themeex/ThemeexTheme.tsx -> Example Theme (예제/example)
    2) pinafore/PinaforeTheme.tsx -> Theme 1 (Pinafore Style)
    3) mastodon/MastodonTheme.tsx -> Theme 2 (Mastodon Style)
    4) minimal/MinimaltTheme.tsx -> Theme 3 (Minimal Style)

    ✔️ /app/usersui/[username]/_components/themes/pinafore/PinaforeTheme.tsx

    — 테마파일 중 하나입니다.
    It is one of the theme files.

    - select메뉴에서 테마를 선택해서 테마 변경
    1) select 메뉴에서 메뉴를 선택
    2) theme.tsx 파일에서 주입된 setTheme(newTheme); 함수실행
    3) 로컬스토리지에 theme 이름을 저장하고 

    ✔️ /instrumentation.ts – 백그라운드 서버 / Background Server

    - Next.js 서버 시작 시 watchThemes.ts 실행
    Execute watchThemes.ts when the Next.js server starts.

    📁 전체 라우트 / Full Route

    ✔️ 브라우저에서 테스트 할 수 있는 라우트
    Routes that can be tested in a browser

    # 1. WebFinger
    https://aloy-horizon.duckdns.org/.well-known/webfinger?resource=acct:user1@aloy-horizon.duckdns.org
    
    # 2. Actor (프로필 / Profile)
    https://aloy-horizon.duckdns.org/users/user1
    
    # 3. Followers (남이 나 팔로우 / Someone follows me)
    https://aloy-horizon.duckdns.org/users/user1/followers
    
    # 4. Following (내가 남을 팔로우 / I follow others)
    https://aloy-horizon.duckdns.org/users/user1/following
    
    # 5. Outbox (내 글 목록 / My post list)
    https://aloy-horizon.duckdns.org/users/user1/outbox
    
    # 6. 타임라인 / Timeline
    
    # - 타임라인UI / Timeline UI
    https://aloy-horizon.duckdns.org/usersui/user1
    # or
    https://aloy-horizon.duckdns.org/@user1
    
    # - 타임라인API / Timeline API
    https://aloy-horizon.duckdns.org/api/timeline?username=user1
    
    # 7. 개별 글(글 상세) / indivisual posts(Post Details)[posts, inbox_posts]
    https://aloy-horizon.duckdns.org/users/user1/statuses/[ID]
    
    # ex)
    # posts table
    https://aloy-horizon.duckdns.org/users/user1/statuses/e6c99652-572f-491a-9e61-05e67b0d58fc
    
    # inbox_posts table
    https://aloy-horizon.duckdns.org/users/user1/statuses/01M0P8VYEQTFW28N97W6MG8PY5
    

    ✔️ 터미널에서만 테스트 가능한 라우트
    Routes that can only be tested in the terminal

    # 팔로우 (following 1로 증가)
    # Follow (following increased to 1)
    
    curl -X POST https://aloy-horizon.duckdns.org/api/follow \
      -H "Content-Type: application/json" \
      -d '{"username":"user1","target":"https://freelifemakers.com/users/user1"}'
    
    # 언팔로우 (following 0으로 감소)
    # Unfollow (following count reduced to 0)
    
    curl -X DELETE https://aloy-horizon.duckdns.org/api/follow \
      -H "Content-Type: application/json" \
      -d '{"username":"user1","target":"https://freelifemakers.com/users/user1"}'
    
    # 글 쓰기 (outbox 7로 증가 + 팔로워들에게 배달)
    # Writing a post (added to outbox 7 + delivered to followers)
    
    curl -X POST https://aloy-horizon.duckdns.org/api/posts \
      -H "Content-Type: application/json" \
      -d '{"username":"user1","content":"Hello Fediverse! #test"}'
    
    
    # 글 수정(로컬만가능, 구현예정, 라우트있음)
    # Modify post (local-only, pending implementation, route exists)
    curl -X PUT https://aloy-horizon.duckdns.org/api/posts \
      -H "Content-Type: application/json" \
      -d '{"username":"user1","id":"xxx","content":"수정된 내용/Revised content"}'
    
    # ❗️연방 수정 추가하려면 위 sendUpdate 함수 추가,일단은 기능 보류,지원안되는 서버 많음.
    # To add federal modifications, include the `sendUpdate` function mentioned above; however, this feature is currently on hold as many servers do not support it.
    # - lib/ap.ts에 sendUpdate 함수추가
    # Add the sendUpdate function to lib/ap.ts.
    # - app/api/posts/route.ts의 PUT함수에 sendUpdate함수 추가
    # Add the `sendUpdate` function to the `PUT` function in`app/api/posts/route.ts`.
    
    # 글 삭제  / Delete Posts
    curl -X DELETE https://aloy-horizon.duckdns.org/api/posts \
     -H "Content-Type: application/json" \
     -d '{"username":"user1","id":"e6c99652-572f-491a-9e61-05e67b0d58fc"}'
    
    # 좋아요 실행 / Likes
    curl -X POST https://aloy-horizon.duckdns.org/api/like \
     -H "Content-Type: application/json" \
     -d '{"username":"user1","target":"https://freelifemakers.com/users/user1/statuses/01M0XT1VBF23F8Y5EXAPK1VY56"}'
    
    # 좋아요 취소하기 / Undo Likes
    curl -X DELETE https://aloy-horizon.duckdns.org/api/like \
     -H "Content-Type: application/json" \
     -d '{"username":"user1","target":"https://mastodon.social/@Gargron/114559081070832514"}'
    
    # 부스트 실행 / Boost
    curl -X POST https://aloy-horizon.duckdns.org/api/announce \
     -H "Content-Type: application/json" \
     -d '{"username":"user1","target":"https://freelifemakers.com/@user1/statuses/01M10AHFHCKGF9BY5G4H50VSHG"}'
    
    # 부스트 취소 / Cancle Boost
    curl -X DELETE https://aloy-horizon.duckdns.org/api/announce \
     -H "Content-Type: application/json" \
     -d '{"username":"user1","target":"https://freelifemakers.com/@user1/statuses/01M10AHFHCKGF9BY5G4H50VSHG"}'

    📁 관련 문서 / Related Documents

    ✔️ 1. 공식 스펙 (W3C) 
    Official Specification (W3C)

    https://www.w3.org/TR/activitypub/
    https://www.w3.org/TR/activitystreams-vocabulary/

    ✔️2.Mastodon 문서! (실질적 표준)
    Mastodon Documentation! (De facto standard)

    https://docs.joinmastodon.org/spec/activitypub/

    ✔️3. Fediverse 개발자 위키 – 호환성 정보
    Fediverse Developer Wiki – Compatibility Information

    https://codeberg.org/fediverse/fep

    ✔️ Mastodon 소스!(루비코드)
    Mastodon source code! (Ruby code)

    https://github.com/mastodon/mastodon/blob/main/app/lib/activitypub/activity/update.rb

    요한복음 8장 32절 / John 8:32

    “그리고 너희는 진리를 알게 될 것이며, 진리가 너희를 자유롭게 할 것이다.”

    “Then you will know the truth ,and the truth will set you free”

    Leave a Reply