Runbooks

kennjordan
← All sections

Runbooks

How to operate the platform. Living document.

Platform overview

Two sites on one VPS (154.66.198.194):

Both run PageMotor with shared plugin patterns. Isolated system users (cpd, docs), isolated databases (cpd_pm, docs_pm), isolated PHP-FPM pools.

Signing in

Admin URL: https://cpd.medilearn.africa/admin and https://documentation.mobilearn.africa/admin. Both Kenn and Hasmukh have admin accounts on each site. Initial passwords were set during infrastructure build and should be rotated on first login.

Retrieve initial passwords once via SSH: ssh s2l cat /root/cpd-docs-handover-20260423.txt

Rotating the Claude API key

Recommended every quarter or whenever the key might have been exposed.

  1. Go to console.anthropic.com → API Keys
  2. Generate a new key
  3. Sign in to cpd.medilearn.africa/admin/ai/
  4. Open Architect: Claude Settings, paste the new key, Save
  5. Revoke the old key in the Anthropic console
  6. Save the new key in Apple Passwords (title: MobiLearn CPD — Claude API)
The plugin reads the key from the admin option on every request — no server reload or cache clear needed.

Rotating the Vimeo API token

  1. Sign in to developer.vimeo.com/apps as the Mobilearn user
  2. Generate a new Personal Access Token with scopes: Public Private Video Files Edit
  3. Sign in to cpd.medilearn.africa/admin/plugins, go to EP Courses → Integrations
  4. Paste the new token, Save
  5. Revoke the old token on Vimeo

Adding a new course pathway

  1. Sign in at /admin/plugins, go to EP Courses → Manage Courses → + Add Course
  2. Fill title, slug, description, outcome
  3. Save, then click Lessons on the row
  4. + Add Lesson → paste a Vimeo URL → click Fetch from Vimeo → save
  5. Return to courses list → click Authorise (domain) to whitelist the embed
  6. Create a CMS page with

    Course not found.

    for the landing page

Featuring a new pathway on the home page

Edit /var/www/cpd/user-content/plugins/ep-cpd-home/plugin.php. In render_cpd_home(), add your new course slug and badge label where the featured cards are rendered.

Whitelisting new videos for cpd.medilearn.africa

When new MLUCT videos are added to Vimeo, they need the cpd.medilearn.africa domain added to their embed whitelist before they will play in the pathway modal.

Either add them one-by-one via the Vimeo video privacy settings, or batch-authorise via the EP Courses admin “Authorise cpd.medilearn.africa” button on the course row.

Re-running the Vimeo inventory audit

When the library grows, the taxonomy snapshot needs regenerating:

cd "~/Library/Mobile Documents/com~apple~CloudDocs/Claude Workspace/MobiLearn CPD/inventory"
# Run the audit script (saved separately; ask Claude to regenerate if missing)
# It produces raw_folders.json and taxonomy.json.
scp taxonomy.json s2l:/var/www/cpd/user-content/inventory-taxonomy.json

Viewing interview sessions

Each interview is logged in the pm_ep_cpd_interviews table. Useful columns: session_id, status (active/completed), profile (JSON), ip, created_at. Query via SSH:

ssh s2l mysql --defaults-extra-file=/etc/mysql/debian.cnf cpd_pm 
  -e "SELECT session_id, status, created_at, SUBSTRING(profile, 1, 100) FROM pm_ep_cpd_interviews ORDER BY id DESC LIMIT 20"

Adjusting rate limits

In /var/www/cpd/user-content/plugins/ep-cpd-interview/plugin.php, class constants:

  • MAX_MESSAGES — per interview (default 20)
  • MAX_INTERVIEWS_PER_IP_PER_DAY — per IP (default 10)

SSL certificate renewal

Handled automatically by certbot’s cron timer. Manual renew: ssh s2l certbot renew

Database backups

Not yet automated. For ad-hoc backup:

ssh s2l sh -c "mysqldump --defaults-extra-file=/etc/mysql/debian.cnf cpd_pm | gzip > /root/cpd_pm_$(date +%%Y%%m%%d).sql.gz"
scp s2l:/root/cpd_pm_*.sql.gz ~/Backups/

Recommended: set up a nightly cron for both cpd_pm and docs_pm, store in cloud storage.

System administration

File locations

  • /var/www/cpd/ — CPD PageMotor install
  • /var/www/docs/ — Docs PageMotor install
  • /etc/nginx/sites-enabled/{cpd,docs} — nginx vhosts
  • /etc/php/8.3/fpm/pool.d/{cpd,docs}.conf — FPM pool configs

Restarts

systemctl reload nginx         # nginx config change
systemctl reload php8.3-fpm    # PHP FPM change

Error logs

  • /var/www/cpd/php-errors.log — CPD site errors
  • /var/www/docs/php-errors.log — docs site errors
  • /var/log/nginx/error.log — nginx errors (shared)