# Joseph & Alice — Wedding PWA (CodeIgniter 4)

A working, installable, bilingual Progressive Web App for wedding invitations, guest registration, RSVPs, donations, event details with maps, and a gift registry — built on CodeIgniter 4 + MySQL/MariaDB.

## What's included

- **Guest registration** — first-time visitors choose a language (English/Kinyarwanda), enter their phone number and name, and are remembered from then on. Returning guests just re-enter their phone number — no password.
- **Home** — the invitation image (a different one per language, if you upload both) as a full-screen background, animated hearts/butterflies/confetti, a floating countdown card (swipe down to dismiss), "Add to calendar", "Share", and fireworks on tap.
- **Details** — ceremony & reception cards with date badges, time, and an embedded Google Map for each venue.
- **RSVP** — locked until a guest registers. No name field — identity comes from registration, so it can't be spoofed. Includes a "Register Donation" flow: amount, Paid Now/Pay Later, and (if paid) which MoMo account it went to.
- **Registry** — just the Gift card; donations moved into the RSVP tab.
- **Bilingual** — every page, button, and message is available in English and Kinyarwanda, switching automatically based on the guest's choice.
- **Admin panel** — login, dashboard stats, RSVP management with CSV export, and a Wedding Details editor (including separate invitation images per language).
- **PWA** — `manifest.json` + `sw.js` service worker for install-to-home-screen and offline shell caching.

## Requirements

- PHP 8.1+ with the `mysqli`, `mbstring`, `intl`, `curl` extensions
- MySQL or MariaDB
- Apache with `mod_rewrite` (an `.htaccess` is included) — or Nginx/PHP-FPM with an equivalent rewrite rule
- No Composer install required — this ships with the full CodeIgniter framework already in `system/`

## 1. Configure the database

Create a database and user (adjust names/password as you like):

```sql
CREATE DATABASE wedding_rsvp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wedding_user'@'localhost' IDENTIFIED BY 'choose-a-strong-password';
GRANT ALL PRIVILEGES ON wedding_rsvp.* TO 'wedding_user'@'localhost';
FLUSH PRIVILEGES;
```

Then either:
- **Import `database_schema.sql`** via phpMyAdmin (Import tab -> choose file -> Go), or
- **Run migrations** from the command line: `php spark migrate`

Tables: `guests`, `rsvps`, `donations`, `settings`, `admin_users`, `migrations`.

## 2. Configure the app

Open `.env` in the project root and update:

```
CI_ENVIRONMENT = production            # switch to `development` while you're testing
app.baseURL = 'https://yourdomain.com/'  # your real domain, with trailing slash

database.default.hostname = localhost
database.default.database = wedding_rsvp
database.default.username = wedding_user
database.default.password = choose-a-strong-password
database.default.DBDriver = MySQLi
```

## 3. Point your web server at `public/`

The document root for your domain (or subdomain) must be the `public/` folder, not the project root. That's where `index.php`, `manifest.json`, `sw.js`, and the images live, and it keeps `app/` and `system/` outside the web-accessible path for security.

- **cPanel/shared hosting**: set the domain/subdomain's "Document Root" to `public/` inside this project folder.
- **Apache VirtualHost**: set `DocumentRoot` to `public/` and allow `.htaccess` overrides (`AllowOverride All`).
- **Nginx**: point `root` at `public/` and add `try_files $uri $uri/ /index.php?$query_string;`.

## 4. Try it locally first (optional)

```bash
php spark serve
```

Visit `http://localhost:8080`.

## How guest registration works

- A first-time visitor sees an onboarding overlay: pick a language → enter phone number → (if new) enter a name → done.
- If the phone number already belongs to a registered guest, they're logged straight back in — no name re-entry.
- "Skip for now" lets someone browse Home/Details/Registry freely, but RSVP and Donation stay locked until they register.
- There's no password — this is intentionally low-friction for a wedding guest list, not a secure account system. Don't reuse this pattern for anything sensitive.
- A guest's language choice is remembered on their record and updates each time they log in with a different choice, so returning guests can switch languages if they want.

## Admin panel

A password-protected admin panel lives at `/admin`:

