๐๐ป inbox_posts ํ
์ด๋ธ์ actor์ original_idํ๋๋ฅผ ์ถ๊ฐ ํฉ๋๋ค.
Add the actor and original_id fields to the inbox_posts table.
๐๐ป original_idํ๋๋ ๋์ค์ id(API์ id ๋ถ๋ถ)๋ฅผ ์งง๊ฒ ๋ณํํ๊ธฐ ์ํด์ ๋ง๋ ํ๋์
๋๋ค.
The original_id field was created to store a shortened version of the id (the ID portion of the API) for later use.
๐๐ป Actor๋ ๊ธ ๋ณด๋ธ ์ฌ๋์ ์ ์ฒด URL์
๋๋ค.
“Actor” is the full URL of the person who sent the post.
๐๐ป ๊ธฐ์กด์ ํ์๋ผ์ธ UI๋ถ๋ถ์ ์ฃผ์์ @userid๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Use @userid in the URL for the existing timeline UI section.
๐ ์ ์ฒด ํ๋ก์ ํธ ๊ตฌ์กฐ / Overall Project Structure
myapp19/
โโโ app/ (Next.js App Router)
โ โโโ .well-known/webfinger/route.ts -> webfinger
โ โโโ api/posts/route.ts -> Writing API
โ โโโ api/follow/route.ts -> Follow API(temporary)
โ โโโ 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
โ โโโ layout.tsx, page.tsx, globals.css
โ โโโ favicon.ico
โโโ lib/
โ โโโ ap.ts -> Follow Accept
โ โโโ db.ts -> DB connection
โโโ data/
โ โโโ keys/ -> private.pem, public.pem
โโโ data.sqlite -> Database
โโโ Caddyfile -> https
โโโ package.json
๐ ํ๋ก์ ํธ ์์(myapp19)
Project Start (myapp19)
npx create-next-app@latest
๐ SQLite์ค์น / Installing SQLite
cd ~/myapp19
npm install better-sqlite3
npm install -D @types/better-sqlite3
๐ DDNS,https์ค์ / DDNS,https settings
๐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ๋ ์ถ๊ฐ
Add database field
โ๏ธ inbox_postsํ
์ด๋ธ์ actor๊ฐ ์๋ค๋ฉด actorํ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
If the actor field does not exist in the inbox_posts table, add it.
ALTER TABLE inbox_posts ADD COLUMN actor TEXT;
ALTER TABLE inbox_posts ADD COLUMN original_id TEXT;
1)inbox_postsํ
์ด๋ธ์ actorํ๋๋ฅผ ์ถ๊ฐํ๊ณ postsํ
์ด๋ธ์๋ ์ถ๊ฐํ์ง ์์ต๋๋ค.
Add the actor field to the inbox_posts table, but do not add it to the posts table.
— ์ ์ฒด DB ์คํค๋ง / Entire DB schema
sqlite> .schema
CREATE TABLE posts (
id TEXT PRIMARY KEY,
content TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
, username TEXT DEFAULT 'user1');
CREATE TABLE followers (
id TEXT PRIMARY KEY,
actor TEXT NOT NULL,
inbox TEXT NOT NULL
, username TEXT);
CREATE TABLE users (
username TEXT PRIMARY KEY,
display_name TEXT DEFAULT '',
summary TEXT DEFAULT '',
private_key TEXT,
public_key TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_followers_username ON followers(username);
CREATE INDEX idx_followers_actor ON followers(actor);
CREATE TABLE following (
id TEXT PRIMARY KEY,
actor TEXT NOT NULL,
username TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_following_username ON following(username);
CREATE INDEX idx_following_actor ON following(actor);
CREATE TABLE inbox_posts (
id TEXT PRIMARY KEY,
actor TEXT,
content TEXT,
username TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
, original_id TEXT);
CREATE INDEX idx_posts_username_created ON posts(username, created_at DESC);
CREATE INDEX idx_inbox_username_created ON inbox_posts(username, created_at DESC);
CREATE INDEX idx_inbox_actor ON inbox_posts(actor);
sqlite>
โ๏ธ ํ์๋ผ์ธ ๋ผ์ฐํธ ์ฝ๋ ์์
Modify timeline route code
— myapp19/app/api/timeline/route.ts
// myapp19 โ
const timeline = db.prepare(`
SELECT id, content, username, username as actor, created_at, 'mine' as source
FROM posts WHERE username = ?
UNION ALL
SELECT id, content, username, actor, created_at, 'inbox' as source
FROM inbox_posts WHERE username = ?
ORDER BY created_at DESC
LIMIT 50
`).all(username, username);
1)ํ์๋ผ์ธ API๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ Actor๋ฅผ ์กฐํํฉ๋๋ค.
Query the database for the Actor using the Timeline API.
โ๏ธ ํ์๋ผ์ธ UI ๋ผ์ฐํธ ์ฝ๋ ์์
Modify timeline UI route code.
— myapp19/app/usersui/[username]/page.tsx
... ...
const timeline = db.prepare(`
SELECT id, content, username, username as actor, created_at, 'mine' as source
FROM posts WHERE username = ?
UNION ALL
SELECT id, content, username, actor, created_at, 'inbox' as source
FROM inbox_posts WHERE username = ?
ORDER BY created_at DESC LIMIT 50
`).all(username, username) as any[];
... ...
return (
<div style={{ padding: 20 }}>
<h1>{username} ํ์๋ผ์ธ / Timeline</h1>
<ul>
{timeline.map((p:any) => (
<li key={`${p.source}-${p.id}`}>
[{p.source}] <b>{p.actor}</b>: {p.content} - {p.created_at}
</li>
))}
</ul>
</div>
);
1)ํ์๋ผ์ธUI์์ Actor๋ฅผ ๋ณด์ฌ์ค๋๋ค.
Displays the Actor in the timeline UI.
โ๏ธ ์ธ๋ฐ์ค ๋ผ์ฐํธ ์ฝ๋ ์์
Modify inbox route code
— myapp19/app/users/[username]/inbox/route.ts
db.prepare(`
INSERT OR IGNORE INTO inbox_posts (id, actor, content, username, original_id, created_at) VALUES (?, ?, ?, ?, ?, ?)`).run(postId, actorId, content, username, note.id, note.published || new Date().toISOString());
1)DB์ Actor์ orginal_id๋ฅผ ์ ์ฅํ๋ ๋ถ๋ถ์
๋๋ค.
This is the part that saves the Actor and original_id to the database.
โ๏ธ ๋ธ๋ผ์ฐ์ ์์ ์๋์ ์ฃผ์๋ก ํ
์คํธ ํด๋ด
๋๋ค.
Try testing it in your browser using the address below.
— Timeline API
https://aloy-horizon.duckdns.org/api/timeline?username=user1

