Website undangan pernikahan yang elegan, modern, dan interaktif dibangun menggunakan Astro, React, Tailwind CSS, dan SQLite. Dilengkapi dengan sistem manajemen tamu yang komprehensif, pelacakan RSVP real-time, notifikasi otomatis, dan tools desain profesional.
- Fitur Utama
- Struktur Proyek
- Konfigurasi
- Instalasi & Development
- Deployment Production
- Panduan Penggunaan
- Stack Teknologi
- Troubleshooting
- Lisensi
Amplop Digital
- Animasi pembuka undangan yang elegan
- Personalisasi otomatis nama tamu
- Transisi smooth dengan backdrop blur
- Floating petals animation
Mode Tema
- Light Mode dan Dark Mode
- Auto-detect preferensi sistem
- Smooth transition antar tema
- Persistent state menggunakan localStorage
Pemutar Musik
- Background music otomatis
- Kontrol play/pause terintegrasi
- Preload untuk performa optimal
- Format audio HTML5 native
Animasi & Efek Visual
- Scroll-triggered reveal animations
- Floating petals menggunakan CSS keyframes
- Subtle zoom pada hero image
- Intersection Observer untuk performa optimal
Countdown Timer
- Hitung mundur real-time ke hari H
- Format: Hari, Jam, Menit, Detik
- Auto-update setiap detik
- Styling responsive dengan frosted glass effect
Personalisasi Tamu
URL Format: /?to=Nama+Tamu
Efek:
- Nama muncul di amplop pembuka
- Nama muncul di hero section
- Form RSVP terisi otomatis (locked)
- Form wishes terisi otomatis (locked)
Sistem RSVP
-
Smart Update System:
- Cek nama tamu sebelum insert
- Update data jika nama sudah ada
- Mencegah duplikasi data
- Timestamp otomatis di-update
-
Form Features:
- Input nama, nomor HP/WA, dan pesan
- Radio button untuk status kehadiran (Hadir/Tidak Hadir/Ragu)
- Counter jumlah tamu dengan min/max validation
- Rate limiting berbasis IP (5 request per menit)
-
Dashboard Real-time:
- Total responden
- Jumlah yang hadir dengan total pax
- Jumlah yang ragu
- Jumlah yang tidak hadir
- List tamu terbaru dengan scroll area
Buku Tamu (Wishes)
- Input nama dan pesan ucapan
- Paginasi dengan navigasi elegan
- Desain card editorial style
- Smart update berdasarkan nama pengirim
- Rate limiting untuk spam protection
Integrasi Lokasi
- Embed Google Maps dengan custom styling
- Copy alamat ke clipboard
- Link langsung ke Google Maps navigation
- Koordinat lat/long yang akurat
Integrasi Kalender
- Add to Google Calendar
- Download file .ics (Apple Calendar, Outlook)
- Dropdown selector dengan animasi
- Include reminder 1 jam sebelum acara
Galeri Foto
- Masonry layout responsive (1-3 kolom)
- Lightbox fullscreen dengan backdrop blur
- Navigasi keyboard (Arrow Left/Right, Escape)
- Lazy loading untuk performa optimal
- Smooth zoom effect on hover
Informasi Kado
- Display nomor rekening multiple bank
- Copy to clipboard dengan konfirmasi visual
- Card desain dengan gradient effect
- Informasi alamat kirim kado fisik
Dynamic Configuration
// Semua data dari environment variables
// Parsing otomatis untuk tipe data kompleks
const parseJson = (jsonString, defaultValue) => {
try {
return JSON.parse(jsonString);
} catch (e) {
return defaultValue;
}
};Server-Side Rendering
- Astro Node Adapter mode standalone
- Pre-render static content
- Dynamic route untuk parameter tamu
- Optimal SEO dengan meta tags lengkap
Database SQLite
-- Tabel RSVP
CREATE TABLE rsvps (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guest_name TEXT NOT NULL,
phone TEXT,
attendance TEXT,
guest_count INTEGER,
message TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
-- Tabel Wishes
CREATE TABLE wishes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
message TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);PWA Support
- Service Worker untuk offline capability
- Manifest.json untuk installable app
- Cache strategy untuk gambar dan assets
- Install prompt untuk Android/iOS
Notifikasi Telegram
// Kirim notifikasi otomatis saat:
// 1. RSVP baru masuk
// 2. Update data RSVP
// 3. Ucapan baru dari buku tamu
// Format pesan dengan HTML parsing
// Timeout 5 detik untuk koneksi lambat
// Silent fail agar tidak mengganggu user experienceAutentikasi
- Cookie-based authentication
- Password dari environment variable
- Session management dengan expire time
- Logout dengan clear cookie
Dashboard Statistik
┌─────────────────────────────────────┐
│ Total Respon │ Hadir (+ Pax) │
│ Ragu │ Tidak Hadir │
└─────────────────────────────────────┘
Manajemen Data RSVP
- View: Tabel dengan sorting dan filtering
- Edit: Modal form untuk update data
- Delete: Single dan bulk delete dengan konfirmasi
- Search: Real-time filtering
- Pagination: Adjustable rows per page
- Export: Download CSV lengkap
Manajemen Ucapan
- View: Card layout dengan timestamp
- Edit: Modal form untuk moderasi
- Delete: Single dan bulk delete
- Search: Filter berdasarkan nama/pesan
- Pagination: Smooth navigation
- Export: Download CSV lengkap
Generator QR Code
Mode Single:
Input: Nama Tamu
Output:
- QR Code dengan logo premium (inisial mempelai)
- Preview real-time
- Download PNG high-quality
- Copy link ke clipboard
Mode Bulk:
Input: CSV File (Kolom 1: Nama Tamu)
Proses:
1. Upload CSV
2. Preview data (max 50 tampil, sisanya hidden)
3. Generate QR batch dengan progress bar
4. Download ZIP file
Features:
- Template CSV download
- Progress indicator dengan status
- Chunk processing (50 QR per batch)
- Premium logo integration
- File naming: {index}_{nama_tamu}.png
Designer Undangan PDF
Template Floral (4 Halaman A5):
Halaman 1: Cover
- Nama mempelai dengan font serif elegant
- Border ornamen bunga (vektor)
- Tanggal pernikahan
- Box personalisasi nama tamu
Halaman 2: Detail Mempelai
- Salam pembuka (Assalamualaikum)
- Quote Ar-Rum:21
- Nama lengkap + orang tua
- Instagram handle
Halaman 3: Jadwal Acara
- Akad Nikah (hari, tanggal, jam)
- Resepsi (hari, tanggal, jam)
- Lokasi dengan QR Code Google Maps
- Border dekoratif
Halaman 4: E-Invitation
- QR Code besar (personalized URL)
- Pesan penutup
- Wassalamualaikum
- Signature mempelai
Theme Options:
-
Sage Green (Original)
- Background: #FFFFFF
- Primary: #556B2F
- Secondary: #BDD1A6
-
Classic Maroon
- Background: #FFFCFC
- Primary: #800020
- Secondary: #E6B4BE
-
Royal Gold
- Background: #FFFFFC
- Primary: #B8860B
- Secondary: #F0E68C
-
Dusty Blue
- Background: #FAFAFF
- Primary: #465A78
- Secondary: #BED2E6
Mode Operasi:
Single PDF:
Input:
- Nama tamu
- Alamat/kota (opsional)
Output:
- Preview real-time
- Download single PDF
- Nama file: Inv_{nama_tamu}_{theme}.pdfBulk PDF:
Input: CSV (Kolom 1: Nama, Kolom 2: Alamat)
Process:
1. Upload & parse CSV
2. Preview data tamu
3. Generate PDF batch dengan progress
4. Compress ke ZIP
5. Download ZIP
Features:
- Template CSV download
- Progress indicator detail
- Chunk processing (10 PDF per batch)
- File naming: {index}_{nama_tamu}.pdf
- ZIP naming: Undangan-{theme}-{date}.zipwedding-invitation/
│
├── .vscode/ # VSCode settings
│ └── settings.json # Format on save, Prettier config
│
├── database/ # SQLite database location
│ └── wedding.db # Auto-created on first run
│
├── public/ # Static assets
│ ├── favicon.svg # Site icon
│ ├── pwa-192x192.png # PWA icon small
│ ├── pwa-512x512.png # PWA icon large
│ └── thumbnail.png # OG image preview
│
├── src/
│ ├── components/ # React components
│ │ ├── Admin/
│ │ │ └── AdminDashboard.tsx # Main admin interface
│ │ ├── CoupleProfile.tsx # Mempelai section
│ │ ├── Envelope.tsx # Opening animation
│ │ ├── EventDetails.tsx # Jadwal acara
│ │ ├── FloatingPetals.tsx # Decorative animation
│ │ ├── Gallery.tsx # Photo gallery + lightbox
│ │ ├── GiftInfo.tsx # Bank accounts + address
│ │ ├── Hero.tsx # Landing section + countdown
│ │ ├── InstallPrompt.tsx # PWA install banner
│ │ ├── InvitationManager.tsx # PDF designer component
│ │ ├── LoveStory.tsx # Timeline kisah cinta
│ │ ├── MusicPlayer.tsx # Background audio
│ │ ├── Navbar.tsx # Bottom navigation
│ │ ├── QRCodeGenerator.tsx # Single QR generator
│ │ ├── QRCodeManager.tsx # Bulk QR generator
│ │ ├── RSVPForm.tsx # RSVP form + dashboard
│ │ └── Wishes.tsx # Guest book + pagination
│ │
│ ├── layouts/
│ │ └── Layout.astro # Base HTML structure
│ │
│ ├── lib/
│ │ ├── db.ts # SQLite setup + migrations
│ │ └── rateLimit.ts # IP-based rate limiter
│ │
│ ├── pages/
│ │ ├── api/
│ │ │ ├── admin.ts # Admin CRUD operations
│ │ │ ├── export-rsvp.ts # RSVP CSV export
│ │ │ ├── export-wishes.ts # Wishes CSV export
│ │ │ ├── rsvp.ts # RSVP GET/POST
│ │ │ └── wishes.ts # Wishes GET/POST
│ │ ├── 404.astro # Custom error page
│ │ ├── admin.astro # Admin panel
│ │ ├── index.astro # Main invitation page
│ │ └── qrcode.astro # QR generator page
│ │
│ ├── services/
│ │ └── dbService.ts # Frontend API wrapper
│ │
│ ├── styles/
│ │ └── global.css # Tailwind + custom styles
│ │
│ ├── utils/
│ │ ├── calendarUtils.ts # Google Cal + ICS
│ │ └── telegram.ts # Telegram notifications
│ │
│ ├── App.tsx # Main React app
│ ├── constants.tsx # Config parser
│ └── types.ts # TypeScript definitions
│
├── .env # Configuration file (REQUIRED)
├── .env.example # Configuration template
├── .prettierrc.mjs # Code formatting rules
├── astro.config.mjs # Astro framework config
├── ecosystem.config.cjs # PM2 process manager
├── eslint.config.mjs # Linting rules
├── nginx.conf # Nginx reverse proxy example
├── package.json # Dependencies + scripts
├── README.md # This file
├── todo.md # Development notes
├── tsconfig.json # TypeScript config
└── LICENSE # MIT License
Database Layer (src/lib/db.ts)
// Auto-migration dari root ke /database folder
// WAL mode untuk concurrent access
// Auto-create tables on first runAPI Layer (src/pages/api/)
// RESTful endpoints
// Rate limiting di semua POST endpoints
// Sanitasi input untuk XSS protection
// Cookie-based auth untuk adminService Layer (src/services/dbService.ts)
// Client-side cache (30 detik)
// Fetch wrapper untuk API calls
// Type-safe responsesComponents
// React functional components dengan hooks
// TypeScript strict mode
// Client-side rendering dengan Astro directives
// Shared props via constantsSemua konfigurasi website dikelola melalui environment variables. Salin .env.example ke .env di root folder.
# Host dan Port untuk development/production
HOST=0.0.0.0
PORT=4321
# Nama file database SQLite (auto-created di /database)
DB_NAME=wedding.db
# Password untuk akses admin panel
ADMIN_PASSWORD=P@ssw0rd_Anda_Disini# Untuk mendapatkan token dan chat_id:
# 1. Buat bot baru melalui @BotFather di Telegram
# 2. Dapatkan chat_id dengan cara kirim pesan ke bot
# lalu akses: https://api.telegram.org/bot<TOKEN>/getUpdates
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
TELEGRAM_CHAT_ID=123456789# Gambar utama (support Unsplash, lokal, atau CDN)
PUBLIC_HERO_IMAGE=https://images.unsplash.com/photo-1511795409834-ef04bbd61622?q=80&w=2069&auto=format&fit=crop
# Lokasi/kota untuk ditampilkan di hero
PUBLIC_HERO_CITY=Kab. Pandeglang, Banten# URL musik (MP3/OGG)
# Bisa menggunakan:
# - CDN seperti BenSound
# - Upload ke hosting sendiri
# - Google Drive (dengan link direct download)
PUBLIC_MUSIC_URL=https://www.bensound.com/bensound-music/bensound-forever.mp3# Nama panggilan (untuk footer dan hero)
PUBLIC_BRIDE_NICKNAME=Fey
# Nama lengkap (untuk profile section)
PUBLIC_BRIDE_FULLNAME=Fera Oktapia
# Info orang tua
PUBLIC_BRIDE_PARENTS=Putri tercinta dari Bpk. [Nama Ayah] & Ibu [Nama Ibu]
# Instagram handle (tanpa @)
PUBLIC_BRIDE_INSTAGRAM=feraoktapia___
# URL foto portrait (landscape atau portrait, min 600x800px)
PUBLIC_BRIDE_IMAGE=https://placehold.co/600x800?text=Fey+PortraitPUBLIC_GROOM_NICKNAME=Yaya
PUBLIC_GROOM_FULLNAME=Yahya Zulfikri
PUBLIC_GROOM_PARENTS=Putra tercinta dari Bpk. [Nama Ayah] & Ibu [Nama Ibu]
PUBLIC_GROOM_INSTAGRAM=zulfikriyahya_
PUBLIC_GROOM_IMAGE=https://placehold.co/600x800?text=Yaya+Portrait# Nama tempat acara
PUBLIC_VENUE_NAME=The Royal Azure Ballroom
# Alamat lengkap (untuk display dan PDF)
PUBLIC_VENUE_ADDRESS=Jl. Taman Makam Pahlawan No.1, Kab. Pandeglang, Banten
# Koordinat GPS (dapatkan dari Google Maps)
# Cara: Klik kanan di Google Maps → koordinat ada di popup
PUBLIC_VENUE_LAT=-6.2088
PUBLIC_VENUE_LNG=106.8456# Judul acara (bebas customize)
PUBLIC_AKAD_TITLE=Akad Nikah
# Nama hari (Senin - Minggu)
PUBLIC_AKAD_DAY=Minggu
# Tanggal dalam format Indonesia
PUBLIC_AKAD_DATE=11 Oktober 2025
# Waktu mulai dan selesai (format 24 jam)
PUBLIC_AKAD_START=08:00
PUBLIC_AKAD_END=10:00
# Format ISO-8601 dengan timezone (+07:00 untuk WIB)
# PENTING: Format ini digunakan untuk countdown timer dan calendar export
PUBLIC_AKAD_ISO_START=2025-10-11T08:00:00+07:00
PUBLIC_AKAD_ISO_END=2025-10-11T10:00:00+07:00PUBLIC_RESEPSI_TITLE=Resepsi Pernikahan
PUBLIC_RESEPSI_DAY=Minggu
PUBLIC_RESEPSI_DATE=11 Oktober 2025
PUBLIC_RESEPSI_START=11:00
PUBLIC_RESEPSI_END=14:00
PUBLIC_RESEPSI_ISO_START=2025-10-11T11:00:00+07:00
PUBLIC_RESEPSI_ISO_END=2025-10-11T14:00:00+07:00# Maksimal jumlah tamu yang bisa dibawa per undangan
# Bisa disesuaikan dengan kapasitas venue
PUBLIC_RSVP_MAX_GUESTS=20PENTING: Data berikut harus ditulis dalam satu baris tanpa line break.
Bank Accounts:
PUBLIC_BANK_ACCOUNTS=[{"bank":"Bank BCA","number":"1234567890","name":"Fera Oktapia"},{"bank":"Bank Mandiri","number":"0987654321","name":"Yahya Zulfikri"}]Love Story Timeline:
PUBLIC_LOVE_STORY=[{"date":"2020","title":"Awal Pertemuan","desc":"Atas izin Allah, kami dipertemukan dalam suasana yang sederhana namun penuh makna."},{"date":"2022","title":"Menjalin Harapan","desc":"Dengan niat baik, kami memutuskan untuk saling mengenal dan membangun komitmen menuju ridho-Nya."},{"date":"2025","title":"Ikatan Suci","desc":"Insya Allah, kami memantapkan hati untuk menyempurnakan separuh agama dalam ikatan pernikahan."}]Gallery Images:
PUBLIC_GALLERY_IMAGES=["https://placehold.co/800x1200?text=Moment+1","https://placehold.co/1200x800?text=Moment+2","https://placehold.co/800x800?text=Moment+3","https://placehold.co/800x1200?text=Moment+4","https://placehold.co/1200x800?text=Moment+5","https://placehold.co/800x1200?text=Moment+6"]-
Validasi JSON:
# Gunakan tool online seperti jsonlint.com # untuk memvalidasi format JSON sebelum paste ke .env
-
URL Gambar:
// Rekomendasi sumber gambar: // - Unsplash (gratis, high-quality) // - ImgBB (free image hosting) // - Cloudinary (CDN profesional) // - Self-hosted di /public folder
-
Koordinat GPS:
1. Buka Google Maps 2. Klik kanan pada lokasi venue 3. Klik koordinat yang muncul (format: -6.xxx, 106.xxx) 4. Copy paste ke .env -
Format Tanggal ISO:
// Format: YYYY-MM-DDTHH:mm:ss+07:00 // YYYY: Tahun 4 digit // MM: Bulan 2 digit (01-12) // DD: Tanggal 2 digit (01-31) // T: Separator // HH:mm:ss: Jam 24-format // +07:00: Timezone (WIB)
Software Required:
- Node.js versi 18.x atau lebih tinggi
- Package manager: Yarn (recommended) atau NPM
- Git untuk version control
- Text editor: VSCode (recommended)
Browser Support:
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
OS Tested:
- Windows 10/11
- macOS 11+
- Ubuntu 20.04/22.04
# Via HTTPS
git clone https://github.com/zulfikriyahya/wedding-invitation.git
# Via SSH (jika sudah setup SSH key)
git clone git@github.com:zulfikriyahya/wedding-invitation.git
# Masuk ke folder project
cd wedding-invitation# Copy template konfigurasi
cp .env.example .env
# Edit file .env dengan text editor favorit
nano .env
# atau
code .env # jika menggunakan VSCodeMinimal Configuration untuk Testing:
HOST=0.0.0.0
PORT=4321
DB_NAME=wedding.db
ADMIN_PASSWORD=admin123
PUBLIC_BRIDE_NICKNAME=Bride
PUBLIC_GROOM_NICKNAME=Groom
PUBLIC_VENUE_NAME=Test Venue
PUBLIC_AKAD_ISO_START=2025-12-31T10:00:00+07:00
PUBLIC_AKAD_ISO_END=2025-12-31T12:00:00+07:00# Menggunakan Yarn (recommended)
yarn install
# Atau menggunakan NPM
npm install
# Proses ini akan:
# - Download semua package yang dibutuhkan
# - Compile native modules (better-sqlite3)
# - Setup development tools (ESLint, Prettier)
# Durasi: 2-5 menit tergantung koneksi internet# Start server
yarn dev
# Output yang muncul:
# 🚀 astro v5.x.x started in XXXms
# ┃ Local http://localhost:4321/
# ┃ Network http://192.168.x.x:4321/Buka browser dan kunjungi:
- Local:
http://localhost:4321 - Network:
http://192.168.x.x:4321(bisa diakses dari device lain dalam jaringan yang sama)
# File yang di-watch untuk auto-reload:
# - src/**/*.astro
# - src/**/*.tsx
# - src/**/*.ts
# - src/**/*.css
# - .env (perlu restart manual)# Setelah edit .env, restart server:
Ctrl + C # Stop server
yarn dev # Start ulang# Database otomatis dibuat di:
./database/wedding.db
# Untuk reset database:
rm -rf database/
yarn dev # Database baru akan dibuat otomatisVSCode Launch Configuration:
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Astro Dev Server",
"runtimeExecutable": "yarn",
"runtimeArgs": ["dev"],
"console": "integratedTerminal"
}
]
}Browser DevTools:
// Enable React DevTools
// Chrome Extension: React Developer Tools
// Enable Astro DevTools
// Built-in di browser console1. Buka http://localhost:4321/?to=Test+User
2. Scroll ke section RSVP
3. Isi form dan submit
4. Cek data di admin panel: http://localhost:4321/admin1. Akses http://localhost:4321/admin
2. Login dengan password dari .env (ADMIN_PASSWORD)
3. Eksplorasi semua fitur:
- Lihat data RSVP
- Edit/delete data
- Export CSV
- Generate QR Code
- Buat PDF undangan1. Login ke admin panel
2. Buka tab "QR Generator"
3. Mode Single:
- Input nama tamu
- Preview QR code
- Download PNG
4. Mode Bulk:
- Download template CSV
- Edit dengan Excel/Google Sheets
- Upload kembali
- Download ZIP1. Login ke admin panel
2. Buka tab "Design PDF"
3. Pilih theme warna
4. Mode Single:
- Input nama dan alamat
- Preview PDF
- Download
5. Mode Bulk:
- Download template CSV
- Upload file
- Generate batchPort Already in Use:
# Ganti port di .env
PORT=3000
# Atau kill process yang menggunakan port 4321
# Windows:
netstat -ano | findstr :4321
taskkill /PID <PID> /F
# Linux/Mac:
lsof -ti:4321 | xargs kill -9Database Lock Error:
# Matikan semua instance dev server yang running
# Hapus file lock
rm database/wedding.db-journalModule Not Found:
# Clear cache dan reinstall
rm -rf node_modules
rm yarn.lock # atau package-lock.json
yarn installBetter-sqlite3 Compile Error:
# Rebuild native module
yarn add better-sqlite3 --forceMinimum Requirements:
- OS: Ubuntu 20.04 LTS atau lebih tinggi
- RAM: 512 MB (1 GB recommended)
- Storage: 2 GB free space
- CPU: 1 vCore
Software Stack:
# Update system
sudo apt update && sudo apt upgrade -y
# Install Node.js 18.x
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
# Install Yarn
sudo npm install -g yarn
# Install PM2
sudo npm install -g pm2
# Install Nginx
sudo apt install -y nginx
# Install certbot (untuk SSL/HTTPS)
sudo apt install -y certbot python3-certbot-nginx# Pastikan semua perubahan sudah di-commit
git status
# Build production
yarn build
# Output akan ada di folder dist/
# Struktur:
# dist/
# ├── client/ # Static assets
# ├── server/ # Server entry point
# └── manifest.json # Build manifest# Compress untuk upload
tar -czf production.tar.gz \
dist/ \
package.json \
yarn.lock \
ecosystem.config.cjs \
.env
# File yang TIDAK perlu di-upload:
# - node_modules/ (install ulang di server)
# - src/ (sudah ter-bundle di dist/)
# - .git/ (opsional, tergantung deployment strategy)Via SCP:
# Upload compressed file
scp production.tar.gz user@your-server.com:/var/www/
# SSH ke server
ssh user@your-server.com
# Extract
cd /var/www
tar -xzf production.tar.gz
rm production.tar.gzVia Git (Recommended):
# Di server, clone repository
cd /var/www
git clone https://github.com/zulfikriyahya/wedding-invitation.git
cd wedding-invitation
# Build di server
yarn install --production
yarn buildcd /var/www/wedding-invitation
# Install hanya production dependencies
yarn install --production
# Verify better-sqlite3 compiled correctly
node -e "require('better-sqlite3')"# Copy .env dari backup atau edit langsung
nano .env
# PENTING: Ganti nilai-nilai berikut untuk production:
ADMIN_PASSWORD=<strong-password-here>
HOST=0.0.0.0
PORT=4321# Test jalankan server manual dulu
node dist/server/entry.mjs
# Jika berhasil, Ctrl+C untuk stop# Start dengan PM2
pm2 start ecosystem.config.cjs
# Verify running
pm2 list
# Output:
# ┌─────┬──────────────────────┬─────────┬─────────┐
# │ id │ name │ status │ cpu │
# ├─────┼──────────────────────┼─────────┼─────────┤
# │ 0 │ wedding.feyaya.com │ online │ 0% │
# └─────┴──────────────────────┴─────────┴─────────┘
# Auto-start on server reboot
pm2 save
pm2 startup
# Follow instructions dari output command# Lihat logs real-time
pm2 logs wedding.feyaya.com
# Restart aplikasi
pm2 restart wedding.feyaya.com
# Stop aplikasi
pm2 stop wedding.feyaya.com
# Hapus dari PM2
pm2 delete wedding.feyaya.com
# Monitor resource usage
pm2 monit# Buat file config
sudo nano /etc/nginx/sites-available/wedding# Basic Rate Limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=general:10m rate=30r/s;
# Upstream
upstream wedding_backend {
server 127.0.0.1:4321;
keepalive 64;
}
server {
listen 80;
listen [::]:80;
server_name wedding.feyaya.com www.wedding.feyaya.com;
# Redirect HTTP to HTTPS (setelah SSL setup)
# return 301 https://$server_name$request_uri;
# Root directory (untuk static files jika diperlukan)
root /var/www/wedding-invitation/dist/client;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# Gzip Compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript
application/javascript application/xml+rss
application/json image/svg+xml;
# Cache untuk Static Assets (_astro/...)
location /_astro/ {
proxy_pass http://wedding_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# Cache selama 1 tahun (immutable)
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
access_log off;
}
# Cache untuk Gambar & Font
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|woff|woff2|ttf|eot)$ {
proxy_pass http://wedding_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
# Cache 30 hari
expires 30d;
add_header Cache-Control "public, max-age=2592000";
access_log off;
}
# Rate Limit untuk API Endpoints
location ~ ^/api/(rsvp|wishes) {
limit_req zone=api burst=5 nodelay;
proxy_pass http://wedding_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
# No Cache untuk API
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# Admin Panel (Protected)
location /admin {
limit_req zone=api burst=3 nodelay;
proxy_pass http://wedding_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_cache_bypass $http_upgrade;
# No Cache
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# Main Application (dengan rate limit lebih longgar)
location / {
limit_req zone=general burst=10 nodelay;
proxy_pass http://wedding_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
# Cache pendek untuk halaman utama (5 menit)
# Bisa di-adjust sesuai kebutuhan
add_header Cache-Control "public, max-age=300";
}
}# Link ke sites-enabled
sudo ln -s /etc/nginx/sites-available/wedding /etc/nginx/sites-enabled/
# Test konfigurasi
sudo nginx -t
# Jika OK, reload Nginx
sudo systemctl reload nginx# Generate SSL certificate
sudo certbot --nginx -d wedding.feyaya.com -d www.wedding.feyaya.com
# Follow prompts:
# - Email untuk renewal notifications
# - Agree to terms of service
# - Redirect HTTP to HTTPS: Yes (recommended)
# Verify auto-renewal
sudo certbot renew --dry-run
# Auto-renewal sudah di-setup via systemd timer
sudo systemctl status certbot.timer# Enable UFW
sudo ufw enable
# Allow SSH
sudo ufw allow 22/tcp
# Allow HTTP & HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Check status
sudo ufw status
# Output:
# Status: active
# To Action From
# -- ------ ----
# 22/tcp ALLOW Anywhere
# 80/tcp ALLOW Anywhere
# 443/tcp ALLOW Anywhere# Backup database
cp /var/www/wedding-invitation/database/wedding.db \
/var/www/wedding-invitation/database/backup-$(date +%Y%m%d).db
# Backup dengan compress
tar -czf wedding-backup-$(date +%Y%m%d).tar.gz \
database/ \
.env# Edit crontab
crontab -e
# Tambahkan line berikut (backup setiap hari jam 2 pagi)
0 2 * * * cd /var/www/wedding-invitation && tar -czf ~/backups/wedding-$(date +\%Y\%m\%d).tar.gz database/ .env
# Buat folder backup
mkdir -p ~/backups
# Cleanup old backups (keep 30 days)
# Tambahkan ke cron
0 3 * * * find ~/backups -name "wedding-*.tar.gz" -mtime +30 -delete# Real-time logs
pm2 logs wedding.feyaya.com --lines 100
# Error logs only
pm2 logs wedding.feyaya.com --err
# Save logs to file
pm2 logs wedding.feyaya.com > app.log# Access logs
sudo tail -f /var/log/nginx/access.log
# Error logs
sudo tail -f /var/log/nginx/error.log
# Analyze logs dengan goaccess (optional)
sudo apt install goaccess
sudo goaccess /var/log/nginx/access.log --log-format=COMBINED# PM2 monitoring
pm2 monit
# System resources
htop
# Disk usage
df -h
# Database size
du -sh database/wedding.db# 1. Pull latest code
cd /var/www/wedding-invitation
git pull origin main
# 2. Install dependencies (jika ada perubahan package.json)
yarn install --production
# 3. Build
yarn build
# 4. Restart PM2
pm2 restart wedding.feyaya.com
# 5. Verify
pm2 statusURL Umum:
https://wedding.feyaya.com
URL Personal (dengan nama tamu):
https://wedding.feyaya.com/?to=Ahmad+Syarief+Ramadhan
Efek Personalisasi:
- Nama muncul di amplop pembuka
- Nama muncul di hero section setelah countdown
- Form RSVP otomatis terisi nama (terkunci, tidak bisa diubah)
- Form buku tamu otomatis terisi nama (terkunci)
- Scroll ke section "Reservasi"
- Nama sudah terisi otomatis (jika akses via link personal)
- Isi nomor HP/WhatsApp (opsional)
- Pilih status kehadiran:
- Hadir: Akan datang ke acara
- Tidak Hadir: Tidak bisa hadir
- Ragu: Belum yakin/tentative
- Jika pilih "Hadir", tentukan jumlah tamu yang dibawa (max 20 orang default)
- Isi pesan untuk mempelai (opsional)
- Klik tombol "Send RSVP"
Catatan Penting:
- Jika submit dengan nama yang sama, data lama akan di-update (tidak duplikat)
- Rate limit: Maksimal 5 submit per menit per IP
- Scroll ke section "Prayers & Wishes"
- Isi nama lengkap (terisi otomatis jika via link personal)
- Tulis ucapan dan doa untuk mempelai
- Klik "Send Message"
- Ucapan akan muncul di galeri ucapan dengan paginasi
- Lihat section "Waktu & Tempat"
- Pilih acara: Akad Nikah atau Resepsi
- Klik tombol "Save The Date"
- Pilih:
- Google Calendar: Langsung buka Google Calendar
- Apple / Outlook: Download file .ics
- Scroll ke section venue/lokasi
- Opsi navigasi:
- Copy Address: Salin alamat ke clipboard
- Open In Maps: Buka di Google Maps native app
- Embedded Map: Lihat langsung di website
Via Transfer Bank:
- Scroll ke section "Tanda Kasih"
- Pilih salah satu bank
- Klik "Salin Nomor" untuk copy nomor rekening
- Lakukan transfer via mobile banking
- Konfirmasi via WhatsApp mempelai (opsional)
Via Kirim Fisik:
- Klik "Salin Alamat" pada card alamat kirim
- Paste alamat saat input di kurir/pos
- Kirim paket ke alamat tersebut
URL: https://wedding.feyaya.com/admin
Password: Sesuai dengan ADMIN_PASSWORD di .env
Dashboard utama menampilkan:
- Total respon RSVP
- Jumlah yang hadir + total pax
- Jumlah yang masih ragu
- Jumlah yang tidak hadir
Fitur Tersedia:
-
View Data
- Tabel lengkap dengan semua kolom
- Search real-time
- Filter dan sorting
- Pagination (5/10/25/50 per halaman)
-
Edit Data
- Klik icon pensil pada baris data
- Edit nama, status, jumlah tamu, atau pesan
- Klik "Simpan"
-
Delete Data
- Single delete: Klik icon trash pada baris
- Bulk delete:
- Checklist data yang ingin dihapus
- Klik tombol "Hapus (X)" di atas tabel
- Konfirmasi sebelum hapus permanen
-
Export Data
- Klik tombol "Export CSV" di kanan atas
- File CSV akan otomatis terdownload
- Bisa dibuka dengan Excel/Google Sheets
Format Export CSV:
Nama Tamu,No HP,Kehadiran,Jumlah,Pesan,Waktu Input
"Ahmad Syarief",'081234567890',hadir,3,"Selamat menempuh hidup baru",2025-01-15 10:30:00Fitur Identik dengan RSVP:
- View, edit, delete (single & bulk)
- Search dan filter
- Export CSV
Use Case:
- Moderasi pesan tidak pantas
- Hapus spam
- Edit typo pada nama pengirim
Mode Single (Satuan):
- Buka tab "QR Generator"
- Pilih "Manual (Satuan)"
- Input nama tamu
- Preview QR code akan muncul real-time
- Opsi:
- Copy Link: Salin URL undangan personal
- Download PNG: Download QR code sebagai gambar
QR Code Design:
- Size: 250x250 px
- Level: High error correction
- Logo: Inisial mempelai dalam circle dengan border gold
- Format: PNG transparent background
Mode Bulk (Banyak):
-
Pilih tab "Import CSV (Banyak)"
-
Download template CSV:
- Klik "Download Template CSV"
- Buka dengan Excel/Google Sheets
- Isi kolom "Nama Tamu" (satu nama per baris)
- Save as CSV
-
Upload CSV:
- Klik "Pilih File CSV"
- Select file yang sudah diisi
- Data akan ter-preview (max 50 tampil)
-
Generate:
- Klik "Download ZIP"
- Progress bar akan muncul
- Proses: 50 QR per chunk
- Output: ZIP file berisi semua QR code
Struktur File ZIP:
QR-Codes-2025-01-15.zip
├── 1_Ahmad_Syarief.png
├── 2_Muhammad_Ikbal.png
├── 3_Keluarga_Bapak_Jokowi.png
└── ...
Tips:
- QR code bisa langsung di-print untuk amplop fisik
- Size 250x250px cukup untuk scan jarak 30cm
- Format PNG support transparency untuk design overlay
Mode Single (Satuan):
-
Buka tab "Design PDF"
-
Pilih theme warna (4 opsi):
- Sage Green (hijau original)
- Classic Maroon (merah maroon)
- Royal Gold (emas)
- Dusty Blue (biru lembut)
-
Input data:
- Nama tamu (wajib)
- Alamat/kota (opsional, default: "Di Tempat")
-
Preview:
- Klik "Preview"
- PDF akan tampil di sebelah kanan
- Scroll untuk lihat 4 halaman
-
Download:
- Klik "Download PDF"
- File:
Inv_{nama_tamu}_{theme}.pdf
Mode Bulk (Banyak):
-
Download template CSV
-
Isi data tamu:
Nama Tamu,Alamat (Opsional) Bapak Jokowi & Ibu Iriana,Jakarta Teman-teman Alumni SMA 1,Di Tempat Keluarga Besar H. Syarif,Bandung
-
Upload CSV:
- Sistem parse dan preview data
- Jumlah tamu terdeteksi akan ditampilkan
-
Generate batch:
- Klik "Download ZIP"
- Progress indicator muncul dengan status detail
- Processing: 10 PDF per chunk
- Output: ZIP file
Struktur ZIP:
Undangan-sage-2025-01-15.zip
├── 1_Bapak_Jokowi.pdf
├── 2_Teman_teman_Alumni_SMA_1.pdf
├── 3_Keluarga_Besar_H_Syarif.pdf
└── ...
Detail Template PDF:
Halaman 1 - Cover:
- Border ornamen bunga (vektor, bukan gambar)
- Judul: "THE WEDDING OF"
- Nama mempelai dalam font serif italic besar
- Tanggal pernikahan
- Box personalisasi:
- "Kepada Yth. Bapak/Ibu/Saudara/i:"
- Nama tamu (bold italic)
- Alamat/kota
Halaman 2 - Detail Mempelai:
- Salam pembuka: "Assalamu'alaikum..."
- Quote QS. Ar-Rum:21 (italic)
- Kalimat pengantar sopan
- Detail mempelai wanita:
- Nama lengkap
- Info orang tua
- Detail mempelai pria:
- Nama lengkap
- Info orang tua
Halaman 3 - Jadwal Acara:
- Judul: "Insya Allah acara akan dilaksanakan pada:"
- Akad Nikah:
- Hari, tanggal
- Jam (WIB)
- Resepsi:
- Hari, tanggal
- Jam (WIB)
- Lokasi:
- Nama venue
- Alamat lengkap
- QR Code Google Maps (size: 22mm)
Halaman 4 - E-Invitation:
- Judul: "E-INVITATION"
- QR Code besar (40mm) dengan:
- URL personal tamu
- Border gradient
- Logo premium di tengah
- Instruksi: "Scan untuk buka undangan digital..."
- Pesan penutup sopan
- "Wassalamu'alaikum..."
- Signature mempelai dengan nama lengkap
Design Features:
- Paper size: A5 (148 x 210 mm)
- Orientation: Portrait
- Border: Triple line dengan gradient
- Ornaments: Corner florals (mawar + daun)
- Fonts:
- Times New Roman untuk body text
- Serif italic untuk judul
- Colors: Sesuai theme yang dipilih
- QR Codes: High error correction level
- File size: ~150-200KB per PDF
Use Case:
- Print untuk amplop fisik undangan
- Email attachment
- Share via WhatsApp
- Upload ke website sebagai downloadable
Tips Printing:
- Print di kertas A5 (148x210mm) atau half-A4
- Recommended: Art Paper 260gsm
- Margin: None (full bleed)
- Color mode: CMYK untuk hasil optimal
- Print setting: Best quality
Klik tombol "LOGOUT" di kanan atas dashboard.
Framework & Library:
-
Astro 5.16.6: Static Site Generator dengan SSR support
- Island Architecture untuk optimal bundle size
- Partial hydration
- Built-in optimization
-
React 19.2.3: UI Component Library
- Functional components dengan hooks
- TypeScript strict mode
- Server Components ready
-
Tailwind CSS 4.1.18: Utility-first CSS Framework
- Custom theme configuration
- Dark mode support
- Responsive design
- JIT compiler
UI Components:
- Lucide React: Icon library (tree-shakeable)
- Custom components dengan editorial design
QR Code & PDF:
- qrcode.react 4.2.0: QR code generator component
- qrcode 1.5.4: Server-side QR generation
- jsPDF 3.0.4: PDF generation library
- Canvas API: untuk render QR dan vector graphics
File Processing:
- PapaParse 5.5.3: CSV parser
- JSZip 3.10.1: ZIP file generator
- FileSaver 2.0.5: Client-side file download
PWA:
- vite-plugin-pwa 1.2.0: PWA integration
- Workbox: Service Worker strategies
Runtime & Server:
- Node.js 18+: JavaScript runtime
- Astro Node Adapter 9.5.1: SSR dengan standalone mode
- Express (via Astro): HTTP server
Database:
- better-sqlite3 12.5.0: Synchronous SQLite3 binding
- WAL mode untuk concurrent access
- Prepared statements
- Transaction support
API Layer:
- RESTful API dengan Astro API routes
- Type-safe dengan TypeScript
- Input sanitization
Code Quality:
- TypeScript 5.9.3: Type-safe JavaScript
- ESLint 9.39.2: Linting
- React plugin
- Astro plugin
- TypeScript plugin
- Prettier 3.7.4: Code formatter
- Astro plugin
- Tailwind plugin
Build Tools:
- Vite 7.3.0: Build tool dan dev server
- HMR (Hot Module Replacement)
- Code splitting
- Asset optimization
Process Management:
- PM2: Production process manager
- Auto-restart on crash
- Log management
- Cluster mode support
Web Server:
- Nginx: Reverse proxy
- Static file serving
- Gzip compression
- Rate limiting
- SSL termination
SSL:
- Let's Encrypt: Free SSL certificates
- Certbot: Auto-renewal
Monitoring:
- PM2 built-in monitoring
- Nginx access/error logs
- Custom logging
Notifications:
- Telegram Bot API: Real-time notifications
- New RSVP alerts
- New wishes alerts
- Update notifications
CDN & Hosting:
- Unsplash: Free high-quality images
- Google Fonts: Web fonts
- Cloudflare (optional): CDN dan DDoS protection
Analytics (Optional):
- Google Analytics
- Plausible Analytics (privacy-friendly)
wedding-invitation
├── @astrojs/node (SSR adapter)
├── @astrojs/react (React integration)
├── @astrojs/sitemap (SEO)
├── better-sqlite3 (Database)
├── react (UI framework)
├── lucide-react (Icons)
├── qrcode.react (QR generator)
├── jspdf (PDF generator)
├── papaparse (CSV parser)
└── jszip (ZIP generator)
Total Bundle Size:
- Client bundle: ~150KB (gzipped)
- Server bundle: ~500KB
- Database: ~100KB (empty)
Performance Metrics:
- First Contentful Paint: <1.5s
- Time to Interactive: <3s
- Lighthouse Score: 95+
Problem:
Error: listen EADDRINUSE: address already in use :::4321
Solution:
# Opsi 1: Ganti port di .env
PORT=3000
# Opsi 2: Kill process yang menggunakan port
# Windows
netstat -ano | findstr :4321
taskkill /PID <PID_NUMBER> /F
# Linux/Mac
lsof -ti:4321 | xargs kill -9Problem:
SqliteError: database is locked
Solution:
# 1. Stop semua instance dev server
pkill -f "astro dev"
# 2. Hapus journal file
rm database/wedding.db-journal
# 3. Restart dev server
yarn devProblem:
Cannot find module 'better-sqlite3'
Solution:
# Clear cache dan reinstall
rm -rf node_modules
rm yarn.lock # atau package-lock.json
yarn installProblem:
Error: The module was compiled against a different Node.js version
Solution:
# Rebuild native module
yarn add better-sqlite3 --force
# Atau dengan node-gyp
npm rebuild better-sqlite3Problem: Server tidak bisa connect ke backend.
Diagnosis:
# Cek PM2 status
pm2 status
# Lihat logs
pm2 logs wedding.feyaya.com --err
# Test manual run
cd /var/www/wedding-invitation
node dist/server/entry.mjsCommon Causes:
- PM2 belum running
- Port conflict
- Permission issues
- Missing dependencies
Solution:
# Restart PM2
pm2 restart wedding.feyaya.com
# Jika masih error, delete dan start ulang
pm2 delete wedding.feyaya.com
pm2 start ecosystem.config.cjs
pm2 saveProblem:
SqliteError: unable to open database file
Solution:
# Set proper permissions
sudo chown -R www-data:www-data /var/www/wedding-invitation/database
sudo chmod -R 755 /var/www/wedding-invitation/databaseProblem: Certbot gagal generate certificate.
Diagnosis:
# Test certbot
sudo certbot certonly --dry-run -d wedding.feyaya.com
# Cek DNS
nslookup wedding.feyaya.com
# Test HTTP access
curl -I http://wedding.feyaya.comCommon Causes:
- DNS belum propagate
- Port 80 blocked
- Nginx config salah
- Domain tidak pointing ke server
Solution:
# Pastikan domain pointing ke IP server
# Tunggu DNS propagate (max 24 jam)
# Test dengan HTTP challenge
sudo certbot --nginx -d wedding.feyaya.com --preferred-challenges httpProblem:
pm2 logs: JavaScript heap out of memory
Solution:
# Edit ecosystem.config.cjs
# Tambahkan max_memory_restart
module.exports = {
apps: [{
max_memory_restart: '500M', // atau '1G'
}]
}
# Restart PM2
pm2 restart wedding.feyaya.comProblem:
SqliteError: database disk image is malformed
Solution:
# Backup database corrupt
cp database/wedding.db database/wedding.db.corrupt
# Restore dari backup
cp database/backup-YYYYMMDD.db database/wedding.db
# Atau export/import manual
sqlite3 wedding.db.corrupt ".dump" | sqlite3 wedding.db.newProblem: Query database lambat (>1s).
Diagnosis:
# Open database dengan sqlite3
sqlite3 database/wedding.db
# Check indexes
.schema
# Analyze query plan
EXPLAIN QUERY PLAN SELECT * FROM rsvps;Solution:
-- Tambah index jika perlu
CREATE INDEX idx_rsvps_created_at ON rsvps(created_at DESC);
CREATE INDEX idx_wishes_created_at ON wishes(created_at DESC);
-- Vacuum database
VACUUM;
-- Analyze database
ANALYZE;Problem: User tidak bisa submit form.
Diagnosis:
// Cek logs
pm2 logs | grep "rate limit"Solution:
// Edit src/lib/rateLimit.ts
// Adjust limits
export const checkRateLimit = (
ip: string,
limit: number = 10, // naikan dari 5
windowMs: number = 60000
)Problem:
Access to fetch blocked by CORS policy
Solution:
// Jika perlu custom CORS
// Edit astro.config.mjs
export default defineConfig({
vite: {
server: {
cors: true,
},
},
});Problem: Page load tapi kosong.
Diagnosis:
// Open browser console (F12)
// Lihat error di console
// Cek network tab untuk failed requestsCommon Causes:
- JavaScript error
- React hydration mismatch
- Missing environment variables
- Bundle error
Solution:
# Rebuild dengan clean cache
rm -rf .astro dist
yarn build
# Check .env
cat .env | grep PUBLIC_Problem: Toggle dark mode tidak work.
Diagnosis:
// Check localStorage
console.log(localStorage.getItem("theme"));
// Check class di HTML element
console.log(document.documentElement.classList);Solution:
// Clear localStorage
localStorage.clear();
// Reload page
location.reload();Problem: Countdown timer menghitung ke tanggal yang salah.
Diagnosis:
# Check .env
cat .env | grep PUBLIC_AKAD_ISO_STARTSolution:
# Format harus exact ISO-8601 dengan timezone
PUBLIC_AKAD_ISO_START=2025-10-11T08:00:00+07:00
# ^^^^-^^-^^T^^:^^:^^+^^:^^
# YYYY-MM-DDTHH:mm:ss+TZProblem: Blank canvas atau error saat generate.
Diagnosis:
// Check console error
// Verify logo image loadedSolution:
// Verify constants.tsx
// Check WEDDING_CONFIG.couple.bride.name
// Check WEDDING_CONFIG.couple.groom.nameProblem:
Error generating PDF
Diagnosis:
# Check browser console
# Verify all env variables loadedSolution:
# Restart browser
# Clear cache
# Try different browser
# Server-side: Check memory
pm2 monitProblem: Generate bulk QR/PDF terlalu lama.
Solution:
// Reduce CHUNK_SIZE
// Di QRCodeManager.tsx atau InvitationManager.tsx
const CHUNK_SIZE = 25; // turunkan dari 50Problem: Submit RSVP/Wishes tapi tidak ada notif Telegram.
Diagnosis:
# Check .env
cat .env | grep TELEGRAM_
# Test manual
curl -X POST "https://api.telegram.org/bot<TOKEN>/sendMessage" \
-d "chat_id=<CHAT_ID>" \
-d "text=Test"Solution:
# Verify token dan chat_id benar
# Check bot belum di-block
# Check internet connection dari server
# Test dari server
curl https://api.telegram.org
# Jika ISP block Telegram:
# - Gunakan VPN/proxy
# - Atau disable notifikasi TelegramProblem:
Gagal koneksi ke Telegram: timeout
Solution:
// Edit src/utils/telegram.ts
// Increase timeout dari 5 detik
const timeoutId = setTimeout(() => controller.abort(), 10000);Problem: Page load > 5 detik.
Diagnosis:
# Check Lighthouse score
# Chrome DevTools > Lighthouse > Generate Report
# Check Network tab
# Identify large/slow resourcesSolution:
# 1. Enable Gzip (sudah ada di nginx.conf)
# 2. Optimize images
# - Compress dengan tinypng.com
# - Use WebP format
# - Lazy load di gallery
# 3. Check CDN
# Pastikan external resources fast (fonts, music)Problem: PM2 restart karena memory limit.
Diagnosis:
pm2 monit
htopSolution:
# Increase memory limit di ecosystem.config.cjs
max_memory_restart: '1G'
# Atau upgrade VPS RAMProblem:
yarn build
ERROR: Build failed
Diagnosis:
# Run dengan verbose
yarn build --verbose
# Check specific errorCommon Causes:
- TypeScript error
- Missing dependencies
- Environment variables tidak load
Solution:
# Fix TypeScript errors
yarn tsc --noEmit
# Install dependencies
yarn install
# Check .env exists
ls -la .envProblem: SSH connection refused atau timeout.
Solution:
# Check server running
ping your-server.com
# Check SSH port
nmap -p 22 your-server.com
# Check firewall
sudo ufw status
# Allow SSH if blocked
sudo ufw allow 22/tcpQ: Apakah database SQLite aman untuk production?
A: Ya, untuk website undangan dengan traffic moderate (< 100 concurrent users), SQLite sangat cocok. Keuntungan: simple, zero-config, backup mudah (tinggal copy file).
Q: Bagaimana cara mengganti data mempelai?
A: Edit file .env, ubah nilai PUBLIC_BRIDE_* dan PUBLIC_GROOM_*, lalu restart server (development) atau rebuild + restart PM2 (production).
Q: Apakah bisa menambah bahasa?
A: Ya, tambahkan translation di src/constants.tsx dan buat logic untuk switch language. Framework sudah support i18n.
Q: Berapa batas maksimal tamu?
A: Tidak ada batas hard limit. Database SQLite bisa handle jutaan records. Yang perlu diperhatikan adalah performa query jika data > 10,000 rows (tambah index).
Q: Apakah mobile-friendly?
A: Ya, fully responsive dengan Tailwind CSS. Tested di berbagai device dan screen size.
Q: Bisa deploy di shared hosting?
A: Tidak, karena butuh Node.js runtime. Minimal pakai VPS. Alternative: Deploy di platform seperti Vercel/Netlify (butuh adapter lain).
Q: Database backup otomatis?
A: Gunakan cron job seperti di section "Database Backup Strategy".
Q: SSL certificate gratis selamanya?
A: Ya, Let's Encrypt gratis dan auto-renew setiap 90 hari via certbot.
Kontribusi sangat welcome! Silakan:
- Fork repository
- Buat branch baru (
git checkout -b feature/AmazingFeature) - Commit changes (
git commit -m 'Add some AmazingFeature') - Push ke branch (
git push origin feature/AmazingFeature) - Open Pull Request
Guidelines:
- Follow existing code style (Prettier + ESLint)
- Write meaningful commit messages
- Test thoroughly before submit
- Update documentation jika perlu
Proyek ini dilisensikan di bawah MIT License.
MIT License
Copyright (c) 2025 Yahya Zulfikri
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Developer: Yahya Zulfikri
Email: zulfikriyahya18@gmail.com
Website: https://wedding.feyaya.com
Repository: https://github.com/zulfikriyahya/wedding-invitation