- **Create your admin login** (do this once, from the server's command line): `php spark admin:create` — prompts for a username and password and stores a securely hashed password. Run it again with the same username to reset a forgotten password. There is no default admin account shipped with this project.
- **Dashboard** (`/admin/dashboard`) — response counts, guest totals, attending/not-attending split, recent RSVPs.
- **RSVPs** (`/admin/rsvps`) — search by name/message, filter by status, delete a response, or export everything to CSV.
- **Wedding Details** (`/admin/details`) — edit the couple's names, wedding date, ceremony & reception venues/times/addresses, dress code, MoMo numbers, and both invitation images (English and Kinyarwanda). Changes apply to the public site immediately — no code edits or redeploys needed.

The admin panel's markup uses DashLite's CSS classes (cards, tables, forms) — copy your licensed DashLite assets into `public/assets/css`, `js`, `fonts`, and `images` to get the full styled look. Until those are in place, admin pages still work but render with plain browser styling.

## Translations

- All UI text lives in `app/Language/en/App.php` and `app/Language/rw/App.php` — plain PHP arrays, easy to open and edit directly.
- The Kinyarwanda translations were done carefully but are **not reviewed by a certified native speaker** — please have someone fluent check `app/Language/rw/App.php` before this goes live, particularly the onboarding and donation messages.
- Admin-authored content (venue names, addresses, dress code text) is a single shared field, not translated per language, since most of it is proper nouns. If you want a bilingual dress-code description too, that would need a small additional field — ask if you want that added.

## Editing your details

- **Do this from the admin panel, not the code**: names, date, venues, times, addresses, dress code, MoMo numbers, invitation images — all editable at `/admin/details`.
- **App icons**: replace `public/assets/icons/icon-192.png` and `icon-512.png` with your own square logo/monogram.
- **Colors/fonts**: in the `<style>` block at the top of `app/Views/app.php` — the CSS variables under `:root` control the palette.
- **Registry "Gift" card link**: currently a placeholder `#` — search for `view_gift_ideas` usage in `app/Views/app.php` and point the link at your real registry.
- **UI wording**: edit the language files directly rather than `app.php` — that keeps English/Kinyarwanda in sync.

## RSVP & donation data

- RSVPs are stored in `rsvps` (`guest_id`, `full_name`, `attending`, `guest_count`, `message`, timestamps) — `full_name` is copied from the guest record server-side, never trusted from the form.
- Donations are stored in `donations` (`guest_id`, `amount`, `status` [`paid`/`pending`], `momo_recipient` [`person1`/`person2`], timestamps).
- Manage RSVPs from `/admin/rsvps`, or query directly via phpMyAdmin. There's no admin donations view yet — query `donations` directly if you need to check pledges, or ask for that page to be added.
- Public API endpoints:
  - `POST /api/rsvp` — requires an active guest session; saves attending/guest_count/message
  - `GET /api/rsvp/summary` — returns `{ responses, guests }` counts
  - `POST /api/donation` — requires an active guest session; saves amount/status/momo_recipient
  - `POST /guest/check-phone`, `POST /guest/register`, `POST /guest/skip` — the registration flow

## Security notes before you launch

- **Change the database password** in `.env` to something strong.
- **Create your real admin login** with `php spark admin:create` before going live.
- **CSRF protection** is on for the entire `/admin` area and off for the public `/api/*` and `/guest/*` endpoints so the fetch-based flows work without extra setup.
- Guest identity is phone-number-only, no verification code — appropriate for a low-stakes wedding guest list, not for anything requiring real authentication.
- **Rate limiting**: consider adding CodeIgniter's built-in throttler to the RSVP/donation/guest endpoints if you're worried about spam.
- Keep `CI_ENVIRONMENT = production` live — this hides error details and disables the debug toolbar.

## PWA / install behavior

- "Add to Home Screen" (iOS Safari) or the automatic install prompt (Android Chrome) installs it like an app, using the icons/colors from `manifest.json`.
- The service worker (`sw.js`) caches the home shell and images for offline access after a first visit. All API calls (RSVP, donation, guest) always hit the network — never cached — so data stays accurate.
