Implement dynamic daily verse system with rotating Biblical content
- Add daily-verse API endpoint with 7 rotating verses in Romanian and English - Replace static homepage verse with dynamic fetch from API - Ensure consistent daily rotation using day-of-year calculation - Support both ro and en locales for verse content 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,33 @@ export default function Home() {
|
|||||||
const [userCount, setUserCount] = useState(2847)
|
const [userCount, setUserCount] = useState(2847)
|
||||||
const [expandedFaq, setExpandedFaq] = useState<string | false>(false)
|
const [expandedFaq, setExpandedFaq] = useState<string | false>(false)
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
|
const [dailyVerse, setDailyVerse] = useState<{
|
||||||
|
date: string
|
||||||
|
verse: string
|
||||||
|
reference: string
|
||||||
|
} | null>(null)
|
||||||
|
|
||||||
|
// Fetch daily verse
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchDailyVerse = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/daily-verse?locale=${locale}`)
|
||||||
|
if (response.ok) {
|
||||||
|
const result = await response.json()
|
||||||
|
setDailyVerse(result.data)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch daily verse:', error)
|
||||||
|
// Fallback to static content if API fails
|
||||||
|
setDailyVerse({
|
||||||
|
date: getCurrentDate(),
|
||||||
|
verse: t('dailyVerse.verse'),
|
||||||
|
reference: t('dailyVerse.reference')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchDailyVerse()
|
||||||
|
}, [locale, t])
|
||||||
|
|
||||||
// Simulate live user counter
|
// Simulate live user counter
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -229,15 +256,15 @@ export default function Home() {
|
|||||||
{t('dailyVerse.title')}
|
{t('dailyVerse.title')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" textAlign="center" sx={{ mb: 4, opacity: 0.9 }}>
|
<Typography variant="body2" textAlign="center" sx={{ mb: 4, opacity: 0.9 }}>
|
||||||
{getCurrentDate()}
|
{dailyVerse?.date || getCurrentDate()}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Paper sx={{ p: 4, textAlign: 'center', bgcolor: 'rgba(255,255,255,0.95)', color: 'text.primary', borderRadius: 3 }}>
|
<Paper sx={{ p: 4, textAlign: 'center', bgcolor: 'rgba(255,255,255,0.95)', color: 'text.primary', borderRadius: 3 }}>
|
||||||
<Typography variant="h5" sx={{ mb: 3, fontStyle: 'italic', lineHeight: 1.6 }}>
|
<Typography variant="h5" sx={{ mb: 3, fontStyle: 'italic', lineHeight: 1.6 }}>
|
||||||
{t('dailyVerse.verse')}
|
{dailyVerse?.verse || t('dailyVerse.verse')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="h6" color="primary" sx={{ fontWeight: 600 }}>
|
<Typography variant="h6" color="primary" sx={{ fontWeight: 600 }}>
|
||||||
{t('dailyVerse.reference')}
|
{dailyVerse?.reference || t('dailyVerse.reference')}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', gap: 1, justifyContent: 'center', mt: 3 }}>
|
<Box sx={{ display: 'flex', gap: 1, justifyContent: 'center', mt: 3 }}>
|
||||||
@@ -245,8 +272,8 @@ export default function Home() {
|
|||||||
<IconButton
|
<IconButton
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const verseText = t('dailyVerse.verse')
|
const verseText = dailyVerse?.verse || t('dailyVerse.verse')
|
||||||
const reference = t('dailyVerse.reference')
|
const reference = dailyVerse?.reference || t('dailyVerse.reference')
|
||||||
const discussMessage = locale === 'ro'
|
const discussMessage = locale === 'ro'
|
||||||
? `Poți să îmi explici mai mult despre acest verset: "${verseText}" (${reference})?`
|
? `Poți să îmi explici mai mult despre acest verset: "${verseText}" (${reference})?`
|
||||||
: `Can you explain more about this verse: "${verseText}" (${reference})?`
|
: `Can you explain more about this verse: "${verseText}" (${reference})?`
|
||||||
|
|||||||
137
app/api/daily-verse/route.ts
Normal file
137
app/api/daily-verse/route.ts
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
// Daily verses collection - you can expand this with more verses
|
||||||
|
const DAILY_VERSES = [
|
||||||
|
{
|
||||||
|
verse: "Căci Eu știu gândurile pe care le am cu privire la voi, zice Domnul, gânduri de pace și nu de rău, ca să vă dau un viitor și o speranță.",
|
||||||
|
reference: "Ieremia 29:11",
|
||||||
|
verseEn: "For I know the plans I have for you, declares the Lord, plans to prosper you and not to harm you, plans to give you hope and a future.",
|
||||||
|
referenceEn: "Jeremiah 29:11"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
verse: "Încrede-te în Domnul din toată inima ta și nu te bizui pe înțelepciunea ta.",
|
||||||
|
reference: "Proverbe 3:5",
|
||||||
|
verseEn: "Trust in the Lord with all your heart and lean not on your own understanding.",
|
||||||
|
referenceEn: "Proverbs 3:5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
verse: "Pot totul în Hristos care mă întărește.",
|
||||||
|
reference: "Filipeni 4:13",
|
||||||
|
verseEn: "I can do all things through Christ who strengthens me.",
|
||||||
|
referenceEn: "Philippians 4:13"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
verse: "Și știm că toate lucrurile lucrează împreună pentru binele celor ce iubesc pe Dumnezeu.",
|
||||||
|
reference: "Romani 8:28",
|
||||||
|
verseEn: "And we know that in all things God works for the good of those who love him.",
|
||||||
|
referenceEn: "Romans 8:28"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
verse: "Nu te teme, căci Eu sunt cu tine; nu te uita cu îngrijorare, căci Eu sunt Dumnezeul tău!",
|
||||||
|
reference: "Isaia 41:10",
|
||||||
|
verseEn: "So do not fear, for I am with you; do not be dismayed, for I am your God.",
|
||||||
|
referenceEn: "Isaiah 41:10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
verse: "Domnul este păstorul meu: nu voi duce lipsă de nimic.",
|
||||||
|
reference: "Psalm 23:1",
|
||||||
|
verseEn: "The Lord is my shepherd, I lack nothing.",
|
||||||
|
referenceEn: "Psalm 23:1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
verse: "Bucurați-vă totdeauna în Domnul! Iarăși zic: Bucurați-vă!",
|
||||||
|
reference: "Filipeni 4:4",
|
||||||
|
verseEn: "Rejoice in the Lord always. I will say it again: Rejoice!",
|
||||||
|
referenceEn: "Philippians 4:4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
function getDailyVerse(date: Date, locale: string = 'ro') {
|
||||||
|
// Calculate day of year to ensure the same verse appears all day
|
||||||
|
const start = new Date(date.getFullYear(), 0, 0)
|
||||||
|
const diff = date.getTime() - start.getTime()
|
||||||
|
const dayOfYear = Math.floor(diff / (1000 * 60 * 60 * 24))
|
||||||
|
|
||||||
|
// Use day of year to select verse consistently
|
||||||
|
const verseIndex = dayOfYear % DAILY_VERSES.length
|
||||||
|
const selectedVerse = DAILY_VERSES[verseIndex]
|
||||||
|
|
||||||
|
const formatDate = (date: Date, locale: string) => {
|
||||||
|
if (locale === 'ro') {
|
||||||
|
return date.toLocaleDateString('ro-RO', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return date.toLocaleDateString('en-US', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
date: formatDate(date, locale),
|
||||||
|
verse: locale === 'ro' ? selectedVerse.verse : selectedVerse.verseEn,
|
||||||
|
reference: locale === 'ro' ? selectedVerse.reference : selectedVerse.referenceEn,
|
||||||
|
dayOfYear,
|
||||||
|
verseIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GET(request: NextRequest) {
|
||||||
|
try {
|
||||||
|
const { searchParams } = new URL(request.url)
|
||||||
|
const locale = searchParams.get('locale') || 'ro'
|
||||||
|
|
||||||
|
// Validate locale
|
||||||
|
if (!['ro', 'en'].includes(locale)) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Invalid locale. Must be "ro" or "en".' },
|
||||||
|
{ status: 400 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const today = new Date()
|
||||||
|
const dailyVerse = getDailyVerse(today, locale)
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
data: dailyVerse
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Daily verse API error:', error)
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
error: 'Failed to get daily verse',
|
||||||
|
message: error instanceof Error ? error.message : 'Unknown error'
|
||||||
|
},
|
||||||
|
{ status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Add POST endpoint to add new verses (for admin use)
|
||||||
|
export async function POST(request: NextRequest) {
|
||||||
|
try {
|
||||||
|
const body = await request.json()
|
||||||
|
|
||||||
|
// This would typically save to database
|
||||||
|
// For now, just return success
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
message: 'Daily verse system is read-only for now'
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Daily verse POST error:', error)
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Failed to process request' },
|
||||||
|
{ status: 500 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
````markdown
|
||||||
|
# Unified SEO & Content Strategy for **Ghid Biblic / Biblical Guide**
|
||||||
|
|
||||||
|
This document provides:
|
||||||
|
1. Unified homepage texts (Romanian + English, SEO-optimized)
|
||||||
|
2. Unified SEO `<head>` setup with hreflang cross-linking
|
||||||
|
3. Best practices to avoid duplicate content penalties
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Homepage Texts
|
||||||
|
|
||||||
|
### Romanian (RO)
|
||||||
|
|
||||||
|
#### H1
|
||||||
|
**Ghid Biblic – Studiu biblic online cu AI, versete zilnice și comunitate de rugăciune**
|
||||||
|
|
||||||
|
#### Hero
|
||||||
|
Ghid Biblic este o aplicație de studiu biblic online. Citește Scriptura, pune întrebări cu ajutorul chatului AI, caută versete rapid și alătură-te unei comunități de rugăciune care te sprijină zilnic.
|
||||||
|
|
||||||
|
**CTA:**
|
||||||
|
Încearcă acum gratuit - Chat AI
|
||||||
|
|
||||||
|
#### Social Proof
|
||||||
|
Alătură-te miilor de credincioși care folosesc Ghid Biblic pentru a înțelege și aplica Cuvântul lui Dumnezeu în viața de zi cu zi.
|
||||||
|
|
||||||
|
#### Daily Verse
|
||||||
|
*Versetul biblic al zilei – primește zilnic inspirație din Scriptură direct în inbox.*
|
||||||
|
|
||||||
|
> Căci Eu știu gândurile pe care le am cu privire la voi, zice Domnul, gânduri de pace și nu de rău, ca să vă dau un viitor și o speranță.
|
||||||
|
> *Ieremia 29:11*
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
- **Citește Biblia online** – toate cele 66 de cărți biblice într-o interfață modernă și intuitivă
|
||||||
|
- **Chat AI biblic** – întreabă Scriptura și primește răspunsuri clare, fundamentate pe versete
|
||||||
|
- **Comunitate de rugăciune** – trimite și primește cereri de rugăciune
|
||||||
|
- **Căutare versete** – găsește rapid pasaje, cuvinte cheie și teme biblice
|
||||||
|
|
||||||
|
#### Footer
|
||||||
|
Ghid Biblic – aplicație de studiu biblic online, cu chat AI, versete zilnice și comunitate de rugăciune.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### English (EN)
|
||||||
|
|
||||||
|
#### H1
|
||||||
|
**Biblical Guide – Online Bible Study with AI Chat, Daily Verses, and Prayer Community**
|
||||||
|
|
||||||
|
#### Hero
|
||||||
|
Biblical Guide is an online Bible study app. Read Scripture, ask questions with AI-powered chat, search verses instantly, and join a global prayer community that supports your spiritual growth.
|
||||||
|
|
||||||
|
**CTA:**
|
||||||
|
Try it free now – AI Bible chat
|
||||||
|
|
||||||
|
#### Social Proof
|
||||||
|
Join thousands of believers who use Biblical Guide to study, understand, and apply God’s Word in their everyday lives.
|
||||||
|
|
||||||
|
#### Daily Verse
|
||||||
|
*Daily Bible Verse – receive encouragement from Scripture every day, straight to your inbox.*
|
||||||
|
|
||||||
|
> “For I know the plans I have for you,” declares the Lord, “plans to prosper you and not to harm you, plans to give you hope and a future.”
|
||||||
|
> *Jeremiah 29:11*
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
- **Read the Bible online** – access all 66 books with a modern and intuitive interface
|
||||||
|
- **AI Bible Chat** – ask Scripture questions and get clear, accurate answers
|
||||||
|
- **Prayer Community** – share requests and join others in prayer
|
||||||
|
- **Verse Search** – quickly find verses, keywords, and topics across the Bible
|
||||||
|
|
||||||
|
#### Footer
|
||||||
|
Biblical Guide – online Bible study app with AI chat, daily verses, and prayer community.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Unified SEO `<head>` Setup
|
||||||
|
|
||||||
|
### Meta Titles
|
||||||
|
- RO:
|
||||||
|
```html
|
||||||
|
<title>Ghid Biblic – Studiu Biblic Online cu AI, Versete Zilnice și Comunitate de Rugăciune</title>
|
||||||
|
````
|
||||||
|
|
||||||
|
* EN:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<title>Biblical Guide – Online Bible Study with AI, Daily Verses & Prayer Community</title>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Meta Descriptions
|
||||||
|
|
||||||
|
* RO:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta name="description" content="Ghid Biblic este o aplicație de studiu biblic online cu chat AI, căutare rapidă de versete și o comunitate de rugăciune. Primește versete zilnice și răspunsuri clare din Scriptură.">
|
||||||
|
```
|
||||||
|
|
||||||
|
* EN:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta name="description" content="Biblical Guide is an online Bible study app with AI-powered chat, instant verse search, and a global prayer community. Get daily Bible verses and Scripture-based answers to your questions.">
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Keywords
|
||||||
|
|
||||||
|
*(Optional, modern SEO engines use them less but safe to include)*
|
||||||
|
|
||||||
|
* RO:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta name="keywords" content="studiu biblic online, aplicație biblică, chat AI biblic, versete biblice zilnice, comunitate de rugăciune, citește Biblia online, căutare versete, Biblia Română">
|
||||||
|
```
|
||||||
|
|
||||||
|
* EN:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta name="keywords" content="online Bible study, AI Bible chat, daily Bible verse, Bible study app, prayer community, read the Bible online, verse search, Scripture study">
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Canonical
|
||||||
|
|
||||||
|
Both languages point to their own canonical URL:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link rel="canonical" href="https://ghidbiblic.com/ro/" hreflang="ro" />
|
||||||
|
<link rel="canonical" href="https://ghidbiblic.com/en/" hreflang="en" />
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Hreflang Cross-Linking
|
||||||
|
|
||||||
|
```html
|
||||||
|
<link rel="alternate" hreflang="ro" href="https://ghidbiblic.com/ro/" />
|
||||||
|
<link rel="alternate" hreflang="en" href="https://ghidbiblic.com/en/" />
|
||||||
|
<link rel="alternate" hreflang="x-default" href="https://ghidbiblic.com/" />
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Open Graph (OG)
|
||||||
|
|
||||||
|
* RO:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta property="og:title" content="Ghid Biblic – Studiu Biblic Online cu AI" />
|
||||||
|
<meta property="og:description" content="Citește Biblia online, pune întrebări prin chat AI și alătură-te unei comunități de rugăciune. Primește versete zilnice în inbox." />
|
||||||
|
<meta property="og:url" content="https://ghidbiblic.com/ro/" />
|
||||||
|
<meta property="og:image" content="https://ghidbiblic.com/og-image-ro.jpg" />
|
||||||
|
```
|
||||||
|
|
||||||
|
* EN:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta property="og:title" content="Biblical Guide – Online Bible Study with AI" />
|
||||||
|
<meta property="og:description" content="Read the Bible online, ask questions with AI chat, and join a prayer community. Get daily Bible verses in your inbox." />
|
||||||
|
<meta property="og:url" content="https://ghidbiblic.com/en/" />
|
||||||
|
<meta property="og:image" content="https://ghidbiblic.com/og-image-en.jpg" />
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Twitter Card
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:site" content="@ghidbiblic" />
|
||||||
|
```
|
||||||
|
|
||||||
|
RO version:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta name="twitter:title" content="Ghid Biblic – Studiu Biblic Online cu AI" />
|
||||||
|
<meta name="twitter:description" content="Aplicație biblică online cu chat AI, versete zilnice și comunitate de rugăciune." />
|
||||||
|
<meta name="twitter:image" content="https://ghidbiblic.com/og-image-ro.jpg" />
|
||||||
|
```
|
||||||
|
|
||||||
|
EN version:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<meta name="twitter:title" content="Biblical Guide – Online Bible Study with AI" />
|
||||||
|
<meta name="twitter:description" content="Online Bible study app with AI chat, daily verses, and prayer community." />
|
||||||
|
<meta name="twitter:image" content="https://ghidbiblic.com/og-image-en.jpg" />
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Schema.org (JSON-LD)
|
||||||
|
|
||||||
|
Single schema with multiple languages:
|
||||||
|
|
||||||
|
```json
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "MobileApplication",
|
||||||
|
"name": ["Ghid Biblic", "Biblical Guide"],
|
||||||
|
"url": "https://ghidbiblic.com",
|
||||||
|
"description": {
|
||||||
|
"ro": "Aplicație de studiu biblic online cu chat AI, versete zilnice și comunitate de rugăciune.",
|
||||||
|
"en": "Online Bible study app with AI-powered chat, daily Bible verses, instant search, and a prayer community."
|
||||||
|
},
|
||||||
|
"applicationCategory": "EducationApplication",
|
||||||
|
"operatingSystem": "iOS, Android, Web",
|
||||||
|
"inLanguage": ["ro", "en"],
|
||||||
|
"offers": {
|
||||||
|
"@type": "Offer",
|
||||||
|
"price": "0",
|
||||||
|
"priceCurrency": "USD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Best Practices to Avoid Duplicate Content
|
||||||
|
|
||||||
|
1. **Hreflang implementation** – Ensure Romanian and English pages point to each other.
|
||||||
|
2. **Separate URLs per language** – e.g., `/ro/` and `/en/`.
|
||||||
|
3. **Canonical tags per version** – Each language version should self-reference.
|
||||||
|
4. **Localized metadata** – Meta title, description, and OG tags must be language-specific.
|
||||||
|
5. **X-default landing page** – The root (`/`) can act as a language selector or default (EN).
|
||||||
|
6. **Consistent translations** – Avoid auto-translating SEO tags; use tailored keywords per language.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ With this setup, search engines will correctly index both RO and EN versions, serve the right one to users based on language/region, and avoid duplicate content penalties.
|
||||||
|
|
||||||
|
```
|
||||||
347
temp/admin-dashboard-mvp.md
Normal file
347
temp/admin-dashboard-mvp.md
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
# BiblicalGuide Admin Dashboard - MVP Features
|
||||||
|
|
||||||
|
## 1. Dashboard Overview (Home)
|
||||||
|
|
||||||
|
### Key Metrics Cards
|
||||||
|
- **Total Users** (number + % change from last week)
|
||||||
|
- **Daily Active Users** (DAU - real-time count)
|
||||||
|
- **AI Conversations Today** (count + cost estimate)
|
||||||
|
- **Active Now** (users currently online)
|
||||||
|
|
||||||
|
### Quick Stats
|
||||||
|
- **New signups** (last 24 hours)
|
||||||
|
- **Total bookmarks created** (all-time)
|
||||||
|
- **Prayer requests** (last 24 hours)
|
||||||
|
- **Server status** (API health, response time)
|
||||||
|
|
||||||
|
### Activity Feed (Live)
|
||||||
|
- New user registrations
|
||||||
|
- Prayer wall posts
|
||||||
|
- High-engagement AI conversations
|
||||||
|
- Error alerts
|
||||||
|
- System notifications
|
||||||
|
|
||||||
|
## 2. User Management
|
||||||
|
|
||||||
|
### User List View
|
||||||
|
```
|
||||||
|
Search: [_________] Filter: [All Users ▼]
|
||||||
|
|
||||||
|
| Email | Name | Joined | Last Active | AI Chats | Status | Actions |
|
||||||
|
|-------|------|--------|-------------|----------|--------|---------|
|
||||||
|
| user@example.com | John D. | 2024-01-15 | 2 hrs ago | 45 | Active | [View] [Ban] |
|
||||||
|
```
|
||||||
|
|
||||||
|
### User Actions
|
||||||
|
- **View Profile** (see detailed user activity)
|
||||||
|
- **Send Email** (direct communication)
|
||||||
|
- **Reset Password** (force password reset)
|
||||||
|
- **Suspend/Ban** (temporary or permanent)
|
||||||
|
- **Delete Account** (GDPR compliance)
|
||||||
|
|
||||||
|
### User Details Modal
|
||||||
|
- Registration date and method
|
||||||
|
- Total AI conversations
|
||||||
|
- Bookmarks count
|
||||||
|
- Last 10 chat topics
|
||||||
|
- Prayer requests posted
|
||||||
|
- Account status history
|
||||||
|
|
||||||
|
## 3. AI Chat Monitoring
|
||||||
|
|
||||||
|
### Conversations Overview
|
||||||
|
- **Total conversations** (today/week/month)
|
||||||
|
- **Average response time** (target: <5 seconds)
|
||||||
|
- **Error rate** (failed responses %)
|
||||||
|
- **Cost tracking** (OpenAI API spend)
|
||||||
|
|
||||||
|
### Live Chat Monitor
|
||||||
|
```
|
||||||
|
Recent Conversations (Auto-refresh every 30s)
|
||||||
|
|
||||||
|
User: "What does the Bible say about forgiveness?"
|
||||||
|
AI: "The Bible speaks extensively about forgiveness..."
|
||||||
|
[View Full] [Flag] [Quality: ⭐⭐⭐⭐⭐]
|
||||||
|
|
||||||
|
User: "Help me understand Romans 8"
|
||||||
|
AI: "Romans 8 is one of the most powerful chapters..."
|
||||||
|
[View Full] [Flag] [Quality: ⭐⭐⭐⭐⭐]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Quality Control
|
||||||
|
- **Flag inappropriate requests**
|
||||||
|
- **Review AI responses** for theological accuracy
|
||||||
|
- **Common questions** (FAQ generation)
|
||||||
|
- **Failed responses** log
|
||||||
|
- **Response ratings** (if users rate them)
|
||||||
|
|
||||||
|
### Cost Management
|
||||||
|
- Daily API usage ($X.XX)
|
||||||
|
- Projection for current month
|
||||||
|
- Per-user average cost
|
||||||
|
- High-usage user alerts
|
||||||
|
|
||||||
|
## 4. Content Moderation
|
||||||
|
|
||||||
|
### Prayer Wall Moderation
|
||||||
|
```
|
||||||
|
Pending Review (3)
|
||||||
|
|
||||||
|
"Please pray for my family..."
|
||||||
|
[Approve] [Edit] [Reject] [Ban User]
|
||||||
|
|
||||||
|
"Spam content here..."
|
||||||
|
[Approve] [Edit] [Reject] [Ban User]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Moderation Queue
|
||||||
|
- **Prayer requests** (pending approval)
|
||||||
|
- **Reported content** (user flags)
|
||||||
|
- **AI conversation flags** (inappropriate)
|
||||||
|
- **Bulk actions** (approve/reject all)
|
||||||
|
|
||||||
|
### Auto-Moderation Settings
|
||||||
|
- Profanity filter (on/off)
|
||||||
|
- Spam detection threshold
|
||||||
|
- Auto-approve trusted users
|
||||||
|
- Keyword blacklist management
|
||||||
|
|
||||||
|
## 5. Analytics Dashboard
|
||||||
|
|
||||||
|
### User Analytics
|
||||||
|
- **Growth Chart** (daily new users - line graph)
|
||||||
|
- **Retention Funnel**
|
||||||
|
- Day 1: 100%
|
||||||
|
- Day 7: 45%
|
||||||
|
- Day 30: 30%
|
||||||
|
- **User Segments**
|
||||||
|
- Power users (>10 chats/week)
|
||||||
|
- Regular (3-10 chats/week)
|
||||||
|
- Casual (<3 chats/week)
|
||||||
|
- Dormant (no activity 7+ days)
|
||||||
|
|
||||||
|
### Engagement Metrics
|
||||||
|
- **Most Read Bible Books** (top 10 bar chart)
|
||||||
|
- **Popular Chat Topics** (word cloud)
|
||||||
|
- **Peak Usage Hours** (heatmap)
|
||||||
|
- **Feature Usage** (bookmarks vs chat vs prayer wall)
|
||||||
|
|
||||||
|
### Simple Conversion Tracking
|
||||||
|
- Sign-up to first chat
|
||||||
|
- First chat to bookmark
|
||||||
|
- Single to returning user
|
||||||
|
- Free to premium (when implemented)
|
||||||
|
|
||||||
|
## 6. System Administration
|
||||||
|
|
||||||
|
### Quick Actions
|
||||||
|
- **Broadcast Message** (banner to all users)
|
||||||
|
- **Maintenance Mode** (on/off toggle)
|
||||||
|
- **Clear Cache** (Redis flush)
|
||||||
|
- **Backup Database** (manual trigger)
|
||||||
|
|
||||||
|
### API Management
|
||||||
|
- **OpenAI API Status**
|
||||||
|
- Current balance
|
||||||
|
- Rate limit status
|
||||||
|
- Error rate
|
||||||
|
- Switch API keys
|
||||||
|
- **Bible API Status**
|
||||||
|
- Response time
|
||||||
|
- Cache hit rate
|
||||||
|
- Error logs
|
||||||
|
|
||||||
|
### Error Monitoring
|
||||||
|
```
|
||||||
|
Recent Errors (Last 24 hours)
|
||||||
|
|
||||||
|
Type | Count | Last Occurred | Status
|
||||||
|
-----|-------|---------------|--------
|
||||||
|
API Timeout | 12 | 10 min ago | [View] [Resolve]
|
||||||
|
Login Failed | 45 | 2 min ago | [View] [Ignore]
|
||||||
|
DB Connection | 0 | - | OK
|
||||||
|
```
|
||||||
|
|
||||||
|
### Server Health
|
||||||
|
- CPU usage (%)
|
||||||
|
- Memory usage (%)
|
||||||
|
- Database connections
|
||||||
|
- API response times
|
||||||
|
- Disk space remaining
|
||||||
|
|
||||||
|
## 7. Communications
|
||||||
|
|
||||||
|
### Email Templates (Basic)
|
||||||
|
- Welcome email
|
||||||
|
- Password reset
|
||||||
|
- Daily verse (if enabled)
|
||||||
|
- Account suspended
|
||||||
|
- System announcements
|
||||||
|
|
||||||
|
### Bulk Email
|
||||||
|
- **Send to**: All users / Active last 7 days / Segment
|
||||||
|
- **Subject**: [_________]
|
||||||
|
- **Message**: [Rich text editor]
|
||||||
|
- **Schedule**: Now / Later
|
||||||
|
- [Send Test] [Schedule] [Send Now]
|
||||||
|
|
||||||
|
### In-App Notifications
|
||||||
|
- Create announcement banner
|
||||||
|
- Target specific user segments
|
||||||
|
- Set expiration time
|
||||||
|
- Track dismissal rate
|
||||||
|
|
||||||
|
## 8. Settings & Configuration
|
||||||
|
|
||||||
|
### App Settings
|
||||||
|
- **Site name**: BiblicalGuide
|
||||||
|
- **Support email**: support@biblical-guide.com
|
||||||
|
- **Daily verse**: Enabled/Disabled
|
||||||
|
- **Prayer wall**: Public/Moderated/Disabled
|
||||||
|
- **AI model**: GPT-4/GPT-3.5
|
||||||
|
- **Rate limits**: X chats per user per day
|
||||||
|
|
||||||
|
### Feature Toggles
|
||||||
|
- [ ] AI Chat enabled
|
||||||
|
- [ ] Prayer Wall enabled
|
||||||
|
- [ ] User registration open
|
||||||
|
- [ ] Daily verse emails
|
||||||
|
- [ ] Social sharing
|
||||||
|
- [ ] Maintenance mode
|
||||||
|
|
||||||
|
### Admin Users
|
||||||
|
```
|
||||||
|
Admin Users (3)
|
||||||
|
|
||||||
|
Email | Role | Last Login | Actions
|
||||||
|
------|------|------------|--------
|
||||||
|
admin@site.com | Super Admin | 1 hr ago | [Edit] [Remove]
|
||||||
|
support@site.com | Moderator | 2 days ago | [Edit] [Remove]
|
||||||
|
[+ Add Admin]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 9. Simple Reporting
|
||||||
|
|
||||||
|
### Daily Report Email
|
||||||
|
- New users count
|
||||||
|
- Total AI conversations
|
||||||
|
- API costs
|
||||||
|
- Error summary
|
||||||
|
- Top chat topics
|
||||||
|
- System health status
|
||||||
|
|
||||||
|
### Export Data
|
||||||
|
- **User list** (CSV)
|
||||||
|
- **Chat logs** (last 30 days)
|
||||||
|
- **Prayer requests** (CSV)
|
||||||
|
- **Analytics summary** (PDF)
|
||||||
|
|
||||||
|
## 10. Security Section
|
||||||
|
|
||||||
|
### Security Log
|
||||||
|
```
|
||||||
|
Recent Security Events
|
||||||
|
|
||||||
|
Time | User | Event | IP Address | Action
|
||||||
|
-----|------|-------|------------|--------
|
||||||
|
10:23 AM | john@... | Failed login (3x) | 192.168.1.1 | [Block IP]
|
||||||
|
09:45 AM | Admin login | Success | 10.0.0.1 | -
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security Actions
|
||||||
|
- View failed login attempts
|
||||||
|
- IP blocking/allowlisting
|
||||||
|
- Force logout all users
|
||||||
|
- Require password reset (bulk)
|
||||||
|
- 2FA enforcement settings
|
||||||
|
|
||||||
|
## Implementation Priority
|
||||||
|
|
||||||
|
### Phase 1 - Critical (Week 1)
|
||||||
|
1. **Login/Authentication** for admins
|
||||||
|
2. **Dashboard overview** (basic metrics)
|
||||||
|
3. **User list** with basic actions
|
||||||
|
4. **AI conversation monitoring** (view only)
|
||||||
|
|
||||||
|
### Phase 2 - Essential (Week 2)
|
||||||
|
1. **Prayer wall moderation**
|
||||||
|
2. **User management** (suspend/ban)
|
||||||
|
3. **Basic analytics** (users, engagement)
|
||||||
|
4. **Error monitoring**
|
||||||
|
|
||||||
|
### Phase 3 - Important (Week 3)
|
||||||
|
1. **Email communications**
|
||||||
|
2. **System settings**
|
||||||
|
3. **Export functionality**
|
||||||
|
4. **Cost tracking**
|
||||||
|
|
||||||
|
## Tech Stack for Admin
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
- **React** with **Recharts** for graphs
|
||||||
|
- **Tailwind CSS** with **shadcn/ui** components
|
||||||
|
- **React Table** for data tables
|
||||||
|
- **React Query** for data fetching
|
||||||
|
|
||||||
|
### Backend Additions
|
||||||
|
- **Admin authentication** (separate from users)
|
||||||
|
- **Role-based access** (admin, moderator)
|
||||||
|
- **Audit logging** (track all admin actions)
|
||||||
|
- **Scheduled jobs** (daily reports)
|
||||||
|
|
||||||
|
### Database Schema Additions
|
||||||
|
```sql
|
||||||
|
-- Admin users table
|
||||||
|
admin_users (
|
||||||
|
id, email, password_hash, role,
|
||||||
|
last_login, created_at
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Audit log table
|
||||||
|
audit_logs (
|
||||||
|
id, admin_id, action, target_user_id,
|
||||||
|
details, ip_address, timestamp
|
||||||
|
)
|
||||||
|
|
||||||
|
-- System settings table
|
||||||
|
settings (
|
||||||
|
key, value, updated_at, updated_by
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Access Control Levels
|
||||||
|
|
||||||
|
### Super Admin
|
||||||
|
- Full access to everything
|
||||||
|
- Can manage other admins
|
||||||
|
- System configuration
|
||||||
|
- Database operations
|
||||||
|
|
||||||
|
### Moderator
|
||||||
|
- Content moderation
|
||||||
|
- User management (not deletion)
|
||||||
|
- View analytics
|
||||||
|
- Cannot change system settings
|
||||||
|
|
||||||
|
### Support
|
||||||
|
- View user details
|
||||||
|
- Reset passwords
|
||||||
|
- View chat logs
|
||||||
|
- Cannot ban/delete users
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
1. **Separate admin authentication** (not regular user accounts)
|
||||||
|
2. **IP allowlisting** for admin access
|
||||||
|
3. **Audit log** all admin actions
|
||||||
|
4. **Session timeout** after 30 min inactive
|
||||||
|
5. **2FA required** for all admin accounts
|
||||||
|
6. **Read-only mode** for most views (explicit edit mode)
|
||||||
|
|
||||||
|
## Success Metrics for Admin
|
||||||
|
|
||||||
|
- **Response time** to user issues < 1 hour
|
||||||
|
- **Moderation queue** cleared daily
|
||||||
|
- **System uptime** > 99.9%
|
||||||
|
- **API costs** within budget
|
||||||
|
- **User complaints** resolved < 24 hours
|
||||||
364
temp/ai-chat-improvements-plan.md
Normal file
364
temp/ai-chat-improvements-plan.md
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
# AI Chat Improvements Plan
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
Enhance the AI chat system with persistent chat history and conversation memory to provide a more engaging and contextual user experience.
|
||||||
|
|
||||||
|
## Current State Analysis
|
||||||
|
- ✅ Basic AI chat with Azure OpenAI integration
|
||||||
|
- ✅ ReactMarkdown rendering for formatted responses
|
||||||
|
- ✅ Floating chat component with fullscreen mode
|
||||||
|
- ✅ Language-specific responses (Romanian/English)
|
||||||
|
- ❌ No chat persistence between sessions
|
||||||
|
- ❌ Limited conversation memory (only last 3 messages)
|
||||||
|
- ❌ No user-specific chat history
|
||||||
|
- ❌ No chat management UI
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
1. **Persistent Chat History**: Store chat conversations in database per user and language
|
||||||
|
2. **Enhanced Memory**: Maintain longer conversation context for better AI responses
|
||||||
|
3. **Chat Management**: Allow users to view, organize, and manage their chat history
|
||||||
|
4. **Multi-language Support**: Separate chat histories for Romanian and English
|
||||||
|
|
||||||
|
## Technical Implementation Plan
|
||||||
|
|
||||||
|
### 1. Database Schema Extensions
|
||||||
|
|
||||||
|
#### 1.1 Chat Conversations Table
|
||||||
|
```prisma
|
||||||
|
model ChatConversation {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
userId String? // Optional for anonymous users
|
||||||
|
title String // Auto-generated from first message
|
||||||
|
language String // 'ro' or 'en'
|
||||||
|
isActive Boolean @default(true)
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
lastMessageAt DateTime @default(now())
|
||||||
|
|
||||||
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
messages ChatMessage[]
|
||||||
|
|
||||||
|
@@index([userId, language, lastMessageAt])
|
||||||
|
@@index([isActive, lastMessageAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
model ChatMessage {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
conversationId String
|
||||||
|
role ChatMessageRole
|
||||||
|
content String @db.Text
|
||||||
|
timestamp DateTime @default(now())
|
||||||
|
metadata Json? // For storing additional context
|
||||||
|
|
||||||
|
conversation ChatConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@index([conversationId, timestamp])
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ChatMessageRole {
|
||||||
|
USER
|
||||||
|
ASSISTANT
|
||||||
|
SYSTEM
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.2 Update User Model
|
||||||
|
```prisma
|
||||||
|
model User {
|
||||||
|
// ... existing fields
|
||||||
|
chatConversations ChatConversation[]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. API Endpoints
|
||||||
|
|
||||||
|
#### 2.1 Chat Conversations API (`/api/chat/conversations`)
|
||||||
|
- **GET**: List user's conversations (paginated, filtered by language)
|
||||||
|
- **POST**: Create new conversation
|
||||||
|
- **DELETE /:id**: Delete conversation
|
||||||
|
|
||||||
|
#### 2.2 Enhanced Chat API (`/api/chat`)
|
||||||
|
- **Modify existing POST**: Include conversation management
|
||||||
|
- **GET /:conversationId**: Get conversation history
|
||||||
|
- **PUT /:conversationId**: Update conversation (rename, etc.)
|
||||||
|
|
||||||
|
#### 2.3 Chat Messages API (`/api/chat/:conversationId/messages`)
|
||||||
|
- **GET**: Get all messages in conversation (paginated)
|
||||||
|
- **POST**: Add message to conversation
|
||||||
|
|
||||||
|
### 3. Frontend Components
|
||||||
|
|
||||||
|
#### 3.1 Enhanced Floating Chat Component
|
||||||
|
```typescript
|
||||||
|
interface FloatingChatProps {
|
||||||
|
conversationId?: string
|
||||||
|
initialMessage?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New state management
|
||||||
|
const [conversations, setConversations] = useState<Conversation[]>([])
|
||||||
|
const [activeConversationId, setActiveConversationId] = useState<string | null>(null)
|
||||||
|
const [messages, setMessages] = useState<ChatMessage[]>([])
|
||||||
|
const [isHistoryOpen, setIsHistoryOpen] = useState(false)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2 Chat History Sidebar
|
||||||
|
```typescript
|
||||||
|
interface ChatHistorySidebarProps {
|
||||||
|
conversations: Conversation[]
|
||||||
|
activeConversationId: string | null
|
||||||
|
onSelectConversation: (id: string) => void
|
||||||
|
onNewConversation: () => void
|
||||||
|
onDeleteConversation: (id: string) => void
|
||||||
|
language: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3 Conversation List Item
|
||||||
|
```typescript
|
||||||
|
interface ConversationListItemProps {
|
||||||
|
conversation: Conversation
|
||||||
|
isActive: boolean
|
||||||
|
onClick: () => void
|
||||||
|
onDelete: () => void
|
||||||
|
onRename: (newTitle: string) => void
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Implementation Phases
|
||||||
|
|
||||||
|
#### Phase 1: Database Schema & Basic API
|
||||||
|
1. **Create Prisma migrations** for new tables
|
||||||
|
2. **Implement conversation CRUD APIs**
|
||||||
|
3. **Add database seed scripts** for testing
|
||||||
|
4. **Update existing chat API** to work with conversations
|
||||||
|
|
||||||
|
#### Phase 2: Enhanced Memory System
|
||||||
|
1. **Modify chat API** to include more conversation context
|
||||||
|
2. **Implement intelligent context selection** (last 10-15 messages)
|
||||||
|
3. **Add conversation summarization** for very long chats
|
||||||
|
4. **Optimize token usage** with smart context management
|
||||||
|
|
||||||
|
#### Phase 3: Frontend Chat Management
|
||||||
|
1. **Add conversation state management** to floating chat
|
||||||
|
2. **Implement chat history sidebar**
|
||||||
|
3. **Add conversation creation/deletion** functionality
|
||||||
|
4. **Implement conversation switching** within chat
|
||||||
|
|
||||||
|
#### Phase 4: Advanced Features
|
||||||
|
1. **Auto-generate conversation titles** from first message
|
||||||
|
2. **Add conversation search/filtering**
|
||||||
|
3. **Implement conversation sharing** (optional)
|
||||||
|
4. **Add conversation export** functionality
|
||||||
|
|
||||||
|
### 5. Detailed Implementation Steps
|
||||||
|
|
||||||
|
#### 5.1 Database Setup
|
||||||
|
```bash
|
||||||
|
# Create migration
|
||||||
|
npx prisma migrate dev --name add-chat-conversations
|
||||||
|
|
||||||
|
# Update database
|
||||||
|
npx prisma db push
|
||||||
|
|
||||||
|
# Generate client
|
||||||
|
npx prisma generate
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5.2 API Implementation Strategy
|
||||||
|
|
||||||
|
**Chat API Enhancement (`/api/chat/route.ts`)**:
|
||||||
|
```typescript
|
||||||
|
// Modified request schema
|
||||||
|
const chatRequestSchema = z.object({
|
||||||
|
message: z.string().min(1),
|
||||||
|
conversationId: z.string().optional(),
|
||||||
|
locale: z.string().default('ro'),
|
||||||
|
userId: z.string().optional()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Enhanced response
|
||||||
|
interface ChatResponse {
|
||||||
|
success: boolean
|
||||||
|
response: string
|
||||||
|
conversationId: string
|
||||||
|
messageId: string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Conversation Management Logic**:
|
||||||
|
```typescript
|
||||||
|
async function handleChatMessage(
|
||||||
|
message: string,
|
||||||
|
conversationId?: string,
|
||||||
|
locale: string = 'ro',
|
||||||
|
userId?: string
|
||||||
|
) {
|
||||||
|
// 1. Get or create conversation
|
||||||
|
const conversation = conversationId
|
||||||
|
? await getConversation(conversationId)
|
||||||
|
: await createConversation(userId, locale, message)
|
||||||
|
|
||||||
|
// 2. Get conversation history (last 15 messages)
|
||||||
|
const history = await getConversationHistory(conversation.id, 15)
|
||||||
|
|
||||||
|
// 3. Generate AI response with full context
|
||||||
|
const aiResponse = await generateBiblicalResponse(message, locale, history)
|
||||||
|
|
||||||
|
// 4. Save both user message and AI response
|
||||||
|
await saveMessages(conversation.id, [
|
||||||
|
{ role: 'user', content: message },
|
||||||
|
{ role: 'assistant', content: aiResponse }
|
||||||
|
])
|
||||||
|
|
||||||
|
// 5. Update conversation metadata
|
||||||
|
await updateConversationActivity(conversation.id)
|
||||||
|
|
||||||
|
return { response: aiResponse, conversationId: conversation.id }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5.3 Frontend State Management
|
||||||
|
|
||||||
|
**Enhanced Floating Chat Hook**:
|
||||||
|
```typescript
|
||||||
|
function useFloatingChat() {
|
||||||
|
const [conversations, setConversations] = useState<Conversation[]>([])
|
||||||
|
const [activeConversation, setActiveConversation] = useState<Conversation | null>(null)
|
||||||
|
const [messages, setMessages] = useState<ChatMessage[]>([])
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
|
||||||
|
const loadConversations = useCallback(async () => {
|
||||||
|
// Fetch user's conversations
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const switchConversation = useCallback(async (conversationId: string) => {
|
||||||
|
// Load conversation messages
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const startNewConversation = useCallback(() => {
|
||||||
|
// Reset state for new conversation
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const sendMessage = useCallback(async (message: string) => {
|
||||||
|
// Send message with conversation context
|
||||||
|
}, [activeConversation])
|
||||||
|
|
||||||
|
return {
|
||||||
|
conversations,
|
||||||
|
activeConversation,
|
||||||
|
messages,
|
||||||
|
isLoading,
|
||||||
|
loadConversations,
|
||||||
|
switchConversation,
|
||||||
|
startNewConversation,
|
||||||
|
sendMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. UI/UX Enhancements
|
||||||
|
|
||||||
|
#### 6.1 Chat History Sidebar Layout
|
||||||
|
```
|
||||||
|
┌─────────────────┬──────────────────────┐
|
||||||
|
│ Chat History │ Active Chat │
|
||||||
|
│ │ │
|
||||||
|
│ ○ New Chat │ ┌─ Messages ─────┐ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ╔═ Today ═══ │ │ User: Question │ │
|
||||||
|
│ ║ ○ Bible Q&A │ │ AI: Response │ │
|
||||||
|
│ ║ ○ Prayer Help │ │ ... │ │
|
||||||
|
│ ╚═══════════ │ │ │ │
|
||||||
|
│ │ └────────────────┘ │
|
||||||
|
│ ╔═ Yesterday ═ │ ┌─ Input ──────────┐ │
|
||||||
|
│ ║ ○ Verse Study │ │ [Type message... ]│ │
|
||||||
|
│ ╚═══════════ │ └──────────────────┘ │
|
||||||
|
└─────────────────┴──────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 6.2 Mobile-Responsive Design
|
||||||
|
- **Mobile**: Stack history as overlay/drawer
|
||||||
|
- **Tablet**: Side-by-side with collapsed history
|
||||||
|
- **Desktop**: Full side-by-side layout
|
||||||
|
|
||||||
|
### 7. Performance Considerations
|
||||||
|
|
||||||
|
#### 7.1 Database Optimization
|
||||||
|
- **Indexes**: conversation lookups, message pagination
|
||||||
|
- **Pagination**: Limit conversation and message queries
|
||||||
|
- **Cleanup**: Archive old conversations after 6 months
|
||||||
|
|
||||||
|
#### 7.2 Frontend Optimization
|
||||||
|
- **Lazy loading**: Load conversations on demand
|
||||||
|
- **Virtualization**: For large message lists
|
||||||
|
- **Caching**: Cache conversation metadata
|
||||||
|
|
||||||
|
#### 7.3 AI Context Management
|
||||||
|
- **Smart truncation**: Summarize old messages if context too long
|
||||||
|
- **Relevance scoring**: Prioritize recent and relevant messages
|
||||||
|
- **Token optimization**: Balance context richness vs cost
|
||||||
|
|
||||||
|
### 8. Security & Privacy
|
||||||
|
|
||||||
|
#### 8.1 Data Protection
|
||||||
|
- **User isolation**: Strict user-based access control
|
||||||
|
- **Encryption**: Sensitive conversation content
|
||||||
|
- **Retention policy**: Auto-delete after configurable period
|
||||||
|
|
||||||
|
#### 8.2 Anonymous Users
|
||||||
|
- **Session-based storage**: For non-authenticated users
|
||||||
|
- **Migration path**: Convert anonymous chats to user accounts
|
||||||
|
|
||||||
|
### 9. Testing Strategy
|
||||||
|
|
||||||
|
#### 9.1 Unit Tests
|
||||||
|
- Conversation CRUD operations
|
||||||
|
- Message history management
|
||||||
|
- AI context generation
|
||||||
|
|
||||||
|
#### 9.2 Integration Tests
|
||||||
|
- Full chat flow with persistence
|
||||||
|
- Conversation switching
|
||||||
|
- Multi-language handling
|
||||||
|
|
||||||
|
#### 9.3 User Testing
|
||||||
|
- Chat history navigation
|
||||||
|
- Conversation management
|
||||||
|
- Mobile responsiveness
|
||||||
|
|
||||||
|
### 10. Deployment Considerations
|
||||||
|
|
||||||
|
#### 10.1 Migration Strategy
|
||||||
|
- **Backward compatibility**: Existing chat continues to work
|
||||||
|
- **Data migration**: Convert existing session data if applicable
|
||||||
|
- **Feature flags**: Gradual rollout of new features
|
||||||
|
|
||||||
|
#### 10.2 Monitoring
|
||||||
|
- **Conversation metrics**: Creation, length, engagement
|
||||||
|
- **Performance monitoring**: API response times
|
||||||
|
- **Error tracking**: Failed chat operations
|
||||||
|
|
||||||
|
## Success Metrics
|
||||||
|
|
||||||
|
1. **User Engagement**: Longer chat sessions, return conversations
|
||||||
|
2. **Conversation Quality**: Better AI responses with context
|
||||||
|
3. **User Satisfaction**: Positive feedback on chat experience
|
||||||
|
4. **Technical Performance**: Fast conversation loading, reliable persistence
|
||||||
|
|
||||||
|
## Timeline Estimate
|
||||||
|
|
||||||
|
- **Phase 1** (Database & API): 3-4 days
|
||||||
|
- **Phase 2** (Enhanced Memory): 2-3 days
|
||||||
|
- **Phase 3** (Frontend Management): 4-5 days
|
||||||
|
- **Phase 4** (Advanced Features): 3-4 days
|
||||||
|
|
||||||
|
**Total**: ~2-3 weeks for complete implementation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. Review and approve this plan
|
||||||
|
2. Begin with Phase 1: Database schema and basic API
|
||||||
|
3. Implement incremental improvements
|
||||||
|
4. Test thoroughly at each phase
|
||||||
|
5. Gather user feedback and iterate
|
||||||
372
temp/azure-embed3-bible-pgvector-guide.md
Normal file
372
temp/azure-embed3-bible-pgvector-guide.md
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
# Azure OpenAI **embed-3** → Postgres + pgvector Ingestion Guide (Bible Corpus)
|
||||||
|
|
||||||
|
**Goal**: Create a production‑ready Python script that ingests the full Bible (Markdown source) into **Postgres** with **pgvector** and **full‑text** metadata, using **Azure OpenAI `embed-3`** embeddings. The vectors will power a consumer chat assistant (Q&A & conversations about the Bible) and a backend agent that generates custom prayers.
|
||||||
|
|
||||||
|
> Sample corpus used here: Romanian *Biblia Fidela* (Markdown). Structure contains books, chapters, verses (e.g., *Geneza 1:1…*) and a TOC in the file. fileciteturn0file0
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0) Architecture at a glance
|
||||||
|
|
||||||
|
- **Input**: Bible in Markdown (`*.md`) → parser → normalized records: *(book, chapter, verse, text, lang=ro)*
|
||||||
|
- **Embedding**: Azure OpenAI **embed-3** (prefer `text-embedding-3-large`, 3072‑D). Batch inputs to cut cost/latency.
|
||||||
|
- **Storage**: Postgres with:
|
||||||
|
- `pgvector` column `embedding vector(3072)`
|
||||||
|
- `tsvector` column for hybrid lexical search (Romanian or English config as needed)
|
||||||
|
- metadata columns for fast filtering (book, chapter, verse, testament, translation, language)
|
||||||
|
- **Indexes**: `ivfflat` over `embedding`, GIN over `tsv` (and btree over metadata)
|
||||||
|
- **Retrieval**:
|
||||||
|
- Dense vector kNN
|
||||||
|
- Hybrid: combine kNN score + BM25/tsvector
|
||||||
|
- Windowed context stitching (neighbor verses) for chat
|
||||||
|
- **Consumers**:
|
||||||
|
- Chat assistant: answer + cite (book:chapter:verse).
|
||||||
|
- Prayer agent: prompt‑compose with retrieved passages & user intents.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1) Prerequisites
|
||||||
|
|
||||||
|
### Postgres + pgvector
|
||||||
|
```bash
|
||||||
|
# Install pgvector (on Ubuntu)
|
||||||
|
sudo apt-get update && sudo apt-get install -y postgresql postgresql-contrib
|
||||||
|
# In psql as superuser:
|
||||||
|
CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Python deps
|
||||||
|
```bash
|
||||||
|
python -m venv .venv && source .venv/bin/activate
|
||||||
|
pip install psycopg[binary] pgvector pydantic python-dotenv httpx tqdm rapidfuzz
|
||||||
|
```
|
||||||
|
|
||||||
|
> `httpx` for HTTP (async‑capable), `pgvector` adapter, `rapidfuzz` for optional de‑dup or heuristic joins, `tqdm` for progress.
|
||||||
|
|
||||||
|
### Azure OpenAI
|
||||||
|
- Create **Embeddings** deployment for **`text-embedding-3-large`** (or `-small` if cost sensitive). Name it (e.g.) `embeddings`.
|
||||||
|
- Collect:
|
||||||
|
- `AZURE_OPENAI_ENDPOINT=https://<your>.openai.azure.com/`
|
||||||
|
- `AZURE_OPENAI_API_KEY=...`
|
||||||
|
- `AZURE_OPENAI_API_VERSION=2024-05-01-preview` *(or your current stable)*
|
||||||
|
- `AZURE_OPENAI_EMBED_DEPLOYMENT=embeddings` *(your deployment name)*
|
||||||
|
|
||||||
|
Create `.env`:
|
||||||
|
```env
|
||||||
|
DATABASE_URL=postgresql://user:pass@localhost:5432/bible
|
||||||
|
AZURE_OPENAI_ENDPOINT=https://YOUR_RESOURCE.openai.azure.com/
|
||||||
|
AZURE_OPENAI_API_KEY=YOUR_KEY
|
||||||
|
AZURE_OPENAI_API_VERSION=2024-05-01-preview
|
||||||
|
AZURE_OPENAI_EMBED_DEPLOYMENT=embeddings
|
||||||
|
EMBED_DIMS=3072
|
||||||
|
BIBLE_MD_PATH=./Biblia-Fidela-limba-romana.md
|
||||||
|
LANG_CODE=ro
|
||||||
|
TRANSLATION_CODE=FIDELA
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2) Database schema
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- One-time setup in your database
|
||||||
|
CREATE EXTENSION IF NOT EXISTS vector;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS bible_passages (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
testament TEXT NOT NULL, -- 'OT' or 'NT'
|
||||||
|
book TEXT NOT NULL,
|
||||||
|
chapter INT NOT NULL,
|
||||||
|
verse INT NOT NULL,
|
||||||
|
ref TEXT GENERATED ALWAYS AS (book || ' ' || chapter || ':' || verse) STORED,
|
||||||
|
lang TEXT NOT NULL DEFAULT 'ro',
|
||||||
|
translation TEXT NOT NULL DEFAULT 'FIDELA',
|
||||||
|
text_raw TEXT NOT NULL, -- exact verse text
|
||||||
|
text_norm TEXT NOT NULL, -- normalized/cleaned text (embedding input)
|
||||||
|
tsv tsvector,
|
||||||
|
embedding vector(3072), -- 1536 if using embed-3-small
|
||||||
|
created_at TIMESTAMPTZ DEFAULT now(),
|
||||||
|
updated_at TIMESTAMPTZ DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Uniqueness by canonical reference within translation/language
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS ux_ref_lang ON bible_passages (translation, lang, book, chapter, verse);
|
||||||
|
|
||||||
|
-- Full-text index (choose config; Romanian available if installed via ISPELL; else use 'simple' or 'english')
|
||||||
|
-- If you have pg_catalog.romanian, use that. Else fallback to 'simple' but keep lexemes.
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tsv ON bible_passages USING GIN (tsv);
|
||||||
|
|
||||||
|
-- Vector index (choose nlist to match data size; we set after populating table)
|
||||||
|
-- First create a flat index for small data, or IVFFLAT for scale:
|
||||||
|
-- Requires ANALYZE beforehand and SET enable_seqscan=off for kNN plans.
|
||||||
|
```
|
||||||
|
|
||||||
|
After loading, build the IVFFLAT index (the table must be populated first):
|
||||||
|
```sql
|
||||||
|
-- Example: around 31k verses ⇒ nlist ~ 100–200 is reasonable; tune per EXPLAIN ANALYZE
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_vec_ivfflat
|
||||||
|
ON bible_passages USING ivfflat (embedding vector_cosine_ops)
|
||||||
|
WITH (lists = 200);
|
||||||
|
```
|
||||||
|
|
||||||
|
Trigger to keep `updated_at` fresh:
|
||||||
|
```sql
|
||||||
|
CREATE OR REPLACE FUNCTION touch_updated_at() RETURNS TRIGGER AS $$
|
||||||
|
BEGIN NEW.updated_at = now(); RETURN NEW; END; $$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
DROP TRIGGER IF EXISTS trg_bible_updated ON bible_passages;
|
||||||
|
CREATE TRIGGER trg_bible_updated BEFORE UPDATE ON bible_passages
|
||||||
|
FOR EACH ROW EXECUTE PROCEDURE touch_updated_at();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3) Parsing & Chunking strategy (large, high‑quality)
|
||||||
|
|
||||||
|
**Why verse‑level?** It’s the canonical granular unit for Bible QA.
|
||||||
|
**Context‑stitching**: during retrieval, fetch neighbor verses (±N) to maintain narrative continuity.
|
||||||
|
**Normalization** steps (for `text_norm`):
|
||||||
|
- Strip verse numbers and sidenotes if present in raw lines.
|
||||||
|
- Collapse whitespace, unify quotes, remove page headers/footers and TOC artifacts.
|
||||||
|
- Preserve punctuation; avoid stemming before embeddings.
|
||||||
|
- Lowercasing optional (OpenAI embeddings are case-robust).
|
||||||
|
|
||||||
|
**Testament/book detection**: From headings and TOC present in the Markdown; detect Book → Chapter → Verse boundaries via regex.
|
||||||
|
Example regex heuristics (tune to your file):
|
||||||
|
- Book headers: `^(?P<book>[A-ZĂÂÎȘȚ].+?)\s*$` (bounded by known canon order)
|
||||||
|
- Chapter headers: `^Capitolul\s+(?P<ch>\d+)` or `^CApitoLuL\s+(?P<ch>\d+)` (case variations)
|
||||||
|
- Verse lines: `^(?P<verse>\d+)\s+(.+)$`
|
||||||
|
|
||||||
|
> The provided Markdown clearly shows book order (e.g., *Geneza*, *Exodul*, …; NT: *Matei*, *Marcu*, …) and verse lines like “**1** LA început…”. fileciteturn0file0
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4) Python ingestion script
|
||||||
|
|
||||||
|
> **Save as** `ingest_bible_pgvector.py`
|
||||||
|
|
||||||
|
```python
|
||||||
|
import os, re, json, math, time, asyncio
|
||||||
|
from typing import List, Dict, Tuple, Iterable
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import httpx
|
||||||
|
import psycopg
|
||||||
|
from psycopg.rows import dict_row
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
AZ_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT", "").rstrip("/")
|
||||||
|
AZ_API_KEY = os.getenv("AZURE_OPENAI_API_KEY")
|
||||||
|
AZ_API_VER = os.getenv("AZURE_OPENAI_API_VERSION", "2024-05-01-preview")
|
||||||
|
AZ_DEPLOYMENT = os.getenv("AZURE_OPENAI_EMBED_DEPLOYMENT", "embeddings")
|
||||||
|
EMBED_DIMS = int(os.getenv("EMBED_DIMS", "3072"))
|
||||||
|
DB_URL = os.getenv("DATABASE_URL")
|
||||||
|
BIBLE_MD_PATH = os.getenv("BIBLE_MD_PATH")
|
||||||
|
LANG_CODE = os.getenv("LANG_CODE", "ro")
|
||||||
|
TRANSLATION = os.getenv("TRANSLATION_CODE", "FIDELA")
|
||||||
|
|
||||||
|
assert AZ_ENDPOINT and AZ_API_KEY and DB_URL and BIBLE_MD_PATH, "Missing required env vars"
|
||||||
|
|
||||||
|
EMBED_URL = f"{AZ_ENDPOINT}/openai/deployments/{AZ_DEPLOYMENT}/embeddings?api-version={AZ_API_VER}"
|
||||||
|
|
||||||
|
BOOKS_OT = [
|
||||||
|
"Geneza","Exodul","Leviticul","Numeri","Deuteronom","Iosua","Judecători","Rut",
|
||||||
|
"1 Samuel","2 Samuel","1 Imparati","2 Imparati","1 Cronici","2 Cronici","Ezra","Neemia","Estera",
|
||||||
|
"Iov","Psalmii","Proverbe","Eclesiastul","Cântarea Cântărilor","Isaia","Ieremia","Plângerile",
|
||||||
|
"Ezechiel","Daniel","Osea","Ioel","Amos","Obadia","Iona","Mica","Naum","Habacuc","Țefania","Hagai","Zaharia","Maleahi"
|
||||||
|
]
|
||||||
|
BOOKS_NT = [
|
||||||
|
"Matei","Marcu","Luca","Ioan","Faptele Apostolilor","Romani","1 Corinteni","2 Corinteni",
|
||||||
|
"Galateni","Efeseni","Filipeni","Coloseni","1 Tesaloniceni","2 Tesaloniceni","1 Timotei","2 Timotei",
|
||||||
|
"Titus","Filimon","Evrei","Iacov","1 Petru","2 Petru","1 Ioan","2 Ioan","3 Ioan","Iuda","Revelaţia"
|
||||||
|
]
|
||||||
|
|
||||||
|
BOOK_CANON = {b:("OT" if b in BOOKS_OT else "NT") for b in BOOKS_OT + BOOKS_NT}
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Verse:
|
||||||
|
testament: str
|
||||||
|
book: str
|
||||||
|
chapter: int
|
||||||
|
verse: int
|
||||||
|
text_raw: str
|
||||||
|
text_norm: str
|
||||||
|
|
||||||
|
def normalize_text(s: str) -> str:
|
||||||
|
s = re.sub(r"\s+", " ", s.strip())
|
||||||
|
s = s.replace(" ", " ")
|
||||||
|
return s
|
||||||
|
|
||||||
|
BOOK_RE = re.compile(r"^(?P<book>[A-ZĂÂÎȘȚ][^\n]+?)\s*$")
|
||||||
|
CH_RE = re.compile(r"^(?i:Capitolul|CApitoLuL)\s+(?P<ch>\d+)\b")
|
||||||
|
VERSE_RE = re.compile(r"^(?P<v>\d+)\s+(?P<body>.+)$")
|
||||||
|
|
||||||
|
def parse_bible_md(md_text: str):
|
||||||
|
cur_book, cur_ch = None, None
|
||||||
|
testament = None
|
||||||
|
for line in md_text.splitlines():
|
||||||
|
line = line.rstrip()
|
||||||
|
|
||||||
|
# Book detection
|
||||||
|
m_book = BOOK_RE.match(line)
|
||||||
|
if m_book:
|
||||||
|
bname = m_book.group("book").strip()
|
||||||
|
if bname in BOOK_CANON:
|
||||||
|
cur_book = bname
|
||||||
|
testament = BOOK_CANON[bname]
|
||||||
|
cur_ch = None
|
||||||
|
continue
|
||||||
|
|
||||||
|
m_ch = CH_RE.match(line)
|
||||||
|
if m_ch and cur_book:
|
||||||
|
cur_ch = int(m_ch.group("ch"))
|
||||||
|
continue
|
||||||
|
|
||||||
|
m_v = VERSE_RE.match(line)
|
||||||
|
if m_v and cur_book and cur_ch:
|
||||||
|
vnum = int(m_v.group("v"))
|
||||||
|
body = m_v.group("body").strip()
|
||||||
|
raw = body
|
||||||
|
norm = normalize_text(body)
|
||||||
|
yield {
|
||||||
|
"testament": testament, "book": cur_book, "chapter": cur_ch, "verse": vnum,
|
||||||
|
"text_raw": raw, "text_norm": norm
|
||||||
|
}
|
||||||
|
|
||||||
|
async def embed_batch(client, inputs):
|
||||||
|
payload = {"input": inputs}
|
||||||
|
headers = {"api-key": AZ_API_KEY, "Content-Type": "application/json"}
|
||||||
|
for attempt in range(6):
|
||||||
|
try:
|
||||||
|
r = await client.post(EMBED_URL, headers=headers, json=payload, timeout=60)
|
||||||
|
if r.status_code == 200:
|
||||||
|
data = r.json()
|
||||||
|
ordered = sorted(data["data"], key=lambda x: x["index"])
|
||||||
|
return [d["embedding"] for d in ordered]
|
||||||
|
elif r.status_code in (429, 500, 503):
|
||||||
|
backoff = 2 ** attempt + (0.1 * attempt)
|
||||||
|
await asyncio.sleep(backoff)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Embedding error {r.status_code}: {r.text}")
|
||||||
|
except Exception:
|
||||||
|
backoff = 2 ** attempt + (0.1 * attempt)
|
||||||
|
await asyncio.sleep(backoff)
|
||||||
|
raise RuntimeError("Failed to embed after retries")
|
||||||
|
|
||||||
|
UPSERT_SQL = """
|
||||||
|
INSERT INTO bible_passages (testament, book, chapter, verse, lang, translation, text_raw, text_norm, tsv, embedding)
|
||||||
|
VALUES (%(testament)s, %(book)s, %(chapter)s, %(verse)s, %(lang)s, %(translation)s, %(text_raw)s, %(text_norm)s,
|
||||||
|
to_tsvector(COALESCE(%(ts_lang)s,'simple')::regconfig, %(text_norm)s), %(embedding)s)
|
||||||
|
ON CONFLICT (translation, lang, book, chapter, verse) DO UPDATE
|
||||||
|
SET text_raw=EXCLUDED.text_raw,
|
||||||
|
text_norm=EXCLUDED.text_norm,
|
||||||
|
tsv=EXCLUDED.tsv,
|
||||||
|
embedding=EXCLUDED.embedding,
|
||||||
|
updated_at=now();
|
||||||
|
"""
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
md_text = Path(BIBLE_MD_PATH).read_text(encoding="utf-8", errors="ignore")
|
||||||
|
verses = list(parse_bible_md(md_text))
|
||||||
|
print(f"Parsed verses: {len(verses)}")
|
||||||
|
|
||||||
|
batch_size = 128
|
||||||
|
async with httpx.AsyncClient() as client, psycopg.connect(DB_URL, autocommit=False) as conn:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
for i in range(0, len(verses), batch_size):
|
||||||
|
batch = verses[i:i+batch_size]
|
||||||
|
inputs = [v["text_norm"] for v in batch]
|
||||||
|
embs = await embed_batch(client, inputs)
|
||||||
|
rows = []
|
||||||
|
for v, e in zip(batch, embs):
|
||||||
|
rows.append({
|
||||||
|
**v,
|
||||||
|
"lang": os.getenv("LANG_CODE","ro"),
|
||||||
|
"translation": os.getenv("TRANSLATION_CODE","FIDELA"),
|
||||||
|
"ts_lang": "romanian",
|
||||||
|
"embedding": e
|
||||||
|
})
|
||||||
|
cur.executemany(UPSERT_SQL, rows)
|
||||||
|
conn.commit()
|
||||||
|
print(f"Upserted {len(rows)} … {i+len(rows)}/{len(verses)}")
|
||||||
|
print("Done. Build IVFFLAT index after ANALYZE.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import asyncio
|
||||||
|
asyncio.run(main())
|
||||||
|
```
|
||||||
|
|
||||||
|
**Notes**
|
||||||
|
- If `romanian` text search config is unavailable, set `ts_lang='simple'`.
|
||||||
|
- For `embed-3-small`, set `EMBED_DIMS=1536` and change column type to `vector(1536)`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5) Post‑ingestion steps
|
||||||
|
|
||||||
|
```sql
|
||||||
|
VACUUM ANALYZE bible_passages;
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_vec_ivfflat
|
||||||
|
ON bible_passages USING ivfflat (embedding vector_cosine_ops)
|
||||||
|
WITH (lists = 200);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_book_ch ON bible_passages (book, chapter);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6) Retrieval patterns
|
||||||
|
|
||||||
|
### A) Pure vector kNN (cosine)
|
||||||
|
```sql
|
||||||
|
SELECT ref, book, chapter, verse, text_raw,
|
||||||
|
1 - (embedding <=> $1) AS cosine_sim
|
||||||
|
FROM bible_passages
|
||||||
|
ORDER BY embedding <=> $1
|
||||||
|
LIMIT $2;
|
||||||
|
```
|
||||||
|
|
||||||
|
### B) Hybrid lexical + vector (weighted)
|
||||||
|
```sql
|
||||||
|
WITH v AS (
|
||||||
|
SELECT id, 1 - (embedding <=> $1) AS vsim
|
||||||
|
FROM bible_passages
|
||||||
|
ORDER BY embedding <=> $1
|
||||||
|
LIMIT 100
|
||||||
|
),
|
||||||
|
l AS (
|
||||||
|
SELECT id, ts_rank(tsv, $2) AS lrank
|
||||||
|
FROM bible_passages
|
||||||
|
WHERE tsv @@ $2
|
||||||
|
)
|
||||||
|
SELECT bp.ref, bp.book, bp.chapter, bp.verse, bp.text_raw,
|
||||||
|
COALESCE(v.vsim, 0) * 0.7 + COALESCE(l.lrank, 0) * 0.3 AS score
|
||||||
|
FROM bible_passages bp
|
||||||
|
LEFT JOIN v ON v.id = bp.id
|
||||||
|
LEFT JOIN l ON l.id = bp.id
|
||||||
|
ORDER BY score DESC
|
||||||
|
LIMIT 20;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7) Chat & Prayer agent tips
|
||||||
|
|
||||||
|
- **Answer grounding**: always cite `ref` (e.g., *Ioan 3:16*).
|
||||||
|
- **Multilingual output**: keep quotes in Romanian; explain in the user’s language.
|
||||||
|
- **Prayer agent**: constrain tone & doctrine; inject retrieved verses as anchors.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8) Ops
|
||||||
|
|
||||||
|
- Idempotent `UPSERT`.
|
||||||
|
- Backoff on 429/5xx.
|
||||||
|
- Consider keeping both `embed-3-large` and `-small` columns when migrating.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9) License & attribution
|
||||||
|
|
||||||
|
This guide references the structure of *Biblia Fidela* Markdown for ingestion demonstration. fileciteturn0file0
|
||||||
1482
temp/bible-chat-implementation-plan.md
Normal file
1482
temp/bible-chat-implementation-plan.md
Normal file
File diff suppressed because it is too large
Load Diff
304
temp/biblical-guide-homepage.md
Normal file
304
temp/biblical-guide-homepage.md
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
# BiblicalGuide Homepage Sections
|
||||||
|
|
||||||
|
## Current Sections ✓
|
||||||
|
1. Hero/CTA (Read Bible & AI Chat)
|
||||||
|
2. Features Overview
|
||||||
|
3. Basic Stats
|
||||||
|
|
||||||
|
## Recommended Additional Sections (In Order)
|
||||||
|
|
||||||
|
### 1. **Hero Section Enhancement** (Update Current)
|
||||||
|
```
|
||||||
|
Headline: "Your Personal Biblical Guide"
|
||||||
|
Subheadline: "Explore Scripture with AI-Powered Insights in [Language]"
|
||||||
|
|
||||||
|
[Start Reading] [Chat with AI Guide]
|
||||||
|
|
||||||
|
Live Counter: "Join 2,847 believers studying God's word right now"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. **Interactive Demo Section** 🌟
|
||||||
|
```
|
||||||
|
Title: "See It In Action"
|
||||||
|
|
||||||
|
[Live Chat Widget Preview]
|
||||||
|
User: "What does the Bible say about hope?"
|
||||||
|
AI: "The Bible offers many encouraging verses about hope..."
|
||||||
|
|
||||||
|
[Try It Yourself - No Sign Up Required]
|
||||||
|
```
|
||||||
|
**Why:** Reduce friction - let users experience the AI immediately without commitment
|
||||||
|
|
||||||
|
### 3. **Daily Verse Section** 📖
|
||||||
|
```
|
||||||
|
Today's Verse - January 15, 2024
|
||||||
|
|
||||||
|
"For I know the plans I have for you," declares the Lord,
|
||||||
|
"plans to prosper you and not to harm you,
|
||||||
|
plans to give you hope and a future."
|
||||||
|
- Jeremiah 29:11
|
||||||
|
|
||||||
|
[💬 Discuss This Verse] [🔖 Save] [📤 Share]
|
||||||
|
|
||||||
|
Tomorrow: Get daily verses delivered to your inbox [Subscribe]
|
||||||
|
```
|
||||||
|
**Why:** Gives immediate value and a reason to return daily
|
||||||
|
|
||||||
|
### 4. **Popular Questions Carousel** 💭
|
||||||
|
```
|
||||||
|
What Others Are Asking
|
||||||
|
|
||||||
|
[< ] "What does the Bible say about anxiety?"
|
||||||
|
"Understanding God's plan for my life"
|
||||||
|
"How to pray effectively"
|
||||||
|
"Finding peace in difficult times" [ >]
|
||||||
|
|
||||||
|
[Ask Your Own Question →]
|
||||||
|
```
|
||||||
|
**Why:** Shows real use cases and inspires engagement
|
||||||
|
|
||||||
|
### 5. **How It Works** (3 Steps) 🎯
|
||||||
|
```
|
||||||
|
Start Your Biblical Journey
|
||||||
|
|
||||||
|
1. Ask Any Question
|
||||||
|
Type or speak your spiritual questions
|
||||||
|
[Icon: Chat bubble]
|
||||||
|
|
||||||
|
2. Get Biblical Answers
|
||||||
|
Receive verses and insights instantly
|
||||||
|
[Icon: Book with sparkle]
|
||||||
|
|
||||||
|
3. Grow in Faith
|
||||||
|
Save insights, track your journey
|
||||||
|
[Icon: Growth chart]
|
||||||
|
|
||||||
|
[Get Started Free →]
|
||||||
|
```
|
||||||
|
**Why:** Reduces complexity anxiety for non-tech users
|
||||||
|
|
||||||
|
### 6. **Community Prayer Wall** (Live) 🙏
|
||||||
|
```
|
||||||
|
Prayer Requests From Our Community
|
||||||
|
|
||||||
|
"Please pray for my mother's health..." - 2 min ago
|
||||||
|
[🙏 32 Praying]
|
||||||
|
|
||||||
|
"Seeking guidance for my job interview..." - 15 min ago
|
||||||
|
[🙏 47 Praying]
|
||||||
|
|
||||||
|
"Thankful for answered prayers!" - 1 hour ago
|
||||||
|
[❤️ 89 Celebrating]
|
||||||
|
|
||||||
|
[Share Your Prayer Request] [View All Prayers]
|
||||||
|
```
|
||||||
|
**Why:** Creates immediate sense of community and belonging
|
||||||
|
|
||||||
|
### 7. **Trust Indicators Section** ✅
|
||||||
|
```
|
||||||
|
Trusted by Believers Worldwide
|
||||||
|
|
||||||
|
✓ Theologically Verified
|
||||||
|
Reviewed by seminary professors and pastors
|
||||||
|
|
||||||
|
✓ 100% Private & Secure
|
||||||
|
Your spiritual journey stays between you and God
|
||||||
|
|
||||||
|
✓ Always Free Core Features
|
||||||
|
Essential tools available to everyone
|
||||||
|
|
||||||
|
✓ Multi-Language Support
|
||||||
|
Available in 25+ languages
|
||||||
|
|
||||||
|
[Logos of: Christianity Today | Bible Society | Local Churches]
|
||||||
|
```
|
||||||
|
**Why:** Builds credibility, especially important for faith-based apps
|
||||||
|
|
||||||
|
### 8. **Use Cases / Who It's For** 👥
|
||||||
|
```
|
||||||
|
Perfect For Every Believer
|
||||||
|
|
||||||
|
[Tab: New Christians]
|
||||||
|
Start your faith journey with gentle guidance
|
||||||
|
- Basic Bible navigation
|
||||||
|
- Simple explanations
|
||||||
|
- Foundational topics
|
||||||
|
|
||||||
|
[Tab: Bible Students]
|
||||||
|
Deep dive into Scripture
|
||||||
|
- Original language insights
|
||||||
|
- Historical context
|
||||||
|
- Cross-references
|
||||||
|
|
||||||
|
[Tab: Parents & Teachers]
|
||||||
|
Share faith with the next generation
|
||||||
|
- Age-appropriate answers
|
||||||
|
- Discussion guides
|
||||||
|
- Family devotionals
|
||||||
|
|
||||||
|
[Tab: Pastors & Leaders]
|
||||||
|
Enhance your ministry
|
||||||
|
- Sermon preparation
|
||||||
|
- Counseling support
|
||||||
|
- Quick references
|
||||||
|
```
|
||||||
|
**Why:** Helps visitors self-identify and see personalized value
|
||||||
|
|
||||||
|
### 9. **Testimonials with Context** 💬
|
||||||
|
```
|
||||||
|
Real Stories from Our Community
|
||||||
|
|
||||||
|
"As a new mom with little time, the AI chat helps me stay
|
||||||
|
connected to God's word during 3am feedings."
|
||||||
|
- Sarah M., Mother of Two | Using for 3 months
|
||||||
|
|
||||||
|
"I was skeptical about AI and faith, but the Biblical accuracy
|
||||||
|
and thoughtful responses exceeded my expectations."
|
||||||
|
- Pastor David K., Baptist Church | Verified Minister
|
||||||
|
|
||||||
|
"Finally, a Bible app that speaks my language - literally!
|
||||||
|
The Portuguese support is perfect."
|
||||||
|
- João S., Brazil | International User
|
||||||
|
|
||||||
|
[Share Your Story]
|
||||||
|
```
|
||||||
|
**Why:** Social proof with relatable contexts
|
||||||
|
|
||||||
|
### 10. **FAQ Section** (Expandable) ❓
|
||||||
|
```
|
||||||
|
Common Questions
|
||||||
|
|
||||||
|
▼ Is the AI theologically accurate?
|
||||||
|
▼ Is it really free?
|
||||||
|
▼ What languages are supported?
|
||||||
|
▼ Can I use it offline?
|
||||||
|
▼ Is my data private?
|
||||||
|
▼ What Bible versions are available?
|
||||||
|
|
||||||
|
[Contact Support] [View All FAQs]
|
||||||
|
```
|
||||||
|
**Why:** Addresses objections before they become barriers
|
||||||
|
|
||||||
|
### 11. **Mobile App CTA** (If Applicable) 📱
|
||||||
|
```
|
||||||
|
Take Your Faith Everywhere
|
||||||
|
|
||||||
|
[App Store] [Google Play]
|
||||||
|
|
||||||
|
⭐⭐⭐⭐⭐ 4.8 rating | 10K+ downloads
|
||||||
|
|
||||||
|
QR Code: [Scan to Download]
|
||||||
|
```
|
||||||
|
**Why:** Many users prefer apps for daily spiritual practices
|
||||||
|
|
||||||
|
### 12. **Footer Enhancement** (Update Current)
|
||||||
|
```
|
||||||
|
Newsletter Signup:
|
||||||
|
"Daily Wisdom in Your Inbox"
|
||||||
|
[Email] [Subscribe]
|
||||||
|
|
||||||
|
Quick Links:
|
||||||
|
About | Blog | Support | API Docs
|
||||||
|
|
||||||
|
Legal:
|
||||||
|
Terms | Privacy | Cookie Policy | GDPR
|
||||||
|
|
||||||
|
Languages: [EN] [ES] [PT] [FR] [DE] [+20 more]
|
||||||
|
|
||||||
|
Social: [Facebook] [Instagram] [YouTube] [Twitter]
|
||||||
|
|
||||||
|
© 2024 BiblicalGuide - Made with ❤️ and 🙏
|
||||||
|
```
|
||||||
|
|
||||||
|
## Optional Advanced Sections
|
||||||
|
|
||||||
|
### **Interactive Bible Map** 🗺️
|
||||||
|
- Visual journey through Biblical locations
|
||||||
|
- "Explore where Jesus walked"
|
||||||
|
- Great for engagement but development-heavy
|
||||||
|
|
||||||
|
### **Live Study Groups** 👥
|
||||||
|
- "3 groups studying Romans right now"
|
||||||
|
- "Join a study group" CTA
|
||||||
|
- Requires more complex infrastructure
|
||||||
|
|
||||||
|
### **Verse of the Day Widget**
|
||||||
|
- Embeddable widget code
|
||||||
|
- "Add to your website"
|
||||||
|
- Good for viral growth
|
||||||
|
|
||||||
|
## Homepage Section Priority
|
||||||
|
|
||||||
|
### Must Have (Launch):
|
||||||
|
1. Enhanced Hero
|
||||||
|
2. Interactive Demo
|
||||||
|
3. How It Works
|
||||||
|
4. Trust Indicators
|
||||||
|
5. Enhanced Footer
|
||||||
|
|
||||||
|
### Should Have (Week 2):
|
||||||
|
6. Daily Verse
|
||||||
|
7. Popular Questions
|
||||||
|
8. Community Prayer Wall
|
||||||
|
9. FAQ
|
||||||
|
|
||||||
|
### Nice to Have (Month 2):
|
||||||
|
10. Use Cases
|
||||||
|
11. Testimonials
|
||||||
|
12. Mobile App CTA
|
||||||
|
|
||||||
|
## Design Principles
|
||||||
|
|
||||||
|
### Above the Fold:
|
||||||
|
- **Hero with clear value prop**
|
||||||
|
- **Two primary CTAs** (Read & Chat)
|
||||||
|
- **Trust indicator** (user count or endorsement)
|
||||||
|
- **Interactive demo** teaser
|
||||||
|
|
||||||
|
### Middle Sections:
|
||||||
|
- **Build trust** progressively
|
||||||
|
- **Show community** presence
|
||||||
|
- **Address objections** naturally
|
||||||
|
- **Provide value** immediately
|
||||||
|
|
||||||
|
### Bottom Sections:
|
||||||
|
- **Capture emails** for retention
|
||||||
|
- **Social proof** for hesitant users
|
||||||
|
- **Resources** for power users
|
||||||
|
- **Legal/trust** information
|
||||||
|
|
||||||
|
## A/B Testing Opportunities
|
||||||
|
|
||||||
|
1. **Hero Headlines**
|
||||||
|
- "Your Personal Biblical Guide"
|
||||||
|
- "Chat with Scripture"
|
||||||
|
- "AI-Powered Bible Study"
|
||||||
|
|
||||||
|
2. **Primary CTA**
|
||||||
|
- "Start Free"
|
||||||
|
- "Chat Now"
|
||||||
|
- "Explore Scripture"
|
||||||
|
|
||||||
|
3. **Demo Placement**
|
||||||
|
- Above fold vs below
|
||||||
|
- Auto-play vs click-to-start
|
||||||
|
|
||||||
|
4. **Social Proof Type**
|
||||||
|
- User count vs testimonials
|
||||||
|
- Ratings vs endorsements
|
||||||
|
|
||||||
|
## Mobile Considerations
|
||||||
|
|
||||||
|
- **Collapse sections** to accordions
|
||||||
|
- **Sticky CTA** at bottom
|
||||||
|
- **Swipeable** testimonials
|
||||||
|
- **Simplified** prayer wall
|
||||||
|
- **Touch-optimized** demo
|
||||||
|
|
||||||
|
## Performance Tips
|
||||||
|
|
||||||
|
- **Lazy load** below-fold sections
|
||||||
|
- **Static cache** daily verse
|
||||||
|
- **WebSocket** for live prayer wall
|
||||||
|
- **Skeleton screens** while loading
|
||||||
|
- **Progressive enhancement** for demo
|
||||||
438
temp/git-deployment-strategy.md
Normal file
438
temp/git-deployment-strategy.md
Normal file
@@ -0,0 +1,438 @@
|
|||||||
|
# Git-Based Production Deployment Strategy
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
This guide covers how to deploy the latest code from your git repository to production, ensuring your local development changes are properly deployed.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- Git repository (GitHub, GitLab, Bitbucket, or self-hosted)
|
||||||
|
- Production server with Docker and Git installed
|
||||||
|
- SSH access to production server
|
||||||
|
|
||||||
|
## Deployment Strategies
|
||||||
|
|
||||||
|
### Option 1: Manual Git Pull Deployment (Simple)
|
||||||
|
|
||||||
|
#### Setup on Production Server
|
||||||
|
```bash
|
||||||
|
# Clone the repository on production server
|
||||||
|
cd /opt
|
||||||
|
git clone https://github.com/yourusername/ghidul-biblic.git
|
||||||
|
cd ghidul-biblic
|
||||||
|
|
||||||
|
# Create production environment file
|
||||||
|
cp .env.example .env.production
|
||||||
|
# Edit .env.production with production values
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Create Deployment Script
|
||||||
|
Create `/opt/ghidul-biblic/deploy.sh`:
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "🚀 Starting deployment..."
|
||||||
|
|
||||||
|
# Navigate to project directory
|
||||||
|
cd /opt/ghidul-biblic
|
||||||
|
|
||||||
|
# Stop current services
|
||||||
|
echo "⏹️ Stopping current services..."
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml down
|
||||||
|
|
||||||
|
# Pull latest code
|
||||||
|
echo "📥 Pulling latest code..."
|
||||||
|
git pull origin main
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
|
export $(cat .env.production | xargs)
|
||||||
|
|
||||||
|
# Build and start services
|
||||||
|
echo "🔨 Building and starting services..."
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml up -d --build
|
||||||
|
|
||||||
|
# Wait for health check
|
||||||
|
echo "🏥 Waiting for health check..."
|
||||||
|
sleep 30
|
||||||
|
curl -f http://localhost:3010/api/health || {
|
||||||
|
echo "❌ Health check failed!"
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml logs app
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "✅ Deployment successful!"
|
||||||
|
echo "🌐 Application is running at http://localhost:3010"
|
||||||
|
```
|
||||||
|
|
||||||
|
Make it executable:
|
||||||
|
```bash
|
||||||
|
chmod +x /opt/ghidul-biblic/deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Deploy from Local Machine
|
||||||
|
```bash
|
||||||
|
# Push your changes to git
|
||||||
|
git add .
|
||||||
|
git commit -m "Your changes"
|
||||||
|
git push origin main
|
||||||
|
|
||||||
|
# SSH into production and deploy
|
||||||
|
ssh user@your-server "cd /opt/ghidul-biblic && ./deploy.sh"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 2: Webhook-Based Auto Deployment (Recommended)
|
||||||
|
|
||||||
|
#### Setup Webhook Server on Production
|
||||||
|
Create `/opt/ghidul-biblic/webhook-server.js`:
|
||||||
|
```javascript
|
||||||
|
const express = require('express');
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const PORT = 9000;
|
||||||
|
const SECRET = process.env.WEBHOOK_SECRET || 'your-webhook-secret';
|
||||||
|
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
function verifySignature(payload, signature) {
|
||||||
|
const hmac = crypto.createHmac('sha256', SECRET);
|
||||||
|
const digest = 'sha256=' + hmac.update(payload).digest('hex');
|
||||||
|
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
|
||||||
|
}
|
||||||
|
|
||||||
|
app.post('/webhook', (req, res) => {
|
||||||
|
const signature = req.headers['x-hub-signature-256'];
|
||||||
|
const payload = JSON.stringify(req.body);
|
||||||
|
|
||||||
|
if (!verifySignature(payload, signature)) {
|
||||||
|
return res.status(401).send('Unauthorized');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only deploy on push to main branch
|
||||||
|
if (req.body.ref === 'refs/heads/main') {
|
||||||
|
console.log('🚀 Webhook received, starting deployment...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
execSync('/opt/ghidul-biblic/deploy.sh', {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: '/opt/ghidul-biblic'
|
||||||
|
});
|
||||||
|
res.status(200).send('Deployment successful');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Deployment failed:', error);
|
||||||
|
res.status(500).send('Deployment failed');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(200).send('Not main branch, skipping deployment');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`Webhook server running on port ${PORT}`);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Setup Webhook Service
|
||||||
|
Create `/etc/systemd/system/ghidul-webhook.service`:
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=Ghidul Biblic Webhook Server
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/opt/ghidul-biblic
|
||||||
|
ExecStart=/usr/bin/node webhook-server.js
|
||||||
|
Restart=always
|
||||||
|
Environment=WEBHOOK_SECRET=your-webhook-secret-here
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable and start the service:
|
||||||
|
```bash
|
||||||
|
systemctl enable ghidul-webhook.service
|
||||||
|
systemctl start ghidul-webhook.service
|
||||||
|
systemctl status ghidul-webhook.service
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Configure Git Repository Webhook
|
||||||
|
**For GitHub:**
|
||||||
|
1. Go to your repository → Settings → Webhooks
|
||||||
|
2. Add webhook:
|
||||||
|
- URL: `http://your-server:9000/webhook`
|
||||||
|
- Content type: `application/json`
|
||||||
|
- Secret: `your-webhook-secret-here`
|
||||||
|
- Events: `Just the push event`
|
||||||
|
|
||||||
|
**For GitLab:**
|
||||||
|
1. Go to your project → Settings → Webhooks
|
||||||
|
2. Add webhook:
|
||||||
|
- URL: `http://your-server:9000/webhook`
|
||||||
|
- Secret token: `your-webhook-secret-here`
|
||||||
|
- Trigger: `Push events`
|
||||||
|
|
||||||
|
### Option 3: GitHub Actions CI/CD (Advanced)
|
||||||
|
|
||||||
|
#### Create GitHub Actions Workflow
|
||||||
|
Create `.github/workflows/deploy.yml`:
|
||||||
|
```yaml
|
||||||
|
name: Deploy to Production
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Deploy to server
|
||||||
|
uses: appleboy/ssh-action@v0.1.5
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.HOST }}
|
||||||
|
username: ${{ secrets.USERNAME }}
|
||||||
|
key: ${{ secrets.SSH_KEY }}
|
||||||
|
script: |
|
||||||
|
cd /opt/ghidul-biblic
|
||||||
|
./deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Setup GitHub Secrets
|
||||||
|
In your GitHub repository, go to Settings → Secrets and variables → Actions:
|
||||||
|
- `HOST`: Your production server IP
|
||||||
|
- `USERNAME`: SSH username
|
||||||
|
- `SSH_KEY`: Private SSH key content
|
||||||
|
|
||||||
|
### Option 4: Docker Hub Auto-Build (Professional)
|
||||||
|
|
||||||
|
#### Setup Dockerfile for Production
|
||||||
|
Ensure your `docker/Dockerfile.prod` is optimized:
|
||||||
|
```dockerfile
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci --only=production && npm cache clean --force
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Generate Prisma client
|
||||||
|
RUN npx prisma generate
|
||||||
|
|
||||||
|
# Build application
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:20-alpine AS runner
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV NODE_ENV production
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
RUN addgroup -g 1001 -S nodejs
|
||||||
|
RUN adduser -S nextjs -u 1001
|
||||||
|
|
||||||
|
# Copy built application
|
||||||
|
COPY --from=builder /app/public ./public
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
|
COPY --from=builder /app/prisma ./prisma
|
||||||
|
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
|
||||||
|
COPY --from=builder /app/package.json ./package.json
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
ENV PORT 3000
|
||||||
|
ENV HOSTNAME "0.0.0.0"
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Create Docker Compose for Auto-Pull
|
||||||
|
Create `docker-compose.prod.autopull.yml`:
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: pgvector/pgvector:pg16
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: bible_chat
|
||||||
|
POSTGRES_USER: bible_admin
|
||||||
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
networks:
|
||||||
|
- bible_network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U bible_admin -d bible_chat"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
app:
|
||||||
|
image: yourdockerhub/ghidul-biblic:latest
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "3010:3000"
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://bible_admin:${DB_PASSWORD}@postgres:5432/bible_chat
|
||||||
|
AZURE_OPENAI_KEY: ${AZURE_OPENAI_KEY}
|
||||||
|
AZURE_OPENAI_ENDPOINT: ${AZURE_OPENAI_ENDPOINT}
|
||||||
|
AZURE_OPENAI_DEPLOYMENT: ${AZURE_OPENAI_DEPLOYMENT}
|
||||||
|
OLLAMA_API_URL: ${OLLAMA_API_URL}
|
||||||
|
JWT_SECRET: ${JWT_SECRET}
|
||||||
|
NEXTAUTH_URL: ${NEXTAUTH_URL}
|
||||||
|
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
|
||||||
|
NODE_ENV: production
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- bible_network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -f http://localhost:3000/api/health || exit 1"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
watchtower:
|
||||||
|
image: containrrr/watchtower
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
command: --interval 300 --cleanup app
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
networks:
|
||||||
|
bible_network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
```
|
||||||
|
|
||||||
|
## Recommended Workflow
|
||||||
|
|
||||||
|
### For Development
|
||||||
|
1. **Local Development**:
|
||||||
|
```bash
|
||||||
|
# Work on your local machine
|
||||||
|
npm run dev
|
||||||
|
# Make changes, test locally
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Commit and Push**:
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
git commit -m "Feature: Add new functionality"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Automatic Deployment**:
|
||||||
|
- Webhook triggers deployment
|
||||||
|
- Or manual trigger: `ssh user@server "/opt/ghidul-biblic/deploy.sh"`
|
||||||
|
|
||||||
|
### For Production Server Setup
|
||||||
|
1. **Initial Setup**:
|
||||||
|
```bash
|
||||||
|
# Clone repository
|
||||||
|
git clone https://github.com/yourusername/ghidul-biblic.git /opt/ghidul-biblic
|
||||||
|
cd /opt/ghidul-biblic
|
||||||
|
|
||||||
|
# Setup environment
|
||||||
|
cp .env.example .env.production
|
||||||
|
# Edit .env.production
|
||||||
|
|
||||||
|
# Make deployment script executable
|
||||||
|
chmod +x deploy.sh
|
||||||
|
|
||||||
|
# Setup webhook (optional)
|
||||||
|
npm install express
|
||||||
|
# Setup systemd service
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Deploy**:
|
||||||
|
```bash
|
||||||
|
./deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### Git Repository
|
||||||
|
- Use private repositories for production code
|
||||||
|
- Use deploy keys or personal access tokens
|
||||||
|
- Never commit sensitive environment variables
|
||||||
|
|
||||||
|
### Production Server
|
||||||
|
- Use non-root user for deployment when possible
|
||||||
|
- Secure webhook endpoints with proper secrets
|
||||||
|
- Use SSH key authentication
|
||||||
|
- Keep server updated
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
```bash
|
||||||
|
# .env.production should never be in git
|
||||||
|
echo ".env.production" >> .gitignore
|
||||||
|
echo ".env.local" >> .gitignore
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring Deployment
|
||||||
|
|
||||||
|
### Create Health Check Script
|
||||||
|
Create `/opt/ghidul-biblic/health-check.sh`:
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
HEALTH_URL="http://localhost:3010/api/health"
|
||||||
|
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL)
|
||||||
|
|
||||||
|
if [ $RESPONSE -eq 200 ]; then
|
||||||
|
echo "✅ Application is healthy"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "❌ Application is unhealthy (HTTP $RESPONSE)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setup Cron for Health Monitoring
|
||||||
|
```bash
|
||||||
|
# Add to crontab
|
||||||
|
*/5 * * * * /opt/ghidul-biblic/health-check.sh >> /var/log/ghidul-health.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
1. **Git pull fails**: Check SSH keys and repository access
|
||||||
|
2. **Docker build fails**: Check Dockerfile and dependencies
|
||||||
|
3. **Health check fails**: Check application logs
|
||||||
|
4. **Webhook not triggered**: Verify webhook URL and secret
|
||||||
|
|
||||||
|
### Useful Commands
|
||||||
|
```bash
|
||||||
|
# Check deployment logs
|
||||||
|
tail -f /var/log/ghidul-deployment.log
|
||||||
|
|
||||||
|
# Check application logs
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml logs -f app
|
||||||
|
|
||||||
|
# Manual health check
|
||||||
|
curl http://localhost:3010/api/health
|
||||||
|
|
||||||
|
# Restart services
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml restart app
|
||||||
|
```
|
||||||
|
|
||||||
|
This setup ensures your production environment always has the latest code from your git repository while maintaining proper deployment practices.
|
||||||
212
temp/multi-language-implementation-plan.md
Normal file
212
temp/multi-language-implementation-plan.md
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
# Multi-Language Support Implementation Plan
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
Add comprehensive multi-language support to the Ghid Biblic application, starting with English as the second language alongside Romanian.
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
- **Database**: Already supports multiple languages (`lang` field) and translations (`translation` field)
|
||||||
|
- **Frontend**: Hardcoded Romanian interface
|
||||||
|
- **Vector Search**: Romanian-only search logic
|
||||||
|
- **Bible Data**: Only Romanian (FIDELA) version imported
|
||||||
|
|
||||||
|
## Implementation Phases
|
||||||
|
|
||||||
|
### Phase 1: Core Infrastructure
|
||||||
|
1. **Install i18n Framework**
|
||||||
|
- Add `next-intl` for Next.js internationalization
|
||||||
|
- Configure locale routing (`/ro/`, `/en/`)
|
||||||
|
- Set up translation file structure
|
||||||
|
|
||||||
|
2. **Language Configuration**
|
||||||
|
- Create language detection and switching logic
|
||||||
|
- Add language persistence (localStorage/cookies)
|
||||||
|
- Configure default language fallbacks
|
||||||
|
|
||||||
|
3. **Translation Files Structure**
|
||||||
|
```
|
||||||
|
messages/
|
||||||
|
├── ro.json (Romanian - existing content)
|
||||||
|
├── en.json (English translations)
|
||||||
|
└── common.json (shared terms)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: UI Internationalization
|
||||||
|
1. **Navigation Component**
|
||||||
|
- Translate all menu items and labels
|
||||||
|
- Add language switcher dropdown
|
||||||
|
- Update routing for locale-aware navigation
|
||||||
|
|
||||||
|
2. **Chat Interface**
|
||||||
|
- Translate all UI text and prompts
|
||||||
|
- Add suggested questions per language
|
||||||
|
- Update loading states and error messages
|
||||||
|
|
||||||
|
3. **Page Content**
|
||||||
|
- Home page (`/` → `/[locale]/`)
|
||||||
|
- Bible browser (`/bible` → `/[locale]/bible`)
|
||||||
|
- Search page (`/search` → `/[locale]/search`)
|
||||||
|
- Prayer requests (`/prayers` → `/[locale]/prayers`)
|
||||||
|
|
||||||
|
### Phase 3: Backend Localization
|
||||||
|
1. **Vector Search Updates**
|
||||||
|
- Modify search functions to filter by language
|
||||||
|
- Add language parameter to search APIs
|
||||||
|
- Update hybrid search for language-specific full-text search
|
||||||
|
|
||||||
|
2. **Chat API Enhancement**
|
||||||
|
- Language-aware Bible verse retrieval
|
||||||
|
- Localized AI response prompts
|
||||||
|
- Language-specific fallback responses
|
||||||
|
|
||||||
|
3. **API Route Updates**
|
||||||
|
- Add locale parameter to all API endpoints
|
||||||
|
- Update error responses for each language
|
||||||
|
- Configure language-specific search configurations
|
||||||
|
|
||||||
|
### Phase 4: Bible Data Management
|
||||||
|
1. **English Bible Import**
|
||||||
|
- Source: API.Bible or public domain English Bible (KJV/ESV)
|
||||||
|
- Adapt existing import script for English
|
||||||
|
- Generate English embeddings using Azure OpenAI
|
||||||
|
|
||||||
|
2. **Language-Aware Bible Browser**
|
||||||
|
- Add language selector in Bible interface
|
||||||
|
- Filter books/chapters/verses by selected language
|
||||||
|
- Show parallel verses when both languages available
|
||||||
|
|
||||||
|
### Phase 5: Enhanced Features
|
||||||
|
1. **Parallel Bible View**
|
||||||
|
- Side-by-side Romanian/English verse display
|
||||||
|
- Cross-reference linking between translations
|
||||||
|
- Language comparison in search results
|
||||||
|
|
||||||
|
2. **Smart Language Detection**
|
||||||
|
- Auto-detect query language in chat
|
||||||
|
- Suggest language switch based on user input
|
||||||
|
- Mixed-language search capabilities
|
||||||
|
|
||||||
|
3. **Advanced Search Features**
|
||||||
|
- Cross-language semantic search
|
||||||
|
- Translation comparison tools
|
||||||
|
- Language-specific biblical term glossaries
|
||||||
|
|
||||||
|
## Technical Implementation Details
|
||||||
|
|
||||||
|
### Routing Structure
|
||||||
|
```
|
||||||
|
Current: /page
|
||||||
|
New: /[locale]/page
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- /ro/biblia (Romanian Bible)
|
||||||
|
- /en/bible (English Bible)
|
||||||
|
- /ro/rugaciuni (Romanian Prayers)
|
||||||
|
- /en/prayers (English Prayers)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Schema Changes
|
||||||
|
**No changes needed** - current schema already supports:
|
||||||
|
- Multiple languages via `lang` field
|
||||||
|
- Multiple translations via `translation` field
|
||||||
|
- Unique constraints per translation/language
|
||||||
|
|
||||||
|
### Vector Search Updates
|
||||||
|
```typescript
|
||||||
|
// Current
|
||||||
|
searchBibleHybrid(query: string, limit: number)
|
||||||
|
|
||||||
|
// Enhanced
|
||||||
|
searchBibleHybrid(query: string, language: string, limit: number)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Translation File Structure
|
||||||
|
```json
|
||||||
|
// messages/en.json
|
||||||
|
{
|
||||||
|
"navigation": {
|
||||||
|
"home": "Home",
|
||||||
|
"bible": "Bible",
|
||||||
|
"prayers": "Prayers",
|
||||||
|
"search": "Search"
|
||||||
|
},
|
||||||
|
"chat": {
|
||||||
|
"placeholder": "Ask your biblical question...",
|
||||||
|
"suggestions": [
|
||||||
|
"What does the Bible say about love?",
|
||||||
|
"Explain the parable of the sower",
|
||||||
|
"What are the fruits of the Spirit?"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Language Switcher Component
|
||||||
|
- Dropdown in navigation header
|
||||||
|
- Flag icons for visual identification
|
||||||
|
- Persist language choice across sessions
|
||||||
|
- Redirect to equivalent page in new language
|
||||||
|
|
||||||
|
## Dependencies to Add
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"next-intl": "^3.x",
|
||||||
|
"@formatjs/intl-localematcher": "^0.x",
|
||||||
|
"negotiator": "^0.x"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure Changes
|
||||||
|
```
|
||||||
|
app/
|
||||||
|
├── [locale]/
|
||||||
|
│ ├── page.tsx
|
||||||
|
│ ├── bible/
|
||||||
|
│ ├── prayers/
|
||||||
|
│ ├── search/
|
||||||
|
│ └── layout.tsx
|
||||||
|
├── api/ (unchanged)
|
||||||
|
└── globals.css
|
||||||
|
|
||||||
|
messages/
|
||||||
|
├── en.json
|
||||||
|
├── ro.json
|
||||||
|
└── index.ts
|
||||||
|
|
||||||
|
components/
|
||||||
|
├── language-switcher.tsx
|
||||||
|
├── navigation.tsx (updated)
|
||||||
|
└── chat/ (updated)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
1. **Unit Tests**: Translation loading and language switching
|
||||||
|
2. **Integration Tests**: API endpoints with locale parameters
|
||||||
|
3. **E2E Tests**: Complete user flows in both languages
|
||||||
|
4. **Performance Tests**: Vector search with language filtering
|
||||||
|
|
||||||
|
## Rollout Plan
|
||||||
|
1. **Development**: Implement Phase 1-3 (core infrastructure and UI)
|
||||||
|
2. **Testing**: Deploy to staging with Romanian/English support
|
||||||
|
3. **Beta Release**: Limited user testing with feedback collection
|
||||||
|
4. **Production**: Full release with both languages
|
||||||
|
5. **Future**: Add additional languages based on user demand
|
||||||
|
|
||||||
|
## Estimated Timeline
|
||||||
|
- **Phase 1-2**: 2-3 days (i18n setup and UI translation)
|
||||||
|
- **Phase 3**: 1-2 days (backend localization)
|
||||||
|
- **Phase 4**: 2-3 days (English Bible import and embeddings)
|
||||||
|
- **Phase 5**: 3-4 days (enhanced features)
|
||||||
|
- **Total**: 8-12 days for complete implementation
|
||||||
|
|
||||||
|
## Success Metrics
|
||||||
|
- Language switching works seamlessly
|
||||||
|
- Vector search returns accurate results in both languages
|
||||||
|
- AI chat responses are contextually appropriate per language
|
||||||
|
- User can browse Bible in preferred language
|
||||||
|
- Performance remains optimal with language filtering
|
||||||
|
|
||||||
|
## Future Considerations
|
||||||
|
- Spanish, French, German language support
|
||||||
|
- Regional dialect variations
|
||||||
|
- Audio Bible integration per language
|
||||||
|
- Collaborative translation features for community contributions
|
||||||
301
temp/production-deployment-plan.md
Normal file
301
temp/production-deployment-plan.md
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
# Biblical Guide - Production Deployment Plan
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
This guide covers deploying the Biblical Guide (ghidul-biblic) application in production mode without local nginx, assuming you'll use a separate nginx proxy manager server.
|
||||||
|
|
||||||
|
## Current Application Status
|
||||||
|
- ✅ Next.js 15.5.3 application
|
||||||
|
- ✅ Database configured and working
|
||||||
|
- ✅ Running on port 3010 in development
|
||||||
|
- ✅ Multi-language support (English/Romanian)
|
||||||
|
- ✅ Docker configuration ready
|
||||||
|
|
||||||
|
## Production Deployment Options
|
||||||
|
|
||||||
|
### Option 1: Docker Compose Production (Recommended)
|
||||||
|
|
||||||
|
#### Prerequisites
|
||||||
|
1. Docker and Docker Compose installed
|
||||||
|
2. Environment variables configured
|
||||||
|
3. External nginx proxy manager configured to route to your server
|
||||||
|
|
||||||
|
#### Step 1: Environment Configuration
|
||||||
|
Create production environment file:
|
||||||
|
```bash
|
||||||
|
cp .env.example .env.production
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `.env.production` with production values:
|
||||||
|
```bash
|
||||||
|
# Database - Use strong password in production
|
||||||
|
DATABASE_URL=postgresql://bible_admin:STRONG_PASSWORD_HERE@postgres:5432/bible_chat
|
||||||
|
DB_PASSWORD=STRONG_PASSWORD_HERE
|
||||||
|
|
||||||
|
# Authentication - Generate secure secrets
|
||||||
|
NEXTAUTH_URL=https://yourdomain.com
|
||||||
|
NEXTAUTH_SECRET=generate-long-random-secret-here
|
||||||
|
JWT_SECRET=another-long-random-secret
|
||||||
|
|
||||||
|
# Azure OpenAI (if using AI features)
|
||||||
|
AZURE_OPENAI_KEY=your-azure-key
|
||||||
|
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
|
||||||
|
AZURE_OPENAI_DEPLOYMENT=gpt-4
|
||||||
|
|
||||||
|
# Ollama (optional - if using local AI)
|
||||||
|
OLLAMA_API_URL=http://your-ollama-server:11434
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2: Create Production Docker Compose
|
||||||
|
Create `docker-compose.prod.simple.yml`:
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: pgvector/pgvector:pg16
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: bible_chat
|
||||||
|
POSTGRES_USER: bible_admin
|
||||||
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
networks:
|
||||||
|
- bible_network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U bible_admin -d bible_chat"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/Dockerfile.prod
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "3010:3000" # Expose on port 3010 for external proxy
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://bible_admin:${DB_PASSWORD}@postgres:5432/bible_chat
|
||||||
|
AZURE_OPENAI_KEY: ${AZURE_OPENAI_KEY}
|
||||||
|
AZURE_OPENAI_ENDPOINT: ${AZURE_OPENAI_ENDPOINT}
|
||||||
|
AZURE_OPENAI_DEPLOYMENT: ${AZURE_OPENAI_DEPLOYMENT}
|
||||||
|
OLLAMA_API_URL: ${OLLAMA_API_URL}
|
||||||
|
JWT_SECRET: ${JWT_SECRET}
|
||||||
|
NEXTAUTH_URL: ${NEXTAUTH_URL}
|
||||||
|
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
|
||||||
|
NODE_ENV: production
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- bible_network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -f http://localhost:3000/api/health || exit 1"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
networks:
|
||||||
|
bible_network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 3: Deploy to Production
|
||||||
|
```bash
|
||||||
|
# Stop development server first
|
||||||
|
pkill -f "next dev"
|
||||||
|
|
||||||
|
# Load production environment
|
||||||
|
export $(cat .env.production | xargs)
|
||||||
|
|
||||||
|
# Build and start production services
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml up -d --build
|
||||||
|
|
||||||
|
# Check status
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml ps
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml logs app
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 4: Configure External Nginx Proxy Manager
|
||||||
|
Point your nginx proxy manager to:
|
||||||
|
- **Target**: `http://your-server-ip:3010`
|
||||||
|
- **Health Check**: `http://your-server-ip:3010/api/health`
|
||||||
|
|
||||||
|
### Option 2: Direct Node.js Production (Alternative)
|
||||||
|
|
||||||
|
#### Step 1: Build the Application
|
||||||
|
```bash
|
||||||
|
# Install production dependencies
|
||||||
|
npm ci --only=production
|
||||||
|
|
||||||
|
# Generate Prisma client
|
||||||
|
npx prisma generate
|
||||||
|
|
||||||
|
# Build the application
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2: Start Production Server
|
||||||
|
```bash
|
||||||
|
# Set production environment
|
||||||
|
export NODE_ENV=production
|
||||||
|
export PORT=3010
|
||||||
|
export HOSTNAME=0.0.0.0
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
|
export $(cat .env.production | xargs)
|
||||||
|
|
||||||
|
# Start the production server
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 3: Process Management (Optional)
|
||||||
|
Use PM2 for process management:
|
||||||
|
```bash
|
||||||
|
# Install PM2
|
||||||
|
npm install -g pm2
|
||||||
|
|
||||||
|
# Create ecosystem file
|
||||||
|
cat > ecosystem.config.js << 'EOF'
|
||||||
|
module.exports = {
|
||||||
|
apps: [{
|
||||||
|
name: 'ghidul-biblic',
|
||||||
|
script: 'npm',
|
||||||
|
args: 'start',
|
||||||
|
cwd: '/root/ghidul-biblic',
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
PORT: 3010,
|
||||||
|
HOSTNAME: '0.0.0.0'
|
||||||
|
},
|
||||||
|
env_file: '.env.production'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Start with PM2
|
||||||
|
pm2 start ecosystem.config.js
|
||||||
|
pm2 save
|
||||||
|
pm2 startup
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Checklist
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- [ ] Strong database passwords set
|
||||||
|
- [ ] JWT secrets generated (min 32 characters)
|
||||||
|
- [ ] NEXTAUTH_SECRET generated
|
||||||
|
- [ ] Environment files secured (not in git)
|
||||||
|
- [ ] Database not exposed to public internet
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- [ ] Application built with `npm run build`
|
||||||
|
- [ ] Database optimized for production
|
||||||
|
- [ ] Proper caching headers configured in proxy
|
||||||
|
- [ ] Health checks configured
|
||||||
|
|
||||||
|
### Monitoring
|
||||||
|
- [ ] Health endpoint accessible: `/api/health`
|
||||||
|
- [ ] Database connection monitoring
|
||||||
|
- [ ] Application logs configured
|
||||||
|
- [ ] Error tracking setup
|
||||||
|
|
||||||
|
### External Services
|
||||||
|
- [ ] Azure OpenAI configured (if using AI features)
|
||||||
|
- [ ] Ollama server configured (if using local AI)
|
||||||
|
- [ ] External nginx proxy manager configured
|
||||||
|
|
||||||
|
## Nginx Proxy Manager Configuration
|
||||||
|
|
||||||
|
### Proxy Host Settings
|
||||||
|
- **Domain Names**: `yourdomain.com`
|
||||||
|
- **Scheme**: `http`
|
||||||
|
- **Forward Hostname/IP**: `your-server-ip`
|
||||||
|
- **Forward Port**: `3010`
|
||||||
|
- **Cache Assets**: `Yes`
|
||||||
|
- **Block Common Exploits**: `Yes`
|
||||||
|
- **Websockets Support**: `Yes`
|
||||||
|
|
||||||
|
### SSL Configuration
|
||||||
|
- Enable SSL with Let's Encrypt or your certificate
|
||||||
|
- Force SSL redirect
|
||||||
|
- HTTP/2 Support
|
||||||
|
|
||||||
|
### Custom Nginx Configuration (Advanced)
|
||||||
|
```nginx
|
||||||
|
# Add to Custom Nginx Configuration in Proxy Manager
|
||||||
|
location /api/health {
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /_next/static {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
client_max_body_size 10M;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
1. **Port conflicts**: Ensure port 3010 is available
|
||||||
|
2. **Database connection**: Check DATABASE_URL format
|
||||||
|
3. **Environment variables**: Verify all required vars are set
|
||||||
|
4. **Build errors**: Check Node.js version compatibility
|
||||||
|
|
||||||
|
### Health Check Commands
|
||||||
|
```bash
|
||||||
|
# Check application health
|
||||||
|
curl http://localhost:3010/api/health
|
||||||
|
|
||||||
|
# Check Docker services
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml ps
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml logs -f app
|
||||||
|
```
|
||||||
|
|
||||||
|
### Maintenance Commands
|
||||||
|
```bash
|
||||||
|
# Update application
|
||||||
|
git pull
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml up -d --build
|
||||||
|
|
||||||
|
# Database backup
|
||||||
|
docker-compose -f docker-compose.prod.simple.yml exec postgres pg_dump -U bible_admin bible_chat > backup.sql
|
||||||
|
|
||||||
|
# View resource usage
|
||||||
|
docker stats
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps After Deployment
|
||||||
|
|
||||||
|
1. **Configure DNS** to point to your server
|
||||||
|
2. **Setup SSL certificate** in nginx proxy manager
|
||||||
|
3. **Configure monitoring** and alerting
|
||||||
|
4. **Setup automated backups** for database
|
||||||
|
5. **Test all functionality** in production environment
|
||||||
|
6. **Setup log rotation** and monitoring
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### Database
|
||||||
|
- Regular VACUUM and ANALYZE
|
||||||
|
- Monitor slow queries
|
||||||
|
- Configure connection pooling if needed
|
||||||
|
|
||||||
|
### Application
|
||||||
|
- Monitor memory usage
|
||||||
|
- Setup proper logging levels
|
||||||
|
- Configure rate limiting in proxy if needed
|
||||||
|
|
||||||
|
### Caching
|
||||||
|
- Static assets cached by proxy
|
||||||
|
- API responses cached where appropriate
|
||||||
|
- Database query optimization
|
||||||
Reference in New Issue
Block a user