[nextjs]SNS Server-27(myapp37)Β 

πŸ‘‰πŸ» νšŒμ›κ°€μž… 및 둜그인과 κ΄€λ ¨λœ κΈ°λŠ₯μž…λ‹ˆλ‹€.
These are features related to sign-up and login.

πŸ‘‰πŸ» myapp27은 νŒ”λ‘œμš°,νŒ”λ‘œμ›Œ 리슀트 κΈ°λŠ₯을 κ΅¬ν˜„ν•©λ‹ˆλ‹€.
myapp27 implements features for the following and followers lists.

πŸ‘‰πŸ» νŒ”λ‘œμš°μ™€ νŒ”λ‘œμ›Œ λ¦¬μŠ€νŠΈλŠ” ν”„λ‘œν•„μ„ ν΄λ¦­ν•˜λ©΄ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.
You can view the lists of people you follow and your followers by clicking on the profile.

πŸ‘‰πŸ» 전체 μ½”λ“œλŠ” κΉƒν—ˆλΈŒμ—μ„œ 확인 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
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(temporary)
β”‚   β”œβ”€β”€ api/announce/route.ts  -> Boost(Announcement)
β”‚   β”œβ”€β”€ api/like/route.ts.     -> Like API
β”‚   β”œβ”€β”€ api/posts/route.ts     -> Writing API
β”‚   β”œβ”€β”€ api/timeline/route.ts  -> Timeline API
β”‚   β”œβ”€β”€ api/v1/instance/route.ts -> auth
β”‚   β”œβ”€β”€ api/v1/apps/route.ts.    -> auth
β”‚   β”œβ”€β”€ api/v1/accounts/verify_credentials/route.ts -> auth
β”‚   β”œβ”€β”€ api/v1/statuses/route.ts -> Write Post
β”‚   β”œβ”€β”€ api/v1/timelines/home/route.ts -> timeline
β”‚   β”œβ”€β”€ oauth/authorize/route.ts -> auth
β”‚   β”œβ”€β”€ oauth/token/route.ts -> auth
β”‚   β”œβ”€β”€ api/v1/search/home/route.ts -> search
β”‚   β”œβ”€β”€ api/v2/search/home/route.ts -> search
β”‚   β”œβ”€β”€ api/v1/accounts/[id]/followers/route.ts -> followers
β”‚   β”œβ”€β”€ api/v1/accounts/[id]/following/route.ts -> following
β”‚   β”œβ”€β”€ 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
β”‚   β”œβ”€β”€ auth.ts                -> Authentication, User Management
β”‚   β”œβ”€β”€ ap.ts                  -> Follow,Undo,Create,Likes,Announce
β”‚   └── db.ts                  -> DB connection
β”œβ”€β”€ data/
β”‚   β”œβ”€β”€ keys/userIDs/          -> private.pem, public.pem(New)
β”‚   └── keys/                  -> private.pem, public.pem(legacy)
β”œβ”€β”€ data.sqlite                -> Database(1/3)
β”œβ”€β”€ data.sqlite-wal            -> Database(2/3)
β”œβ”€β”€ data.sqlite-shm            -> Database(3/3)
β”œβ”€β”€ Caddyfile                  -> https 
β”œβ”€β”€ instrumentation.ts         -> Background Server
└── package.json

πŸ“ ν”„λ‘œμ νŠΈ μ‹œμž‘ / Project Start


 πŸ“ 라우트 μΆ”κ°€ 및 μ½”λ“œ μˆ˜μ • / Add routes and modify code

βœ”οΈ νŒ”λ‘œμ›Œ / follower

— μ‹ κ·œ μΆ”κ°€λœ 라우트 / Newly added routes

— app/api/v1/accounts/[id]/followers/route.ts

/ βœ… myapp37 - followers API
// /api/v1/accounts/:id/followers

import { NextResponse } from 'next/server';
import db from '@/lib/db';

const DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';

function parseActor(actor: string, idx: number) { ... }
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) { ... }

export async function OPTIONS() { ... }

βœ”οΈ νŒ”λ‘œμž‰ / following

— μ‹ κ·œ μΆ”κ°€λœ 라우트 / Newly added routes

— app/api/v1/accounts/[id]/following/route.ts

// βœ… myapp37 - following API
// /api/v1/accounts/:id/following

