ππ» 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”