Create instagram-automation-session-notes.md via n8n
This commit is contained in:
parent
dfbabd73ed
commit
6f81771dd8
165
PBS/Tech/Sessions/instagram-automation-session-notes.md
Normal file
165
PBS/Tech/Sessions/instagram-automation-session-notes.md
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
---
|
||||||
|
project: instagram-automation-session-notes
|
||||||
|
type: session-notes
|
||||||
|
status: active
|
||||||
|
tags:
|
||||||
|
- pbs
|
||||||
|
- n8n
|
||||||
|
- instagram
|
||||||
|
- mysql
|
||||||
|
- wordpress
|
||||||
|
- automation
|
||||||
|
- docker
|
||||||
|
created: 2026-03-16
|
||||||
|
updated: 2026-03-16
|
||||||
|
path: PBS/Tech/Sessions/
|
||||||
|
---
|
||||||
|
|
||||||
|
# Session Notes — MySQL Schema, Error Checking & The Great Lockout of 2026
|
||||||
|
|
||||||
|
## ✅ Accomplished This Session
|
||||||
|
|
||||||
|
### Error Checking — Instagram Reply Workflow
|
||||||
|
All four error checks are now wired to Notify Travis → Google Chat:
|
||||||
|
|
||||||
|
- ✅ Subscribe check notification
|
||||||
|
- ✅ Hash verification failure notification (with ⛔ alert level)
|
||||||
|
- ✅ Empty table lookup notification (includes Reel ID, commenter, comment text)
|
||||||
|
- ✅ Keyword not matched notification
|
||||||
|
|
||||||
|
**Key learnings:**
|
||||||
|
- n8n "Always Output Data" needed on MySQL node so IF node can evaluate empty results
|
||||||
|
- When "Always Output Data" is on, check `$('node').first().json.id` exists instead of `length > 0` (length returns 1 for empty item)
|
||||||
|
- Google Chat HTTP Request node must use "Using Fields Below" mode, not raw JSON — literal newlines from expressions break JSON
|
||||||
|
- Build message strings as single `={{ }}` expression using `+` concatenation to keep `\n` as escaped characters
|
||||||
|
- `$now.toFormat('MMM dd, HH:mm:ss')` works in both test and live contexts (unlike `$execution.startedAt`)
|
||||||
|
- Timestamp and title passed from calling workflow, Notify Travis just passes them through
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### MySQL Schema — New Tables Created
|
||||||
|
|
||||||
|
**`pbs_recipes`:**
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS pbs_recipes (
|
||||||
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
post_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
title VARCHAR(500) NOT NULL,
|
||||||
|
url VARCHAR(500) NOT NULL,
|
||||||
|
keyword VARCHAR(100) NOT NULL,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY (post_id)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**`instagram_posts`:**
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS instagram_posts (
|
||||||
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
reel_id VARCHAR(50) NOT NULL,
|
||||||
|
post_id BIGINT UNSIGNED NULL,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
UNIQUE KEY (reel_id),
|
||||||
|
FOREIGN KEY (post_id) REFERENCES pbs_recipes(post_id)
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key decisions:**
|
||||||
|
- `post_id` is nullable in `instagram_posts` — NULL means unmatched reel, not an error
|
||||||
|
- `reel_id` stored as VARCHAR not BIGINT (Instagram ID integer overflow issue)
|
||||||
|
- Normalized schema — keyword and URL live in `pbs_recipes` only, JOIN at query time
|
||||||
|
- Staying on shared MySQL instance — at current scale (2k/month, 10-20 replies) separate instance is overkill
|
||||||
|
- phpMyAdmin added back to Docker Compose for direct MySQL access
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### WordPress Publish Webhook — Proof of Concept Complete
|
||||||
|
- WPCode Lite snippet fires on post publish (admin only)
|
||||||
|
- Payload: post_id, title, url, tags, categories
|
||||||
|
- HMAC signature verification via X-PBS-Signature header
|
||||||
|
- Raw body passed via X-PBS-Body header (base64 encoded) for exact signature verification
|
||||||
|
- n8n Code node verifies signature before processing
|
||||||
|
- Ready to wire into `pbs_recipes` table insert workflow
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Architecture Decision — Reply Workflow Refactor
|
||||||
|
Current two-table lookup + merge is being replaced with:
|
||||||
|
- Single `instagram_posts` lookup only
|
||||||
|
- URL stored directly in `instagram_posts` (populated at reel insert time from `pbs_recipes`)
|
||||||
|
- Simpler, faster, fewer failure points
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 The Great WordPress Lockout of 2026
|
||||||
|
|
||||||
|
**What happened:** Wordfence locked out staging WP admin. Unlock email never arrived.
|
||||||
|
|
||||||
|
**What we tried (none of it worked):**
|
||||||
|
- WP-CLI wf:unblock-ip command (not a registered command)
|
||||||
|
- Clearing wp_options Wordfence entries in MySQL
|
||||||
|
- Disabling Wordfence plugin
|
||||||
|
- Restarting WordPress container
|
||||||
|
- Deleting wflogs directory
|
||||||
|
|
||||||
|
**Root cause discovered:**
|
||||||
|
Wordfence WAF runs as a PHP auto_prepend_file — completely independent of the plugin being active. Found in .htaccess and wordfence-waf.php in WordPress root.
|
||||||
|
|
||||||
|
**Actual fix:** Wrong email address on the admin account. Changed it, logged right in. 🤦
|
||||||
|
|
||||||
|
**Real lesson learned:** Read the error message carefully before spending an hour troubleshooting! 😄
|
||||||
|
|
||||||
|
**Lockout duration if we hadn't figured it out:** 1 MONTH
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Runbook Addition — WordPress Lockout Recovery
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get into WordPress container
|
||||||
|
docker exec -it wordpress bash
|
||||||
|
cd /var/www/html
|
||||||
|
|
||||||
|
# List all users
|
||||||
|
wp --allow-root user list
|
||||||
|
|
||||||
|
# Reset password by username
|
||||||
|
wp --allow-root user update admin --user_pass=newpassword
|
||||||
|
|
||||||
|
# Reset password by email
|
||||||
|
wp --allow-root user update user@email.com --user_pass=newpassword
|
||||||
|
|
||||||
|
# If WAF is blocking login page independently of plugin:
|
||||||
|
# 1. Remove Wordfence WAF block from .htaccess
|
||||||
|
# 2. Rename wordfence-waf.php to wordfence-waf.php.disabled
|
||||||
|
# 3. docker restart wordpress
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔜 Next Steps
|
||||||
|
|
||||||
|
- [ ] Wire WordPress publish webhook → n8n workflow → insert into `pbs_recipes`
|
||||||
|
- [ ] Build one-time migration workflow — n8n datatables → MySQL
|
||||||
|
- [ ] Finish reply workflow refactor — remove Merge node, single `instagram_posts` lookup
|
||||||
|
- [ ] Fix production WordPress admin email (same issue exists there!)
|
||||||
|
- [ ] Deploy all changes to production once staging is verified
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Notes
|
||||||
|
|
||||||
|
- All development on staging (staging.plantbasedsoutherner.com)
|
||||||
|
- n8n datatables to be retired once MySQL migration complete
|
||||||
|
- Foreign key constraint requires `pbs_recipes` record to exist before `instagram_posts` insert
|
||||||
|
- Use `WHERE post_id IS NULL` query to find unmatched reels for Content Hub dashboard
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last Updated: March 16, 2026*
|
||||||
|
*Maintained by: Travis*
|
||||||
|
*Project: Plant Based Southerner — Instagram Automation*
|
||||||
Loading…
Reference in New Issue
Block a user