[nextjs]SNS Server-28(myapp38) 

👉🏻 회원가입 및 로그인과 관련된 기능입니다.
These are features related to sign-up and login.

👉🏻 myapp38에서는 알림 기능을 구현합니다.
myapp38 implements a notification feature.

👉🏻 알림 기능은 pinafore.social을 기준으로 합니다.
The notification feature is based on pinafore.social.

👉🏻 전체 코드는 깃허브에서 확인 할 수 있습니다.
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


📁 FOLLOWERS,FOLLOWER 테이블 구조 변경

✔️ 테이블 / Table

— 테이블은 알림 확인시 날짜가 저장되지 않아 무조건 now로 표시되어 followers테이블 필드에 날짜입력 추가
The table always displays ‘now’ because the date is not saved when a notification is checked, so date input was added to the followers table field.

— 테이블 구조를 수정하면 필드가 기존 필드마지막에 추가되므로 관리와 일관성문제로 테이블 새로 생성
Since modifying the table structure adds fields to the end of existing fields, a new table is created due to management and consistency issues.

— 한줄씩 실행을 추천합니다. 한번에 실행하면 데이터 삭제 될 수 있습니다.
It is recommended to execute the commands one line at a time. Executing them all at once could result in data loss.

-- 1. 백업 / backup 
CREATE TABLE followers_backup AS SELECT * FROM followers;
CREATE TABLE following_backup AS SELECT * FROM following;

SELECT * FROM followers_backup LIMIT 2;
SELECT * FROM following_backup LIMIT 2;

-- 2. 기존 테이블 삭제 / Delete existing table
DROP TABLE followers;
DROP TABLE following;

-- 3. 동일한 스키마로 새로 생성 (필드순서 동일하게 맞춤)
-- Create new with the same schema (matching field order)
CREATE TABLE followers (
    id TEXT PRIMARY KEY,
    actor TEXT NOT NULL,
    inbox TEXT NOT NULL,
    username TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE following (
    id TEXT PRIMARY KEY,
    actor TEXT NOT NULL,
    inbox TEXT NOT NULL,
    username TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- 4. 인덱스는 기존과 동일함 / The index is the same as before.
CREATE INDEX idx_followers_username ON followers(username);
CREATE INDEX idx_followers_actor ON followers(actor);
CREATE INDEX idx_followers_created ON followers(created_at DESC);
CREATE UNIQUE INDEX idx_followers_actor_username ON followers(actor, username);

CREATE INDEX idx_following_username ON following(username);
CREATE INDEX idx_following_actor ON following(actor);
CREATE INDEX idx_following_inbox ON following(inbox);
CREATE INDEX idx_following_created ON following(created_at DESC);
CREATE UNIQUE INDEX idx_following_actor_username ON following(actor, username);

-- 5. 데이터 복구 (inbox 없으면! actor + /inbox로! 추정!)
-- Data recovery! (If there's no 'inbox', assume it's 'actor' + '/inbox'!)
INSERT INTO followers (id, actor, inbox, username, created_at)
SELECT 
  id,
  actor,
  COALESCE(inbox, actor || '/inbox'),
  username,
  COALESCE(created_at, CURRENT_TIMESTAMP)
FROM followers_backup;

INSERT INTO following (id, actor, inbox, username, created_at)
SELECT 
  id,
  actor,
  COALESCE(inbox, actor || '/inbox'),
  username,
  COALESCE(created_at, CURRENT_TIMESTAMP)
FROM following_backup;

-- 6. 확인 / check
SELECT * FROM followers;
SELECT * FROM following;
.schema followers
.schema following

-- 7. 백업 테이블 삭제(확인 후)
-- Delete backup table (after verification)
DROP TABLE followers_backup;
DROP TABLE following_backup;

✔️ 인덱스 추가 / Add Index

— 테이블 구조변경으로 인덱스도 동일하게 맞추기
Adjusting indexes to match table structure changes

CREATE INDEX IF NOT EXISTS idx_followers_inbox ON followers(inbox);

📁 코드수정 / Code Modification

✔️ 테이블수정으로 코드 수정한 부분
Parts of the code modified due to table changes

app/api/v1/accounts/[id]/following/route.ts
app/api/v1/accounts/[id]/followers/route.ts
app/users/[username]/inbox/route.ts
lib/db.ts

✔️ 알림기능 / Notification feature

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

// ✅ myapp38 - app/api/v1/notifications/route.ts 

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) { ... }
function makeAccount(parsed: ReturnType<typeof parseActor>, idx: number, createdAt?: string) { ... }
export async function GET(req: Request) { ...
// 1. Follow 알림 / Follow Notification
try { ... } catch(e){ console.error('follow', e); }

// 2. Like 알림 / Like Notification
try { ... } catch(e){ console.error('likes notif', e); }

// 3. Reblog 알림 / Reblog(boost) Notification
try { ... }catch(e){}
}
... ...

📁 테스트 / Test

✔️ 알림 라우트 터미널 테스트 / Notification Route Terminal Test

curl "https://aloy-horizon.duckdns.org/api/v1/notifications?limit=20"
# 터미널 / Terminal
% curl "https://aloy-horizon.duckdns.org/api/v1/notifications?limit=20"

# 응답 / Response

[{"id":"follow_0_https://mastodon.social/b7cc4c41-b22a-43b6-9df8-5bb46b2222fd","type":"follow","created_at":"2026-09-10T23:25:07.353Z","account":{"id":"notif_acct_mastodon_social_117193449750714993_0","username":"117193449750714993","acct":"117193449750714993@mastodon.social","display_name":"117193449750714993","avatar":"https://aloy-horizon.duckdns.org/icon.png", ... ... }]

✔️ 팔로워 알림 / Followers Notification

✔️ 부스트 알림 / Boost Notification

Boost

✔️ 좋아요 알림 / Likes Notification

likes

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

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

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

Leave a Reply