# Church+ — Full Deployment Guide

This is the complete operator's manual for taking Church+ to market: standing up
the platform, building the **Master template** you clone from, onboarding each new
church, and maintaining the already-running **Kingdom First Church (KFCC)** demo.

It assumes cPanel shared or VPS hosting. Commands are shown for both the cPanel UI
and the shell where useful.

---

## Contents

1. The model in one minute
2. Requirements
3. Part A — One-time platform setup (control plane)
4. Part B — Build the Master template
5. Part C — Clone a new church from Master
6. Part D — The KFCC demo (already live) — how it's wired and how to update it
7. Part E — Applying updates to everything
8. Part F — Operations: backups, suspending, removing, security
9. Appendix — Config reference, troubleshooting, what's next

---

## 1. The model in one minute

Church+ is multi-tenant: **one codebase, one database per church**, routed by
subdomain.

- A **control-plane database** (`churchplus_admin`) is your registry — which
  church is on which plan, in which database, at which subdomain.
- Each church gets its **own database** (`churchplus_<slug>`) holding only their
  people, gifts, attendance, and settings. Churches are fully isolated from one
  another.
- The **Master template** is a pristine, configured copy of the code you keep on
  the server and clone each time you onboard a church. You never edit a church's
  code by hand — you clone Master, then drop in that church's config.

```
~/churchplus/
├── churchplus-master/      ← golden template (code only, no config.php)
├── kfcc.churchplus.io/      ← KFCC demo (clone + its own config.php)
├── cornerstone/             ← future church (clone + its own config.php)
└── ...
```

---

## 2. Requirements

- PHP **8.1+** with PDO MySQL and the `mbstring`, `fileinfo`, and `gd` extensions
  (mbstring has a built-in fallback, but enable it if you can)
- MySQL **5.7+** / MariaDB **10.4+**
- One **subdomain per church** with HTTPS (AutoSSL is fine)
- Ability to create databases and MySQL users in cPanel

---

## 3. Part A — One-time platform setup (control plane)

Do this **once** for the whole platform.

1. **cPanel → MySQL Databases.** Create:
   - Database: `churchplus_admin`
   - User: a dedicated MySQL user with a strong password
   - Grant that user **ALL privileges** on `churchplus_admin`
2. **cPanel → phpMyAdmin.** Select `churchplus_admin`, click **Import**, and
   import `sql/admin_schema.sql`.
3. That's it. Every church you onboard adds one row to the `churches` table here.

> cPanel prefixes database and user names with your account username (e.g.
> `myacct_churchplus_admin`). Always use the **full prefixed names** in any
> config and grant. This trips up almost everyone the first time.

---

## 4. Part B — Build the Master template

The Master is the clean copy you clone from. Build it once; update it whenever a
new release ships (Part E).

1. **Upload the code.** Put the contents of this package in
   `~/churchplus/churchplus-master/` so the structure is:

   ```
   ~/churchplus/churchplus-master/
   ├── config/
   │   └── config.example.php     (no config.php in Master — clones get their own)
   ├── public/                     (web root for a church points *into* a clone of this)
   │   ├── assets/
   │   ├── includes/
   │   ├── uploads/                (writable; starts empty except .htaccess + photos/)
   │   └── *.php
   ├── scripts/
   ├── sql/
   ├── src/
   ├── DEPLOYMENT.md  INSTALL.md  README.md  VERSION
   ```

2. **Confirm the upload protections are intact:**
   - `public/uploads/.htaccess` exists (blocks script execution in the uploads
     folder)
   - `public/uploads/photos/` exists and is writable (0755)

3. **Leave `config/config.php` out of Master.** The Master holds no credentials.
   Each church clone gets its own config in Part C. This is what makes updates
   safe — you can re-copy Master's code over a church without ever touching their
   config or data.

Master is now ready to clone.

---

## 5. Part C — Clone a new church from Master

Repeat these six steps per church. Budget ~10 minutes.

### C.1 Create the subdomain
**cPanel → Domains → Create a New Domain.**
- Subdomain: `<slug>.churchplus.io` (e.g. `cornerstone.churchplus.io`)
- Document root: `~/churchplus/<slug>/public`
- Enable **AutoSSL**.

### C.2 Create the church database
**cPanel → MySQL Databases.**
- Database: `churchplus_<slug>`
- User: `churchplus_<slug>` with a strong **generated** password (save it)
- Grant that user **ALL privileges on that database only**
- **phpMyAdmin → Import** `sql/schema.sql` into the new database.

### C.3 Copy the code from Master
In the **File Manager** (or shell), copy the Master folder to the church's folder:

```bash
cp -a ~/churchplus/churchplus-master ~/churchplus/<slug>
```

### C.4 Write the church's config
```bash
cd ~/churchplus/<slug>
cp config/config.example.php config/config.php
php -r "echo bin2hex(random_bytes(32));"   # copy this value
nano config/config.php
```
Set, using the **full prefixed** names from C.2:
- `db.name`, `db.user`, `db.pass`
- `app.base_url` = `https://<slug>.churchplus.io`
- `security.app_key` = the 64-char value you just generated (unique per church)