— Timeline UI
https://aloy-horizon.duckdns.org/usersui/user1

๐ ํ์๋ผ์ธ ์ฃผ์์ @userid ์ฌ์ฉํ๊ธฐ
Using @userid in the timeline URL
โ๏ธ myapp19/next.config.ts ์ฝ๋ ์์
Modify myapp19/next.config.ts code
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* allow domain*/
allowedDevOrigins: ['aloy-horizon.duckdns.org', '*.duckdns.org'],
/* host.domain.org/@userid */
async rewrites() {
return [
{
source: '/@:username',
destination: '/usersui/:username',
},
]
}
};
export default nextConfig;
1)rewrites()ํจ์๋ nextjs์์ฝํจ์๋ผ ์๋์คํ๋ฉ๋๋ค.
The rewrites() function is a reserved Next.js function, so it executes automatically.
โ๏ธ ์๋ฒ๋ฅผ ์ฌ์์ํฉ๋๋ค.
Restarting the server.
ctrl + c
npm run dev
โ๏ธ ๋ธ๋ผ์ฐ์ ์์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ํด ๋ด
๋๋ค.
Try accessing the following in your browser.
https://aloy-horizon.duckdns.org/@user1
โ๏ธ ๊ธฐ์กด์ ํ์๋ ์ฌ์ฉ๊ฐ๋ฅ ํฉ๋๋ค.
The existing format can also be used.
https://aloy-horizon.duckdns.org/usersui/user1
๐ก next.config.ts๋ฅผ ์์ ํ์ง ์๊ณ ๋๋ ํ ๋ฆฌ์ด๋ฆ์ ๋ฐ๊ฟ๋ @userid ํ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
You can use the @userid format even if you change the directory name, without modifying next.config.ts.
app/@[username]/page.tsx

์ํ๋ณต์ 8์ฅ 32์ / John 8:32
“๊ทธ๋ฆฌ๊ณ ๋ํฌ๋ ์ง๋ฆฌ๋ฅผ ์๊ฒ ๋ ๊ฒ์ด๋ฉฐ, ์ง๋ฆฌ๊ฐ ๋ํฌ๋ฅผ ์์ ๋กญ๊ฒ ํ ๊ฒ์ด๋ค.”
“Then you will know the truth ,and the truth will set you free”