# The Daily Pour — Marketing Automation Deployment **Owner:** Annie (Marketing Lead) **Infra:** Sam (GitLab CI + Kestra) **Target deploy date:** Sunday, August 17, 2026 **GitLab repo:** https://gitlab.com/samueljamesinc/daily-pour-marketing (LIVE) **Code-server:** https://code.snsnetlabs.com (LXC 304, Fedora 44, pve3) --- ## What This Is Automated daily social media promotion for The Daily Pour, powered by Kestra workflows. Annie manages the content calendar and approvals; the system handles content generation, hashtag selection, platform-specific formatting, and publishing — zero daily effort once configured. --- ## Architecture ``` ┌──────────────┐ ┌───────────────┐ ┌──────────────┐ ┌─────────────┐ ┌────────────┐ │ Pre-Flight │ ──▶ │ Content Gen │ ──▶ │ Hashtag │ ──▶ │ Platform │ ──▶ │ Publish │ │ Checks │ │ (ChatGPT / │ │ Engine │ │ Formatter │ │ (Buffer │ │ │ │ Ollama) │ │ │ │ │ │ API) │ └──────────────┘ └───────────────┘ └──────────────┘ └─────────────┘ └────────────┘ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ APIs alive? Weather + Tier 1-4 + Per-platform One API → Drive access? day theme → RiteKit trending + character limits, FB + IG + Platforms up? brand voice → rotation logic → image specs, TikTok + Content exists? caption draft anti-shadowban hashtag counts LinkedIn + Google Biz ``` ### Data Flow (detailed) ``` ┌─────────────────────────────────────────────────────┐ │ GitLab.com (Source of Truth) │ │ daily-pour-marketing repo │ │ ├── workflows/ (Kestra YAML) │ │ ├── config/ (brand voice, hashtags, locations) │ │ └── CI Variables (secrets, tokens) │ └───────────────────────┬─────────────────────────────┘ │ git sync (every 15 min) ▼ ┌──────────────┐ ┌─────────────────────────────┐ │ Google Drive │◀────read────▶│ Kestra (Execution) │ │ (60GB) │ │ 192.168.122.71 │ │ ├── photos/ │ │ │ │ ├── videos/ │ │ Cron triggers: │ │ └── logos/ │ │ • 5:30 AM — preflight │ └──────────────┘ │ • 6:00 AM — daily post │ │ • Sun 8PM — weekly gen │ └──────────────┬──────────────┘ │ ┌──────────────┼──────────────┐ ▼ ▼ ▼ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐ │ OpenWeather │ │ ChatGPT / │ │ RiteKit │ │ API │ │ Ollama │ │ (trending │ │ (weather) │ │ (captions) │ │ hashtags) │ └──────────────┘ └─────────────┘ └──────────────┘ │ ▼ ┌─────────────────────────────┐ │ Buffer API │ │ (single publishing │ │ layer for all 5 │ │ platforms) │ └──────────────┬──────────────┘ │ ┌────────┬───────┬───────┼───────┬────────┐ ▼ ▼ ▼ ▼ ▼ │ Facebook Instagram TikTok LinkedIn Google │ Business │ │ ┌────────────────────────────────┘ ▼ ┌─────────────────────────────┐ │ Kestra plugin-meta (backup) │ │ Direct FB + IG posting │ │ (if Buffer doesn't cover │ │ a specific need) │ └─────────────────────────────┘ ``` --- ## Publishing Layer: Buffer API **Why Buffer instead of 5 separate platform APIs:** - One integration → posts to all 5 platforms - Handles format differences (image sizes, character limits, hashtag placement) - Built-in scheduling, analytics, engagement inbox - Free tier: 3 channels, 10 posts/channel/month - Paid: ~$6/channel/month ($30/mo for all 5 — cheaper than dev time on 5 APIs) - Has an MCP server (AI agents can post directly) - REST API: `https://api.bufferapp.com/1/updates/create.json` **Fallback:** Kestra `plugin-meta` for direct Facebook + Instagram posting if Buffer doesn't cover a specific need (carousels, reels with specific metadata, etc.) **Setup:** 1. Sign up at buffer.com 2. Connect all 5 social accounts 3. Generate API token 4. Add `BUFFER_ACCESS_TOKEN` to GitLab CI Variables + Kestra namespace secrets --- ## Hashtag Engine ### Strategy: 4-Tier System with Rotation | Tier | What | Example | Rotation | |------|------|---------|----------| | 1 — Brand | Always present | #TheDailyPour #DailyPourCoffee | Never changes | | 2 — Category | Broad reach | #CoffeeAddict #SpecialtyCoffee #LocalCoffee | 3 sets, cycle every 3 days | | 3 — Day Theme | Matches daily rotation | #MenuMonday #BehindTheScenes #FridayFeels | Changes daily | | 4 — Dynamic | Fresh per post | Weather-based, trending, time-of-day | Every post (RiteKit + weather API) | ### Platform Limits (enforced by the formatter) | Platform | Optimal Count | Format | |----------|---------------|--------| | Instagram | 20-25 | In caption or first comment (separated by dots) | | TikTok | 5-8 | In caption only (algorithm punishes excess) | | Facebook | 3-5 | In caption, early | | LinkedIn | 3-5 | Final line, professional tone only | | Google Business | 2-3 | In description, minimal | ### Anti-Shadowban Rules - Never repeat the same Tier 2 set within 7 days on the same platform - Rotate Tier 2 pools: A → B → C → A (3-day cycle) - Tier 4 (trending) is always unique — pulled fresh per post - Track hashtag history in Kestra (7-day lookback before selecting) ### Trending Hashtag Sources - **RiteKit API** (https://ritekit.com) — give it post text, returns optimized hashtags based on real-time popularity. 100 free calls/month. - **Apify TikTok Scraper** — pulls TikTok Creative Center trending hashtags daily - **OpenWeatherMap** — weather-reactive hashtags (#SummerVibes, #CozyMorning, etc.) - **Day-of-week cultural moments** — #MondayMotivation, #FridayFeels, #SundayFunday ### Config Files ``` config/ ├── hashtag-rotation.yml ← Tier 2 pools (A/B/C), Tier 3 by day, rotation state ├── hashtag-limits.yml ← Per-platform max counts + format rules └── hashtag-banned.yml ← Hashtags known to be suppressed/banned (check monthly) content/templates/ └── hashtags.md ← Master reference (all tiers defined, human-readable) ``` --- ## Pre-Requisites Checklist (Updated) ### Infrastructure (Sam) — ✅ = Done - [x] **GitLab.com repo** — https://gitlab.com/samueljamesinc/daily-pour-marketing - [x] **Kestra** running and healthy — 192.168.122.71:8080 - [x] **Code-server** — LXC 304, Fedora 44, code.snsnetlabs.com - [x] **GitLab SSH** from code-server working - [x] **OpenWeatherMap API** — key active, tested - [x] **OpenAI API** — key active, tested - [x] **Google Drive OAuth** — refresh token working, tested upload/list/download - [x] **Pre-flight checks flow** — tested, all passing - [x] **Weather caption flow** — tested, generating captions - [ ] **Buffer account** — sign up, connect platforms, get API token - [ ] **RiteKit account** — sign up, get API key (free tier) - [ ] **Kestra ↔ GitLab sync flow** — auto-pull workflows from repo - [ ] **Publish GCP OAuth app** (Testing → Production) — prevent 7-day token expiry ### Platform Accounts (Sam or Annie) - [ ] **Google Business Profile** created for The Daily Pour - [ ] **Facebook Business Page** created - [ ] **Instagram Business Account** connected to Facebook page - [ ] **TikTok Business Account** created - [ ] **LinkedIn Company Page** created (SnS Hospitality Group or The Daily Pour) ### Content Library (Annie — ongoing, seed before launch) - [ ] **Logos** — PNG (dark/light/icon), SVG source - [ ] **Product photos** — at least 10 menu item shots - [ ] **Trailer photos** — exterior, window, signage (even mockups/renders to start) - [ ] **Video clips** (optional for launch) — espresso pulls, morning prep, b-roll - [x] **Brand voice doc** — committed to repo - [x] **Hashtag sets** — committed to repo (expand with Tier 2/3/4 config) - [x] **Rules doc** — committed to repo - [x] **Platform config** — committed to repo --- ## Kestra Workflows (Updated) | # | Workflow | Trigger | What it does | Status | |---|---------|---------|--------------|--------| | 0 | `preflight_checks` | Before every deployment | Validates APIs, platforms, Drive, content exist | ✅ LIVE | | 1 | `weather_caption_test` | Manual / Cron | Weather + ChatGPT → generates caption | ✅ LIVE | | 2 | `daily_post_rotation` | Cron 6:00 AM daily | Preflight → content gen → hashtags → format → publish via Buffer | TODO | | 3 | `weekly_content_gen` | Cron Sunday 8 PM | LLM generates 7 draft captions + hashtag sets for the week | TODO | | 4 | `location_announce` | Manual or webhook | New location signed → announcement series across all platforms | TODO | | 5 | `hiring_post` | Webhook from Plane | Hiring task created → generates + posts hiring content | TODO | | 6 | `review_responder` | Cron daily 9 AM | Pulls Google reviews → drafts responses → Annie approves | TODO | | 7 | `engagement_repost` | Cron 2x/week | Scans for UGC/mentions → queues for repost with credit | TODO | | 8 | `hashtag_performance` | Cron Monday 9 AM | Pulls engagement data, correlates with hashtags, recommends rotations | TODO | --- ## Content Rotation (daily theme) | Day | Type | Platforms | Tier 3 Hashtags | |-----|------|-----------|-----------------| | Mon | Menu highlight | All | #MenuMonday #CoffeeMagic #MondayMotivation | | Tue | Behind the scenes | IG, TikTok, FB | #BehindTheScenes #MorningShift #BaristaDiary | | Wed | Testimonial / review | FB, Google, LinkedIn | #CustomerLove #TestimonialTuesday #FiveStars | | Thu | Educational / fun fact | All | #CoffeeEd #DidYouKnow #ThursdayThoughts | | Fri | Weekend teaser + location | All | #FridayFeels #WeekendPlans #CoffeeNearMe | | Sat | Live energy / "we're open" | IG Stories, TikTok, FB | #WeAreOpen #SaturdayVibes #LiveEnergy | | Sun | Community / gratitude | FB, LinkedIn, IG | #CommunityLove #SundayBrunch #Grateful | --- ## GitLab Repo Structure (Updated) ``` daily-pour-marketing/ ← https://gitlab.com/samueljamesinc/daily-pour-marketing ├── .gitlab-ci.yml ← Validates YAML + syncs to Kestra ├── README.md ├── content/ │ ├── logos/ │ ├── photos/{products,trailer,team,customers}/ │ ├── videos/{reels,tiktok,stories}/ │ └── templates/ │ ├── captions/ ← Per-day caption templates │ ├── hashtags.md ← Master hashtag reference │ └── canva/ ← Brand templates ├── config/ │ ├── brand-voice.md ← Annie's tone guide │ ├── colors.md ← Brand palette │ ├── rules.md ← What to never post │ ├── platforms.yml ← Platform config (no secrets) │ ├── locations.yml ← Active locations + hours │ ├── hashtag-rotation.yml ← NEW: Tier 2 pools, rotation state │ ├── hashtag-limits.yml ← NEW: Per-platform counts + format │ └── hashtag-banned.yml ← NEW: Suppressed/banned hashtags ├── workflows/ │ ├── preflight-checks.yml ← ✅ LIVE │ ├── daily-post-rotation.yml ← TODO (full pipeline) │ ├── weather-reactive.yml │ ├── weekly-content-gen.yml │ ├── location-announce.yml │ ├── hiring-post.yml │ ├── review-responder.yml │ ├── engagement-repost.yml │ └── hashtag-performance.yml ← NEW: Weekly analytics └── scripts/ ├── hashtag-selector.py ← NEW: Tier selection + rotation logic ├── hashtag-validator.py ← NEW: Validates sets before posting └── platform-formatter.py ← NEW: Formats caption + hashtags per platform ``` --- ## Secrets (GitLab CI Variables + Kestra Namespace Files) | Variable | Location | Status | |----------|----------|--------| | `KESTRA_API_USER` | GitLab CI | ✅ Set | | `KESTRA_API_PASSWORD` | GitLab CI | ✅ Set | | `KESTRA_URL` | GitLab CI | ✅ Set | | `OPENAI_API_KEY` | GitLab CI + Kestra | ✅ Set | | `OPENWEATHER_API_KEY` | GitLab CI + Kestra | ✅ Set | | `GOOGLE_DRIVE_REFRESH_TOKEN` | Kestra namespace | ✅ Set (publish GCP app to prevent 7-day expiry) | | `GOOGLE_DRIVE_CLIENT_ID` | Kestra namespace | ✅ Set | | `GOOGLE_DRIVE_CLIENT_SECRET` | Kestra namespace | ✅ Set | | `BUFFER_ACCESS_TOKEN` | GitLab CI + Kestra | ⬜ TODO (after Buffer signup) | | `RITEKIT_API_KEY` | GitLab CI + Kestra | ⬜ TODO (after RiteKit signup) | | `META_ACCESS_TOKEN` | GitLab CI + Kestra | ⬜ TODO (after FB/IG app approval) | | `TIKTOK_ACCESS_TOKEN` | GitLab CI + Kestra | ⬜ TODO (after TikTok developer app) | | `LINKEDIN_ACCESS_TOKEN` | GitLab CI + Kestra | ⬜ TODO (after LinkedIn API access) | | `GOOGLE_BUSINESS_TOKEN` | GitLab CI + Kestra | ⬜ TODO (after GBP API setup) | --- ## Tech Stack | Layer | Tool | Cost | Role | |-------|------|------|------| | Orchestration | Kestra (self-hosted) | Free | Cron schedules, task coordination, retry logic | | Source control | GitLab.com | Free | Workflow YAML, config, content templates | | Dev environment | code-server (LXC 304) | Free | Browser IDE for editing flows + scripts | | Content storage | Google Drive (60GB) | Free | Photos, videos, logos — large binary media | | Content generation | ChatGPT (OpenAI API) | Pay-per-use (~$0.01/caption) | Caption drafting, hashtag brainstorming | | Local LLM (backup) | Ollama (192.168.122.20) | Free | Fallback caption gen, no API cost | | Weather data | OpenWeatherMap | Free (1000 calls/day) | Weather-reactive content | | Trending hashtags | RiteKit | Free (100 calls/mo) | Real-time hashtag optimization | | TikTok trends | Apify scraper | Pay-per-run (pennies) | TikTok Creative Center trending data | | Publishing | Buffer API | Free–$30/mo | Single API → all 5 platforms | | Publishing (backup) | Kestra plugin-meta | Free | Direct FB + IG posting | | Project management | Plane CE | Free (self-hosted) | Annie's task board, hiring triggers | --- ## Deployment Steps (Updated) ### Phase 1: Foundation (Done) 1. ~~Create GitLab repo~~ ✅ 2. ~~Push scaffold~~ ✅ 3. ~~Add CI variables (Kestra, OpenAI, OpenWeather)~~ ✅ 4. ~~Build + test preflight checks~~ ✅ 5. ~~Build + test weather caption flow~~ ✅ ### Phase 2: Publishing Pipeline (This Week) 6. Sign up for Buffer → connect platforms → add API token 7. Sign up for RiteKit → get API key 8. Build `hashtag-rotation.yml` config 9. Build `hashtag-selector.py` script (Tier 1-4 + rotation logic) 10. Build `platform-formatter.py` (per-platform caption + hashtag assembly) 11. Build full `daily-post-rotation` workflow (preflight → gen → hashtags → format → Buffer) 12. Test end-to-end: one real post on one platform ### Phase 3: Content & Handoff (Before Launch) 13. Seed content library (10+ photos, 7 caption templates) 14. Annie reviews brand voice + hashtag sets 15. Enable cron schedules 16. Set up Kestra ↔ GitLab sync (auto-pull from repo every 15 min) 17. Publish GCP OAuth app (prevent token expiry) ### Phase 4: Analytics & Optimization (After Launch) 18. Build `hashtag-performance` weekly analytics workflow 19. Set up A/B testing framework (same content, different hashtag sets) 20. Connect Buffer analytics → Kestra for automated optimization 21. Add Apify TikTok trending scraper to daily pipeline --- ## Decision Framework Score | Gate | Score | Reason | |------|-------|--------| | Time | 5 | Zero daily posting effort once live — fully automated | | Net Worth | 4 | Consistent presence builds brand → more customers at trailer | | Freedom | 5 | Marketing runs without Sam; scales across all trailers | | **Total** | **14** | Execute | --- ## Repos to Evaluate (from research) | Repo | What | Action | |------|------|--------| | [charlie947/social-media-skills](https://github.com/charlie947/social-media-skills) | Claude skills behind 350K-follower creator | Fork `post-writer` + `post-scorer` for caption logic | | [rampstackco/claude-skills](https://github.com/rampstackco/claude-skills) | 65 Claude skills including SEO/content | Adapt keyword research → hashtag research | --- *Created 2026-08-13. Updated 2026-08-14 with Buffer publishing layer, hashtag engine, and research findings.*