FELLOWSHIP OF THE PLAGUE — CPANEL SETUP
Last Asylum: Plague / Server 345

Confirmed FOP address: https://fop.lastasylum345.com
Network base domain: lastasylum345.com
Future alliances use their alliance code as the subdomain. See MULTI-ALLIANCE.txt
for separate databases, sessions, leadership, and Discord connections per site.

WHAT YOU HAVE
An initial self-hosted PHP website with public recruitment/guides and a private
member community. Discord sign-in and email/password use the same account when
linked. Officers approve membership and manage content. Background checks import
selected Discord channels and RSS/Atom feeds into a review queue.

The package contains no real members, credentials, active codes, or game events.
It includes three optional alliance onboarding guides. Automatic game-stat
syncing and AI-written summaries are not implemented. These need a supported
game data source and an explicitly configured summarization service respectively.

REQUIREMENTS
- A domain or subdomain dedicated to the alliance, with a valid HTTPS certificate.
- PHP 8.3 or 8.4 (use your host's currently maintained patch release).
- PHP extensions: PDO, pdo_mysql, curl, mbstring, SimpleXML, OpenSSL, session.
- MySQL 8+ or MariaDB 10.6+ with an empty database and dedicated database user.
- PHP command-line access through cPanel Terminal/SSH or assistance from the host.
- cPanel Cron Jobs enabled; outbound HTTPS to Discord and approved feeds allowed.
- Outgoing PHP mail configured for your domain, with SPF/DKIM and working delivery.
- No Node.js server, Composer, WordPress, or paid cPanel app is required.

1. PUT FILES IN THE RIGHT PLACE
Upload/extract the fellowship-of-the-plague folder to a PRIVATE location, e.g.:
  /home/CPANEL_USER/fellowship-of-the-plague

Set the alliance domain's document root to:
  /home/CPANEL_USER/fellowship-of-the-plague/public

Only public/ should be web-accessible. Do not place config.php, app/, bin/, tests/,
or storage/ in a publicly served document root. The included .htaccess files add
protection, but are not a substitute for the correct document root. If your host
will not allow this structure, ask it to configure an appropriate document root
before uploading credentials. Serve this application at the domain root, not a
subfolder such as example.com/alliance.

Use cPanel Domains and SSL/TLS Status to activate the domain and HTTPS. Select PHP
8.3 or 8.4 in MultiPHP Manager. The app expects direct HTTPS at PHP; if the host
uses a reverse proxy, have it correctly supply HTTPS=on after TLS termination.
Do not blindly trust arbitrary forwarded headers.

2. CONFIGURE THE DATABASE AND EMAIL
In cPanel's database tools, create an empty database and a dedicated user. Grant
that user access to this database. Copy config.example.php to config.php, outside
public/, then edit:
- base_url: the exact HTTPS origin, without a trailing slash or subdirectory.
- db.dsn: mysql:host=localhost;dbname=YOUR_DATABASE;charset=utf8mb4
- db.user and db.password: your cPanel database credentials.
- mail_from: an actual sender on your domain.
- environment: production (leave it that way on the public host).
- mail_transport: mail.

Keep configuration readable only by the hosting account / PHP service. Never
send your cPanel password, Discord client secret, or bot token in ordinary chat.
The storage/ directory needs to be writable by PHP for the scheduled-job lock.

3. INITIALIZE AND CREATE YOUR R5
From the cPanel terminal:
  cd /home/CPANEL_USER/fellowship-of-the-plague
  /usr/local/bin/php bin/install.php
  /usr/local/bin/php bin/leader.php

The leader command prompts for email and game name. It creates the first R5 and
emails a password-setup link. There is no default password and public sign-up
never creates administrators. If delivery fails, fix mail and use Forgot password.

If cPanel uses a version-specific PHP binary, replace /usr/local/bin/php in every
command with the path your host supplies, such as:
  /usr/local/bin/ea-php84

Optionally publish the included onboarding guides:
  /usr/local/bin/php bin/starter-guides.php

Sign in as R5, complete your game profile, and create your alliance announcements.
R4 titles are editable. Support and morale titles in the list are suggestions.

4. CONNECT DISCORD SIGN-IN
Create an application in the Discord Developer Portal:
  https://discord.com/developers/applications

Under OAuth2, register this exact redirect URL, replacing the hostname:
  https://fop.lastasylum345.com/index.php?r=discord-callback

Set discord.client_id and discord.client_secret in private config.php.
The application requests only identify and email for sign-in. It does not request
permission to join servers or manage members. Discord identity is not proof of
in-game membership; new Discord users still wait for officer approval.

Existing email users should sign in first and select My profile > Link Discord.
The app never automatically merges accounts based only on a matching email.
Discord users with a verified email can choose Add password to receive a setup
link. If Discord does not supply an email, resolve that with the user before
offering email sign-in. Do not create duplicate accounts for an existing member.

5. CONNECT SELECTED DISCORD CHANNELS
In that application, create/configure a bot. Enable Message Content Intent, then
invite it only to your alliance Discord server. It needs View Channel and Read
Message History in the channels you choose. Do not grant Administrator, Manage
Roles, Kick Members, or permission to send messages: this importer does not need
them. Store its bot token and your Discord server ID in private config.php.

Tell members which channels are imported and how their posts will be used.
Use Officers > Sources & review queue > Add an approved source. Enter the channel
ID, intended content type, and audience. Officer-only channels must use Officers
only. Each imported message begins as an officer-only review draft, even when its
eventual audience is public. Publication is an explicit officer action.

If the game's official server provides an announcement channel that can be
followed, you can arrange for those announcements to appear in a designated
channel in your own server, then connect that channel. Access to your alliance
server does not grant access to the game's official Discord server.

The importer polls text channels every five minutes, including recent edits.
On first connection it reads up to the latest 100 messages; it does not import
an entire historical archive. Later it can catch up to 1,000 messages per run and
flags larger backlogs without advancing the checkpoint. Threads need their own
channel entries. Attachment-only messages are not ingested. Deletions and edits
outside the recent polling window need officer reconciliation on the website.
It does not send Discord messages or synchronize Discord roles.

6. ENABLE REGULAR CHECKS
In cPanel > Cron Jobs, run this every five minutes:
  */5 * * * * /usr/local/bin/php /home/CPANEL_USER/fellowship-of-the-plague/bin/update.php

Use your host's actual PHP binary path. Enable cPanel's Cron Email for failures if
you want host-level alerts; the website shows failed sources and overdue runs in
the officer area. The job writes a short result to stdout and returns nonzero for
source failures. It does not send alerts to Discord or members.

Discord sources are due every five minutes; RSS/Atom sources every six hours.
Known expiration times are processed on each run. Source checks deduplicate
items, preserve source links, and update the last-success time only after success.
Changed source text returns to review. A failed source does not get a fresh date.
An unchanged source preserves an officer's edited title/body.

Add actual HTTPS RSS/Atom feed URLs in the officer area. Arbitrary web pages are
not RSS feeds and will be marked as errors. No unverified news source is prewired.
RSS entries store short attributed excerpts and links, not full copied articles.
Imported codes and events need an officer to confirm dates, code text, and Server
345 relevance. Publication does not guarantee a gift code still redeems.

7. MEMBERSHIP AND INACTIVITY
Members register, verify email if using a separate login, and enter their game ID.
R4/R5 approve applications. Most members can be assigned R3. R1 distinguishes a
new member from inactivity; R2 remains available without invented restrictions.
Only R5 can appoint R4 officers. The R5 cannot be demoted through these controls.

Default review thresholds are 7 inactive days and a 3-day warning grace period.
These are editable starting values, not a claim about your existing policy.
Officers record last seen IN GAME, carry out any demotion in the game, update the
website rank, deliver the warning in game/Discord, and record that delivery here.
The site identifies overdue reviews. It never kicks or demotes players by itself.
Website/Discord activity is not treated as game activity. Unknown stays unknown.

8. BEFORE INVITING MEMBERS
- Confirm HTTPS and document-root isolation; visiting /config.php or /app/ on the
  public domain must never return private source or configuration.
- Verify email delivery and single-use verification/password-recovery links.
- Register a test member with each sign-in method, check pending status, approve
  it, link accounts, and confirm private/officer access boundaries.
- Run the update job once; check Last successful check and error messages.
- Add only approved source channels and review imported material before publishing.
- Review privacy text against actual hosting, retention, and alliance practices.
- Use cPanel backups for database and private files; test restoring a backup.

TESTING ALREADY PERFORMED
PHP 8.4 syntax checks and isolated SQLite HTTP integration tests cover registration,
verification, password reset, session invalidation, CSRF, stored-text escaping,
member approval, role boundaries, content visibility, imports, deduplication,
source edit review, SSRF URL restrictions, and expiry. Desktop and 390px mobile
views were inspected in a browser. Live MySQL/MariaDB, cPanel mail, Discord OAuth,
and real channel/feed polling still require verification on your actual host.
67 automated assertions passed in total, including a separate second-alliance
installation that rejected a copied leader session from the first alliance.

DOCUMENTATION
PHP selection: https://docs.cpanel.net/cpanel/software/multiphp-manager-for-cpanel/
Cron jobs: https://docs.cpanel.net/cpanel/advanced/cron-jobs/
Discord OAuth: https://docs.discord.com/developers/topics/oauth2
Discord permissions: https://docs.discord.com/developers/topics/permissions
Message content: https://docs.discord.com/developers/events/gateway
