A comprehensive tech news aggregation and newsletter platform built with Next.js 14. Delivers curated content from YouTube, Twitter/X, blogs, and Reddit directly to your inbox every morning.
- π° Multi-Source Aggregation: YouTube, RSS feeds, Reddit
- π·οΈ Smart Categorization: AI/ML, Web Dev, Mobile, DevOps, and 6 more categories
- π― Tag-Based Organization: Auto-extract tags (javascript, python, docker, etc.)
- π§ Beautiful Newsletters: HTML emails via Resend with category grouping
- π¨ Modern UI: Next.js 14 + Tailwind CSS + shadcn/ui
- π§ Admin Panel: Manual triggers for scraping and newsletter sending
- π³ Docker Ready: Complete Docker Compose setup
- Framework: Next.js 14 (App Router)
- Database: LibSQL (SQLite) with Drizzle ORM
- Email: Resend API
- Styling: Tailwind CSS + shadcn/ui
- Deployment: Docker Compose / Vercel
tech_upkeep/
βββ app/ # Next.js App Router
β βββ page.tsx # Landing page
β βββ admin/page.tsx # Admin dashboard
β βββ api/ # API routes
βββ lib/
β βββ db/ # Database (Drizzle ORM)
β βββ services/ # Aggregator, Email, Categorizer
βββ components/ui/ # shadcn/ui components
βββ docker-compose.yml # Docker setup
βββ .env.example # Environment template
1. Clone and Install
git clone <your-repo>
cd tech_upkeep
npm install2. Configure Environment
Copy .env.example to .env.local:
cp .env.example .env.localEdit .env.local:
DATABASE_URL=file:./data/tech-upkeep.db
RESEND_API_KEY=re_your_api_key_hereGet Resend API Key:
- Sign up at https://resend.com (free tier: 100 emails/day)
- Go to API Keys β Create API Key
- Copy and paste into
.env.local
3. Run Database Migrations
npm run db:generate
npm run db:push4. Start Development Server
npm run devVisit:
- Landing Page: http://localhost:3000
- Admin Panel: http://localhost:3000/admin
1. Update .env for Docker
DATABASE_URL=postgres://postgres:postgres@db:5432/tech_upkeep
RESEND_API_KEY=re_your_api_key_here2. Start with Docker Compose
docker-compose up --buildThis starts:
- Next.js app on
localhost:3000 - PostgreSQL on
localhost:5432
3. Stop Containers
docker-compose down- Go to https://resend.com
- Sign up (free tier: 100 emails/day, 3,000/month)
- Verify your email
For production:
- Go to Domains in Resend dashboard
- Add your domain (e.g.,
yourdomain.com) - Add DNS records as shown
- Wait for verification
- Go to API Keys
- Click Create API Key
- Name it "Tech Upkeep"
- Copy the key (starts with
re_) - Add to
.env.local:RESEND_API_KEY=re_xxxxxxxxxxxxx
Edit lib/services/email.ts line ~60:
from: 'Tech Upkeep <newsletter@yourdomain.com>', // Update thisFor development, use: newsletter@resend.dev
Access at http://localhost:3000/admin
Features:
- View Statistics: Users, content, newsletters
- Manual Scrape: Trigger content aggregation
- Send Newsletter: Send to all users immediately
- Real-time Feedback: See results of actions
Scrape Content:
- Fetches from RSS, YouTube, Reddit
- Categorizes and tags automatically
- Skips duplicates
Send Newsletter:
- Gets content from last 24 hours
- Generates HTML emails
- Sends to all active users
For production, set up cron jobs to automate:
Create vercel.json:
{
"crons": [
{
"path": "/api/admin/scrape",
"schedule": "0 6 * * *"
},
{
"path": "/api/admin/send-newsletter",
"schedule": "0 8 * * *"
}
]
}- Scrapes at 6 AM daily
- Sends newsletters at 8 AM daily
Use services like cron-job.org:
- Create account
- Add job:
POST https://yourdomain.com/api/admin/scrape - Schedule:
0 6 * * * - Repeat for newsletter endpoint
Add to Dockerfile:
RUN apt-get update && apt-get install -y cron
COPY crontab /etc/cron.d/tech-upkeep
RUN crontab /etc/cron.d/tech-upkeepCreate crontab file:
0 6 * * * curl -X POST http://localhost:3000/api/admin/scrape
0 8 * * * curl -X POST http://localhost:3000/api/admin/send-newsletter
Using Drizzle ORM with 8 tables:
- users - Email subscribers
- categories - 10 tech categories
- tags - Auto-extracted tags
- content - Aggregated news items
- contentTags - Content-Tag relationships
- userCategoryPreferences - User subscriptions
- userTagPreferences - User tag filters
- newsletterSends - Delivery tracking
# Generate migration after schema changes
npm run db:generate
# Apply migrations
npm run db:push
# Open Drizzle Studio (GUI)
npm run db:studioPOST /api/users/register- Register new subscriber
POST /api/admin/scrape- Trigger content aggregationPOST /api/admin/send-newsletter- Send newslettersGET /api/admin/stats- Get statistics
Currently aggregating from:
- RSS Feeds: Hacker News, TechCrunch, The Verge, Ars Technica
- Reddit: r/programming, r/technology, r/webdev, r/MachineLearning
- YouTube (optional): Y Combinator, Fireship, freeCodeCamp, The Net Ninja
- Get API key from https://console.cloud.google.com/
- Enable YouTube Data API v3
- Add to
.env.local:YOUTUBE_API_KEY=your_key_here
Content is auto-categorized into:
- AI & Machine Learning
- Web Development
- Mobile Development
- DevOps & Cloud
- Programming Languages
- Cybersecurity
- Data Science
- Open Source
- Tech Industry
- Developer Tools
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel
# Set environment variables in dashboarddocker build -t tech-upkeep .
docker run -p 3000:3000 --env-file .env tech-upkeepnpm run dev # Start dev server
npm run build # Build for production
npm start # Start production server
npm run lint # Lint code
npm run db:studio # Open database GUIEdit lib/services/aggregator.ts:
private rssFeeds = [
// Add new RSS feed
{ url: 'https://example.com/feed', name: 'Example', type: 'article' },
];Edit lib/services/email.ts β generateNewsletterHTML()
- Check
RESEND_API_KEYin.env.local - Verify domain in Resend dashboard
- Update
fromemail inlib/services/email.ts - Check Resend dashboard logs
rm -rf data/
npm run db:generate
npm run devdocker-compose down -v
docker-compose build --no-cache
docker-compose up| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | SQLite or PostgreSQL connection string |
RESEND_API_KEY |
Yes | Resend API key for emails |
YOUTUBE_API_KEY |
No | YouTube Data API v3 key |
OPENAI_API_KEY |
No | OpenAI API for enhanced categorization |
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
MIT
- Built with Next.js 14
- Email powered by Resend
- UI components from shadcn/ui
- Database with Drizzle ORM
Need Help? Check out CLAUDE.md for detailed architecture docs.