TravelTamers.com
TravelTamers is the operating platform I wrote to run a working travel agency, and it is the largest and longest-running piece of software I currently maintain, and also the one that most of my electricity bill goes toward. It is made up of five interconnected applications, one hundred and nineteen Postgres tables across three databases, roughly sixty automations in n8n, and a conversational concierge named Miles, and every piece of it runs on the same rented VPS. I started it in the summer of 2023 as a single Hono endpoint against one Postgres table, and I have been adding to it, more or less without interruption, ever since.
The Five Applications
1. Marketing Site
Astro 5 + React 19 + Tailwind CSS 4. Static site with React "islands" for interactive components. 43 partner pages, 25 destinations, 12 experiences, blog with category filtering, and a group trips calculator. Self-hosted fonts. GSAP animations. Pagefind search. Auto-generated sitemap and RSS feed. Served via Nginx with long-term caching on _astro/ assets.
2. Hono API Server
Hono 4.7 + TypeScript + Drizzle ORM + PostgreSQL. 33 routers mounted on a single instance. Three auth domains: public (Slack events, Miles chat, forms), internal services (X-Webhook-Secret), and authenticated API (X-API-Key or Bearer). Every input validated with Zod schemas. Custom error classes. Timing-safe secret comparison on all webhooks. Redis-backed rate limiting with in-memory fallback. Idempotency middleware via SHA-256 hash + Redis SET NX EX.
// 33 routers across 8 domains — integrations/src/index.ts
app.route('/api/companies', companies)
app.route('/api/contacts', contacts)
app.route('/api/deals', deals)
app.route('/api/bookings', bookings)
app.route('/api/buddy', milesChat)
app.route('/api/vendors', vendors)
app.route('/api/commissions', commissions)
app.route('/api/intelligence', intelligence)
app.route('/api/analytics', analytics)
// ... 24 more routers
3. Miles — AI Concierge
Claude API with Ollama fallback. A chat widget embedded across the site. Handles travel inquiries with a warm, knowledgeable personality. Auto-detects when a user has provided enough info (name, email, phone) and silently fills in the contact form. Falls back to Ollama (llama3.2:3b on the VPS) when Claude is unavailable. Context-aware responses based on the page the user is visiting.
Miles is the concierge who does not require me to be standing by. A visitor can ask about Japan cherry blossom cruises while I am occupied elsewhere, and Miles will research the question via Perplexity, propose three itinerary options, and hand the completed thread off into a Slack channel with the contact form already filled in.
4. Nexus CRM
Fastify 5 + React 19 + PostgreSQL + Redis + BullMQ. A custom CRM with 54 tables, 5-tier RBAC, pipeline management, email campaigns, service desk, knowledge base, and Socket.io real-time notifications. Runs across 5 Docker containers (API, web, worker, database, Redis). Fire-and-forget sync from the main API with 3-retry exponential backoff.
5. n8n Automations
60 workflows in 3 tiers. Tier 1 (launch blockers): social media content pipeline, form submission processing, Slack channel creation, passport expiry alerts. Tier 2 (first month): lead scoring, proposal generation, engagement tracking, departure date pipelines. Tier 3 (growth): trip recommendation engine, safety alerts, referral automation, quarterly newsletters. Integrations: Slack, Claude, Ollama, Perplexity, Replicate FLUX, Buffer, Google Calendar, Resend.
The Social Media Pipeline
Every day at 7am ET, a 7-step automated pipeline generates social media content:
- 1. Google Trends — Playwright screenshots the trending topics page.
- 2. Slack Feed — Aggregates 300+ daily messages from #feed-travel-news.
- 3. Ollama Filter — llama3.2:3b classifies and pre-filters stories.
- 4. Claude Selection — Selects the top 5 stories with editorial judgment.
- 5. Perplexity Research — Real-time web research to fact-check and enrich.
- 6. FLUX Images — Replicate generates 2 images per story (hero + alternate).
- 7. Platform Posts — 4 platform-specific posts per story (LinkedIn, Instagram, Facebook, X).
Database Architecture
Three PostgreSQL databases running on the VPS, each purpose-built:
- tt_fresh_db — 52 tables. Companies, contacts, deals, bookings, trips, experiences, vendors, commissions, analytics. 18 enum types.
- nexus_crm — 54 tables. CRM operations, marketing automation, service desk, knowledge base. 60 enum types. Dual soft-delete pattern.
- groups_db — 13 tables. Trip groups, itinerary legs, voting, comments, images, notifications.
Deployment
13 Docker containers on a single VPS. Ubuntu 24.04, 2 CPUs, 8GB RAM, 96GB disk. Traefik v3 handles reverse proxy and auto-SSL for 7 domains. GitHub Actions CI/CD with 5 parallel check jobs and automatic rollback if health checks fail. Backups every 6 hours with 30-day retention. fail2ban, UFW, key-only SSH, root login disabled.