Next.js 15(App Router) + React 19 ๊ธฐ๋ฐ์ AI ์บ๋ฆญํฐ ๋ํ/์ฐฝ์ ํ๋ซํผ์ ๋๋ค. Firebase(์ธ์ฆ/Firestore/Storage/Analytics)์ Supabase(pgvector)๋ฅผ ๊ฒฐํฉํด ์ฅ๊ธฐ ๊ธฐ์ต RAG, ์์ฝ(SUPA/HYPA ๋กค์ ), ๊ทธ๋ฃน ์ฑํ , ์บ๋ฆญํฐ/๋ก์ด ๊ด๋ฆฌ, ํฌ์ธํธยท๋ฉค๋ฒ์ญยท๊ฒฐ์ (Stripe/Patreon) ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. PWA์ Vercel Cron๋ ์ง์ํฉ๋๋ค.
์ฃผ์ ํด๋์ ์ฝ๋(์ผ๋ถ):
src/appโ ๋ผ์ฐํธ(App Router),api/*์๋ฒ ๋ผ์ฐํธ,chat,ranking,lorebook,settings,admin๋ฑ ํ๋ฉดsrc/utils/vector/*โ ์๋ฒ ๋ฉ/ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์/RAG/์์ฝ ์ ์ฅ์(Supabase)src/utils/memory/*โ ์์ฝ ์ ์ฑ /ํ๋กฌํํธ/์์ฝ๊ธฐ(SUPA/HYPA)src/firebase/*โ Firebase ํด๋ผ์ด์ธํธ/์ด๋๋ฏผ ์ด๊ธฐํ, ์ปฌ๋ ์ ์ ํธsupabase/schema/*.sqlโ pgvector/tsvector ๊ธฐ๋ฐ ์คํค๋ง์ RPC(SQL Editor์์ ์คํ)docs/*.mdโ ๊ทธ๋ฃน ์ฑํ /์ถ์ ๋ฑ ๊ธฐ๋ฅ ์ค๊ณ ๋ฌธ์
- AI ๋ํ
- ๋จ์ผ/๊ทธ๋ฃน ์ฑํ , ์บ๋ฆญํฐ๋ณ ํ๋กํ/์ด๋ฏธ์ง ๋งค์นญ, ์ต๊ทผ ๋ํ ์์ฝ ์ฝ์
- LLM: Google AI Studio(Gemini/Vertex), OpenRouter(Anthropic/OpenAI)
- ์ฅ๊ธฐ ๊ธฐ์ต(RAG): Supabase pgvector + tsvector ํ์ด๋ธ๋ฆฌ๋ ๊ฒ์, ์์ฝ ์ฐ์ (summary-first) ๊ฒ์
- ์ปจํ
์ธ /์์ฐ
- ์บ๋ฆญํฐยท๋ก์ด๋ถ CRUD, ์ด๋ฏธ์ง ์์ฑ(
/api/generate-image) ๋ฐ ์์ฝ(/api/summarize)
- ์บ๋ฆญํฐยท๋ก์ด๋ถ CRUD, ์ด๋ฏธ์ง ์์ฑ(
- ๊ฒฝ์ /๋ญํน
- ํฌ์ธํธ ์์ก/๊ฑฐ๋, Stripe ๊ฒฐ์ /์นํ , Patreon ์ฐ๋
- ์ผ/์ฃผ/์ ๋ญํน ์ง๊ณ(cron) + ์กฐํ(
/api/rankings)
- ๊ด๋ฆฌ/๋ณด์
- ๊ด๋ฆฌ์ ๊ถํ ๊ด๋ฆฌ(
src/app/admin/users/page.tsx), ์ญ์ /์ ๋ฆฌ์ฉ cron - Firestore ๊ท์น/์ธ๋ฑ์ค(
firestore.rules,firestore.indexes.json)
- ๊ด๋ฆฌ์ ๊ถํ ๊ด๋ฆฌ(
- ๋ฐฐํฌ/์ด์
- Vercel Cron(
vercel.json), PWA(next-pwa,public/manifest.json,public/sw.js)
- Vercel Cron(
- Web: Next.js 15, React 19, TypeScript, Mantine + MUI
- Backend(App Router API): Firebase Admin, Supabase(Postgres + pgvector + pg_trgm + tsvector)
- AI: Google Generative AI/Vertex, OpenRouter, OpenAI(์๋ฒ ๋ฉ ํฌํจ)
- Payments: Stripe(Checkout/Webhook), Patreon OAuth
- Infra: Vercel, PWA, Vercel Cron
์ฌ์ ์๊ตฌ์ฌํญ
- Node.js 20+ ๊ถ์ฅ, pnpm 9+ (repo์
pnpm-lock.yaml์กด์ฌ) - Firebase ํ๋ก์ ํธ, Supabase ํ๋ก์ ํธ, Stripe ๊ณ์ , (์ ํ) Patreon ํด๋ผ์ด์ธํธ
- ์์กด์ฑ ์ค์น
pnpm install- ํ๊ฒฝ ๋ณ์ ์ค๋น
.env.example๋ฅผ ์ฐธ๊ณ ํด.env๋๋.env.local์ ์ฑ์๋๋ค.- ๊ผญ ํ์ํ ๊ฐ(์์ฝ):
- Firebase Web:
NEXT_PUBLIC_FIREBASE_* - Firebase Admin:
FIREBASE_ADMIN_SDK_CONFIG(JSON), ๋๋ ์๋น์ค ๊ณ์ ํ์ผ ์ง์ (GOOGLE_APPLICATION_CREDENTIALS) - Supabase(Server-only):
SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY, (์ต์ )SUPABASE_ANON_KEY - AI ํค:
GOOGLE_AI_STUDIO_API_KEY๋๋GOOGLE_AI_STUDIO_API_KEYS, (์ต์ )OPENROUTER_API_KEY,OPENAI_API_KEY - ๊ฒฐ์ :
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET - Cron ๋ณด์:
CRON_SECRET(๋ญํน ์ง๊ณ),CRON_SECRET_TOKEN(์ ๋ฆฌ ์์ ) - RAG/๋ฉ๋ชจ๋ฆฌ: ์๋ RAG/Memory ์น์ ์ฐธ์กฐ
- Firebase Web:
๋ณด์ ์ฃผ์: SUPABASE_SERVICE_ROLE_KEY๋ ์ ๋ ํด๋ผ์ด์ธํธ์ ๋
ธ์ถ๋๋ฉด ์ ๋ฉ๋๋ค. ์๋ฒ ์ ์ฉ์
๋๋ค.
- Supabase ์คํค๋ง ์ ์ฉ
- Supabase Dashboard โ SQL Editor์์ ์๋ ์์๋๋ก ์คํ:
supabase/schema/001_chat_message_embeddings.sqlsupabase/schema/002_match_chat_messages.sqlsupabase/schema/004_enable_trgm_and_lexical.sqlsupabase/schema/005_match_chat_messages_hybrid.sqlsupabase/schema/006_parent_child_windowing.sqlsupabase/schema/007_memory_summaries.sqlsupabase/schema/008_memory_summaries_param_fix.sqlsupabase/schema/009_memory_roomid_to_text.sqlsupabase/schema/010_memory_summaries_rpc_roomid_text.sql
- ๊ฐ๋ฐ ์๋ฒ ์คํ
pnpm dev๋ธ๋ผ์ฐ์ ์์ http://localhost:3000 ์ ์
Firebase
NEXT_PUBLIC_FIREBASE_API_KEY,NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,NEXT_PUBLIC_FIREBASE_PROJECT_ID,NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,NEXT_PUBLIC_FIREBASE_APP_ID,NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, (์ต์ )NEXT_PUBLIC_FIREBASE_VAPID_KEY- Admin:
FIREBASE_ADMIN_SDK_CONFIG(๋ฌธ์์ด JSON) ๋๋GOOGLE_APPLICATION_CREDENTIALS(ํ์ผ ๊ฒฝ๋ก)
Supabase (์๋ฒ ์ ์ฉ)
SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY, (์ต์ )SUPABASE_ANON_KEY
AI/์๋ฒ ๋ฉ
- Google AI Studio:
GOOGLE_AI_STUDIO_API_KEY๋๋GOOGLE_AI_STUDIO_API_KEYS - OpenRouter(Anthropic/OpenAI ๊ฒฝ์ ):
OPENROUTER_API_KEY - OpenAI ์๋ฒ ๋ฉ:
OPENAI_API_KEY, (์ต์ )EMBED_PROVIDER=openai|openrouter|local,EMBED_MODEL=text-embedding-3-small,LOCAL_EMBEDDING_URL
๊ฒฐ์ /๋ฉค๋ฒ์ญ
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRETPATREON_CLIENT_ID,PATREON_CLIENT_SECRET,PATREON_REDIRECT_URI
Cron/์ด์
CRON_SECRET,CRON_SECRET_TOKEN- PWA๋
next-pwa์ค์ (๊ฐ๋ฐ ๋ชจ๋ ๋นํ์ฑ)
์์ฝ/๋ฉ๋ชจ๋ฆฌ/RAG
- ๋ฉ๋ชจ๋ฆฌ ์ ์ฑ
(
src/utils/memory/policy.ts):SUPA_HYPA_MEMORY_ENABLED=true|false(๊ธฐ๋ณธ on)MEMORY_RETRIEVAL_MODE=summary_only|cascaded|messages_first(๊ธฐ๋ณธ cascaded)SUPA_THRESHOLD_TOKENS,SUPA_WINDOW_MESSAGES,HYPA_ROLLUP_CHUNKS,SUPA_ROLLUP_MAX_GAP_MINUTES,HYPA_ROLLUP_PERIOD_HOURSMEMORY_SUMMARY_K1,MEMORY_SUMMARY_K2,MEMORY_MIN_SCORE,MEMORY_ALPHA,MEMORY_WEIGHT_BETA,DECAY_HALFLIFE_HOURS,MAX_CONTEXT_TOKENS_FOR_MEMORY
- RAG ๊ฒ์(
src/utils/vector/rag.ts):RAG_MODE=v1|hybrid(๊ธฐ๋ณธ v1),RAG_K,RAG_FETCH_K,RAG_MIN_SCORE,RAG_ALPHA,RAG_WINDOW_SIZE,RAG_USE_TSV,RAG_USE_MQ,RAG_USE_HYDE,RAG_USE_RERANK,RAG_DECAY_HALFLIFE_HOURS,DEBUG_RAG
- ์์ฝ API(
src/app/api/summarize/route.ts):SUMMARY_SERVER_MAX_INPUT_CHARS,SUMMARY_SERVER_CHUNK_CHARS,SUMMARY_SERVER_MAX_MESSAGES, (ํด๋ผ์ด์ธํธ ์ ํ)SUMMARY_CLIENT_*
์ฐธ๊ณ : .env.example์ ์ ์ฒด ์์๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
- ์ธ๋ฑ์ฑ:
/api/vector/index-messageโchat_message_embeddings์ ์ํธ - ๊ฒ์: ํ์ด๋ธ๋ฆฌ๋(RAG_MODE=hybrid) = pgvector(semantic) + trigram/tsvector(lexical) + ์๊ฐ๊ฐ์ โ
match_chat_messages_hybrid - ์์ฝ ์ฐ์ (summary-first):
chat_memory_summaries(SUPA=level 0, HYPA=level 1)์์ ๋จผ์ ๋งค์นญ โ ํ์์ ๋ฉ์์ง ์ค๋ํซ ๋ณด๊ฐ - ์๋ ๋กค์
:
- SUPA: ์ต๊ทผ ์ฐฝ ํฌ๊ธฐ/ํ ํฐ ์๊ณ ๋๋ฌ ์
runSupaSummarization์ผ๋ก ์์ฝ ์ ์ฅ - HYPA: ์ผ์ ๊ฐ์/๊ธฐ๊ฐ ๊ฒฝ๊ณผ ์
runHypaRollup์ผ๋ก ์์ ์์ฝ ๋ฐ ๋งํฌ ์ ์ฅ(chat_memory_links)
- SUPA: ์ต๊ทผ ์ฐฝ ํฌ๊ธฐ/ํ ํฐ ์๊ณ ๋๋ฌ ์
- ํตํฉ ์์คํ ๋ธ๋ก: ๊ฒ์/์์ฝ ๊ฒฐ๊ณผ๋ฅผ ์์คํ ํ๋กฌํํธ๋ก ์ฃผ์ ํ์ฌ ๋ต๋ณ ํ์ง ํฅ์
๊ด๋ จ ํ์ผ
src/app/api/chat/bot-response/route.tsโ RAG ์ฃผ์ , ์์ฝ ๋กค์ , ๋ฉํฐ ๋ชจ๋ธ ์ง์src/utils/vector/*โ ์๋ฒ ๋ฉ/๊ฒ์/์์ถ/์์คํ ๋ธ๋กsrc/utils/memory/*โ ์ ์ฑ /ํ๋กฌํํธ/์ ์ฅ์supabase/schema/*.sqlโ ํ ์ด๋ธ/์ธ๋ฑ์ค/RPC ์ ์
- ์ฑํ
POST /api/chat/bot-responseโ ์บ๋ฆญํฐ ์๋ต ์์ฑ + RAG ์ฃผ์ /์์ฝ ๋กค์POST /api/chat/convertโ ๊ทธ๋ฃนโ๊ฐ์ธ ๋ฐฉ ์ ํ, ํฌํฌ ๊ด๋ฆฌPOST /api/vector/index-messageโ ๋ฉ์์ง ์๋ฒ ๋ฉ ์ธ๋ฑ์ฑ
- ์์ฑ/์์ฝ
POST /api/generate-loreโ ๋ก์ด/์ฒซ ๋ฉ์์ง ์์ฑ(WW+ ํ์)POST /api/generate-imageโ ์ด๋ฏธ์ง ์์ฑ(์ ํ)POST /api/summarizeโ ๋ํ ์์ฝ
- ๊ฒฝ์ /๋ญํน
POST /api/stripe/checkout,POST /api/stripe/webhookโ ๊ฒฐ์ /์นํGET /api/rankingsโ ์ผ/์ฃผ/์ ๋ญํน ์กฐํGET /api/cron/aggregate-rankings/*โ Vercel Cron ๋์(ํค๋X-Cron-Auth: $CRON_SECRET)
- Vercel ๋ฐฐํฌ ๊ถ์ฅ.
vercel.json์ Cron์ด ์ ์๋์ด ์์ต๋๋ค. - Stripe Webhook์
STRIPE_WEBHOOK_SECRETํ๊ฒฝ๋ณ์๋ก ์๋ช ๊ฒ์ฆ์ ์ํํฉ๋๋ค. - Vertex/Google AI ์ฌ์ฉ ์ ์๋น์ค ๊ณ์ ์๊ฒฉ์ฆ๋ช
์ด ํ์ํฉ๋๋ค(
GOOGLE_APPLICATION_CREDENTIALS๋๋ JSON ๋ฌธ์์ด).
๋ณด์ ์ฒดํฌ๋ฆฌ์คํธ
- ์๋น์ค ๋กค ํค/์๋น์ค ๊ณ์ JSON์ ์ ๋ ํด๋ผ์ด์ธํธ์ ๋ ธ์ถ ๊ธ์ง
- Firestore Rules/Indexes ๋๊ธฐํ(
firestore.rules,firestore.indexes.json) - Stripe Webhook ์๋ช /๋น์ฉ ์ถ์ (ํฌ์ธํธ ์ฐจ๊ฐ ๋ก์ง)
package.json ์ผ๋ถ ์คํฌ๋ฆฝํธ:
dev,build,start,lint- ๋ง์ด๊ทธ๋ ์ด์
/์ ๋ฆฌ:
scripts/migrations/*,src/scripts/*(์: ๋น ์ฑํ ๋ฐฉ ์ ๋ฆฌ, ๊ธฐ๋ณธ๊ฐ ๋ฐฑํ ๋ฑ)
๋ฌธ์
- ๊ทธ๋ฃน ์ฑํ
:
docs/group-chat.md - ์ถ์ ์ค๊ณ:
docs/attendance-design.md
๋ผ์ด์ ์ค
- ๋ฏธ์ ๋๋ ๋ ํฌ์งํ ๋ฆฌ ์์ ์ ์ ์ฑ ์ ๋ฐ๋ฆ ๋๋ค.
An AI character chat/creation platform built with Next.js 15 (App Router) and React 19. It combines Firebase (Auth/Firestore/Storage/Analytics) and Supabase (pgvector) to deliver longโterm memory RAG, summary rollups (SUPA/HYPA), group chat, character/lore management, and an economy layer (points, Stripe, Patreon). PWA and Vercel Cron are supported.
Highlighted directories:
src/appโ Routes (App Router), server routes underapi/*, pages forchat,ranking,lorebook,settings,adminsrc/utils/vector/*โ Embeddings, hybrid retrieval, RAG, summary repository (Supabase)src/utils/memory/*โ Policy/prompts/summarizer (SUPA/HYPA)src/firebase/*โ Firebase client/admin setup, collection helperssupabase/schema/*.sqlโ pgvector/tsvector schema and RPCs (run in SQL Editor)docs/*.mdโ Feature specs (group chat, attendance)
- AI Chat
- Single/group chat, perโcharacter profiles/image selection, recent summary injection
- LLM providers: Google AI Studio (Gemini/Vertex), OpenRouter (Anthropic/OpenAI)
- Longโterm memory (RAG): Supabase pgvector + tsvector hybrid, summaryโfirst retrieval
- Content/Assets
- Character/lorebook CRUD, image generation (
/api/generate-image), conversation summarization (/api/summarize)
- Character/lorebook CRUD, image generation (
- Economy/Ranking
- Points balance/ledger, Stripe checkout/webhook, Patreon OAuth
- Daily/weekly/monthly ranking aggregation (cron) and fetch (
/api/rankings)
- Admin/Security
- Admin role management (
src/app/admin/users/page.tsx), cleanup cron - Firestore rules and indexes (
firestore.rules,firestore.indexes.json)
- Admin role management (
- Ops
- Vercel Cron (
vercel.json), PWA (next-pwa,public/manifest.json,public/sw.js)
- Vercel Cron (
- Web: Next.js 15, React 19, TypeScript, Mantine + MUI
- Backend: Firebase Admin, Supabase (Postgres + pgvector + pg_trgm + tsvector)
- AI: Google Generative AI/Vertex, OpenRouter, OpenAI (incl. embeddings)
- Payments: Stripe (Checkout/Webhook), Patreon
- Infra: Vercel, PWA, Vercel Cron
Prereqs
- Node.js 20+ recommended, pnpm 9+
- Firebase project, Supabase project, Stripe account, (optional) Patreon client
- Install deps
pnpm install- Configure env
- Copy
.env.exampleโ.envor.env.localand fill in values. - Minimum required:
- Firebase Web:
NEXT_PUBLIC_FIREBASE_* - Firebase Admin:
FIREBASE_ADMIN_SDK_CONFIG(JSON) orGOOGLE_APPLICATION_CREDENTIALS - Supabase (serverโonly):
SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY, (opt)SUPABASE_ANON_KEY - AI keys:
GOOGLE_AI_STUDIO_API_KEYorGOOGLE_AI_STUDIO_API_KEYS, (opt)OPENROUTER_API_KEY,OPENAI_API_KEY - Payments:
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET - Cron:
CRON_SECRET(aggregation),CRON_SECRET_TOKEN(cleanup)
- Firebase Web:
Important: Never expose SUPABASE_SERVICE_ROLE_KEY to the client. Itโs serverโonly.
- Apply Supabase schema
- Run the SQL files in this order via Supabase SQL Editor:
001_chat_message_embeddings.sqlโ002_match_chat_messages.sqlโ004_enable_trgm_and_lexical.sqlโ005_match_chat_messages_hybrid.sqlโ006_parent_child_windowing.sqlโ007_memory_summaries.sqlโ008_memory_summaries_param_fix.sqlโ009_memory_roomid_to_text.sqlโ010_memory_summaries_rpc_roomid_text.sql
- Start dev server
pnpm devFirebase
NEXT_PUBLIC_FIREBASE_*for client config- Admin:
FIREBASE_ADMIN_SDK_CONFIG(stringified JSON) orGOOGLE_APPLICATION_CREDENTIALS
Supabase (serverโonly)
SUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY, (opt)SUPABASE_ANON_KEY
AI/Embeddings
- Google AI Studio:
GOOGLE_AI_STUDIO_API_KEYorGOOGLE_AI_STUDIO_API_KEYS - OpenRouter:
OPENROUTER_API_KEY - OpenAI embeddings:
OPENAI_API_KEY, (opt)EMBED_PROVIDER,EMBED_MODEL,LOCAL_EMBEDDING_URL
Payments/Membership
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRETPATREON_CLIENT_ID,PATREON_CLIENT_SECRET,PATREON_REDIRECT_URI
Cron/Ops
CRON_SECRET,CRON_SECRET_TOKEN
Summary/Memory/RAG
- Memory policy (
src/utils/memory/policy.ts): thresholds, modes - RAG retrieval (
src/utils/vector/rag.ts): mode/hybrid knobs, decay, debug - Summarizer API (
src/app/api/summarize/route.ts): server/client budget limits
- Indexing via
/api/vector/index-messageโchat_message_embeddings - Retrieval: hybrid (pgvector + lexical with optional decay) via
match_chat_messages_hybrid - Summaryโfirst: match in
chat_memory_summaries(SUPA/HYPA) and optionally enrich with message snippets - Automatic rollups: SUPA and HYPA are produced based on thresholds and linked in
chat_memory_links - Unified system block injected into model prompts to improve grounding
See:
src/app/api/chat/bot-response/route.tssrc/utils/vector/*,src/utils/memory/*supabase/schema/*.sql
- Chat:
POST /api/chat/bot-response,POST /api/chat/convert,POST /api/vector/index-message - Generation/Summarization:
POST /api/generate-lore,POST /api/generate-image,POST /api/summarize - Economy/Ranking:
POST /api/stripe/checkout,POST /api/stripe/webhook,GET /api/rankings - Cron:
GET /api/cron/aggregate-rankings/*(setX-Cron-Auth: $CRON_SECRET)
- Prefer Vercel. Cron jobs are defined in
vercel.json. - Stripe webhook verification uses
STRIPE_WEBHOOK_SECRET. - Vertex/Google AI requires proper service account credentials (
GOOGLE_APPLICATION_CREDENTIALSor JSON string var).
Security
- Never expose service role keys or service account JSON to the client.
- Keep Firestore rules and indexes in sync.
- Monitor token usage and point deduction for paid models.
- Core:
dev,build,start,lint - Migrations/maintenance under
scripts/migrations/*,src/scripts/*
Docs
- Group chat:
docs/group-chat.md - Attendance:
docs/attendance-design.md
License
- Apache-2.0 licensed.