### C.5 Create the church's first admin
```bash
php scripts/seed_admin.php "Pastor Jane Doe" jane@example.org "A-Strong-Password"
```
(If shell isn't available, use the browser fallback in the Appendix.)

### C.6 Register the church in the control plane
**phpMyAdmin → `churchplus_admin` → `churches` → Insert** a row with the slug,
subdomain, database name, plan, and contact info.

### Hand-off
Send the church admin their URL, email, and temporary password, and have them
change it at first sign-in (**Staff Accounts → Reset password**). Suggested first
run: **Settings** (church name/address, upload logo) → **People** → group into
**Families** → adjust **Funds** → record first **Gifts** → take first
**Attendance**.

---

## 6. Part D — The KFCC demo (already live)

KFCC is already installed and operational at `kfcc.churchplus.io`. It has one
important difference from a textbook install, documented here so future-you
remembers.

### How it's wired
- Install path: `~/churchplus/kfcc.churchplus.io/` containing the usual
  `config/ public/ scripts/ sql/ src/`.
- **The document root could not be repointed** to `public/` on this account, so a
  **root `.htaccess` workaround** routes everything into `public/`. That file:
  - blocks direct access to `config/`, `src/`, `sql/`, `scripts/`
  - sets `DirectoryIndex public/index.php`
  - rewrites all other requests into `public/`
  - turns off directory indexing
- The database is `churchplus_<...>` with the **account-prefixed** name in
  `config/config.php`.

### The one rule for KFCC updates
When you apply a release to KFCC, **never overwrite the root `.htaccess`** — it's
the custom routing that makes this install work. Releases only touch `src/`,
`public/*.php`, `public/includes/`, and `public/assets/`. See Part E.

### Demo data
KFCC is a sandbox. It's fine to add, edit, and delete freely; demo data is wiped
on each major update. Keep the security notice in front of testers: the system
has real protections, but it's a shared demo — **fictional data only, no real
personal or financial information.**

---

## 7. Part E — Applying updates to everything

Setup is one-time. Updates only ever replace **code**, never config or data.

**Always replaced by an update:** `src/`, `public/*.php`, `public/includes/`,
`public/assets/`, `scripts/`.

**Never touched:** `config/config.php`, `sessions/`, `public/uploads/`, a
church's database, and KFCC's custom **root `.htaccess`**.

### Per church (and Master), ~2 minutes each
1. **Back up first** — cPanel → Backup → download the church's MySQL database.
   (Skip for Master; it has no database.)
2. Upload the release zip into the church's install folder.
3. Right-click → **Extract** → confirm **overwrite**. (Extract merges folders and
   only replaces files present in the zip, so it cannot clobber config, uploads,
   or .htaccess.)
4. If the release includes `sql/migrations/NNN.sql`, run it: phpMyAdmin → the
   church's database → **Import**. Migrations only **add** tables/columns; they
   never rewrite existing records. Run them in number order if a church skipped one.
5. Delete the zip, sign in, spot-check the dashboard.

Always update **churchplus-master** too (step 2–3 only) so the next clone ships
current.

> The current 1.2 release needs **no migration** — it's code-only.

---

## 8. Part F — Operations

**Backups** — nightly, per church, kept separate:
```bash
mysqldump -u churchplus_<slug> -p churchplus_<slug> > /backups/<slug>-db-$(date +%F).sql
```

**Suspending a church** (pause / non-payment) — set `status = 'suspended'` in the
control plane, or temporarily swap `public/index.php` for a notice. Data is
untouched.

**Removing a church** — final `mysqldump`, send the export to the church for their
records, then drop the database and MySQL user, remove the subdomain, and delete
`~/churchplus/<slug>`.

**Security posture (shipping):** bcrypt password hashing, login lockout after
repeated failures, CSRF tokens on every form, prepared statements everywhere,
session idle timeout, a private session store, script-blocked uploads, and a full
audit log. Per-church `app_key` and database isolation keep tenants separate.
For a public demo, reinforce the **no-real-data** notice — isolation protects
churches from each other, not testers from their own entries.

---

## 9. Appendix

### Config reference (`config/config.php`)
- `db.host` — usually `localhost`
- `db.name` / `db.user` / `db.pass` — the **prefixed** church DB and user
- `app.base_url` — full https URL, no trailing slash
- `app.timezone` — e.g. `America/Chicago`
- `security.app_key` — unique 64-hex string per church (`bin2hex(random_bytes(32))`)

### Browser fallback for the first admin (no shell access)
Temporarily place a one-off `public/first_admin.php` that calls the same code as
`scripts/seed_admin.php`, load it once in the browser, confirm the admin was
created, then **delete the file immediately**. Never leave it on a live site.

### Troubleshooting
- **"Session expired" / 419 on login** — the `sessions/` dir isn't writable or
  isn't private. Confirm it exists above the web root and is writable. (Fixed in
  1.1; included here.)
- **Blank page / 500 after deploy** — check the church's error log in cPanel.
  Most often a `config.php` typo or an unprefixed DB name.
- **CSV import "incorrect date value"** — fixed in 1.2; the importer now converts
  MM/DD/YYYY and other common formats automatically.
- **Logo looks wrong** — brand art lives in `public/assets/brand-login.png` and
  `brand-topbar.png`; replacing those two files reskins the app with no code change.

### What's next (roadmap)
See `ROADMAP.md` for the planned phased releases — member portal, online giving
(Stripe + text-to-give), email/accounting/payroll integrations, custom fields,
groups & ministries, advanced search, duplicate merge, and a congregation map.
These are **not** in this build; they ship as future numbered releases applied
exactly as in Part E.