import { NextResponse } from 'next/server';
import db from '@/lib/db';

const DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';

function parseActor(actor: string, idx: number) { ... }
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) { ... }
export async function OPTIONS() { ... }

βœ”οΈ pinaforeμ—μ„œ νŒ”λ‘œμ›Œ,νŒ”λ‘œμž‰ λͺ©λ‘μ€ urlencodeλΌμ„œ μ½”λ“œ μˆ˜μ •
Modified the code because the follower and following lists in Pinafore are URL-encoded.

— app/api/v1/apps/route.ts

import { NextResponse } from 'next/server';
import db from '@/lib/db';
import { randomUUID } from 'crypto';

const DOMAIN = process.env.DOMAIN || 'aloy-horizon.duckdns.org';

export async function POST(req: Request) { 
try {
... ...
    const contentType = req.headers.get('content-type') || '';
    
    if (contentType.includes('application/json')) {
      const body = await req.json();
      clientName = body.client_name || 'Unknown';
      redirectUris = body.redirect_uris || body.redirect_uri || '';
      scopes = body.scopes || 'read write follow';
      website = body.website || '';
    }else{
      // form-urlencoded! Pinafore!κ°€! 이걸둜! 보냄!
      //
      const text = await req.text();
      const params = new URLSearchParams(text);
      clientName = params.get('client_name') || 'Unknown';
      redirectUris = params.get('redirect_uris') || params.get('redirect_uri') || '';
      scopes = params.get('scopes') || 'read write follow';
      website = params.get('website') || '';
    }
... ...

    // βœ… Pinaforeκ°€ κΈ°λŒ€ν•˜λŠ” 응닡! 
    // Pinafore expects this response!
    return NextResponse.json({
      id: clientId, // PinaforeλŠ” id도 확인 / Pinafore also checks id
      name: clientName,
      website: website,
      redirect_uri: redirectUris,
      client_id: clientId,
      client_secret: clientSecret,
      vapid_key: '' // push용, 없어도 됨 / for push, not required
    });

  } catch (e) {
    console.error('apps μ—λŸ¬ / apps error:', e);
    //return NextResponse.json({ error: String(e) }, { status: 500 });

    // βœ… myapp37 - μ—λŸ¬λ‚˜λ„ 일단 μ„±κ³΅μœΌλ‘œ 리턴 / Return a success status for now, even if an error occurs.
    return NextResponse.json({
      id: '1',
      name: 'Pinafore',
      website: null,
      redirect_uri: 'https://pinafore.social/settings/instances/add',
      client_id: 'pinafore_client_id',
      client_secret: 'pinafore_client_secret',
      vapid_key: null,
    }, {
      headers: { 'Access-Control-Allow-Origin': '*' }
    });
  }

}

βœ”οΈ Notifications

— μ‹ κ·œ μΆ”κ°€λœ 라우트 / Newly added routes

— app/api/v1/notifications/route.ts

// βœ… myapp37 - myapp/api/notifications/route.ts

import { NextResponse } from 'next/server';

export async function GET() {
  // 아직! κ΅¬ν˜„ μ•ˆ 함! 빈 λ°°μ—΄! / Not yet! Not implemented! Empty array!
  return NextResponse.json([], {
    headers: { 'Access-Control-Allow-Origin': '*' }
  });
}

export async function OPTIONS() {
  return new NextResponse(null, {
    status: 204,
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization'
    }
  });
}

πŸ“ ν…ŒμŠ€νŠΈ / Test

βœ”οΈ 둜그인 ν›„ ν”„λ‘œν•„μ—μ„œ FOLLOWS와 FOLLOWλ₯Ό ν΄λ¦­ν•˜λ©΄ 리슀트λ₯Ό λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.
After logging in, you can view the lists by clicking on “FOLLOWS” and “FOLLOW” in your profile.

βœ”οΈ νŒ”λ‘œμš° / Follows

Follows

βœ”οΈ νŒ”λ‘œμ›Œ / Followers

Followers

μš”ν•œλ³΅μŒ 8μž₯ 32절 / John 8:32

“그리고 λ„ˆν¬λŠ” 진리λ₯Ό μ•Œκ²Œ 될 것이며, 진리가 λ„ˆν¬λ₯Ό 자유둭게 ν•  것이닀.”

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

Leave a Reply