A modern podcast streaming platform with blog system, subscription management, merchandise store, and comprehensive admin dashboard. Built with React, TypeScript, and deployed on Vercel Edge Functions.
🌐 Live Demo: tendertalks.live
- Audio & video podcast streaming with custom player
- Playback speed control (0.5x - 2x)
- Volume control with mute toggle
- Progress tracking & resume playback
- Lock screen media controls (Media Session API)
- Download for offline listening (subscription feature)
- Category & tag filtering
- Fullscreen video support
- Session persistence (resume where you left off)
- Full markdown blog with rich editor
- Featured articles support
- Tag-based filtering
- Author attribution
- Read time estimation
- SEO optimized with Open Graph
- Syntax highlighting for code blocks
- Image galleries and embeds
- Multiple pricing tiers (Free, Pro, Premium)
- Upgrade/downgrade with prorated billing
- Cancel & reactivate subscriptions
- 7-day refund window
- Individual podcast purchases
- Razorpay payment integration
- Webhook support for payment events
- Product catalog with categories (clothing, accessories, digital)
- Shopping cart with persistent state
- Secure checkout via Razorpay
- Stock management
- Product image uploads
- Google OAuth & Email/Password authentication
- User dashboard with listening history
- Billing & payment history
- Download management
- Profile settings
- Subscription management
- Revenue analytics with charts
- Podcast management (CRUD, publish/draft)
- Blog management with markdown editor
- User management & roles
- Payment & invoice tracking
- Subscription management (pause, cancel, extend)
- Refund processing with Razorpay integration
- Product inventory management
- Pricing plan configuration
- Category & tag management
- Feature Toggles: Enable/disable features dynamically
- Blog section
- Merchandise store
- Subscription system
- Downloads
- Newsletter signup
- Maintenance Mode: Show maintenance page to non-admin users
- Real-time toggle updates across the platform
- Fully responsive design for all screen sizes
- Touch-optimized interactions with haptic feedback
- Safe area support for notched devices (iPhone X+)
- iOS Safari fixes (100vh, input zoom prevention)
- Mobile-friendly admin dashboard with slide-out menu
- PWA-ready with manifest and icons
| Category | Technology |
|---|---|
| Frontend | React 18.3, TypeScript 5.5, Vite 5 |
| Styling | Tailwind CSS 3.4, Framer Motion 11 |
| State | Zustand 4.5 |
| Database | Neon PostgreSQL, Drizzle ORM |
| Auth | Supabase Auth (Google OAuth + Email) |
| Storage | Supabase Storage |
| Payments | Razorpay |
| Hosting | Vercel (Edge Functions) |
| Analytics | Vercel Analytics |
| Markdown | @uiw/react-md-editor, react-markdown |
| Icons | Lucide React |
tendertalks/
├── api/ # Vercel Edge Functions
│ ├── admin/ # Admin-only endpoints
│ │ ├── blogs/ # Blog CRUD
│ │ ├── podcasts/ # Podcast CRUD
│ │ ├── categories/ # Category management
│ │ ├── tags/ # Tag management
│ │ ├── plans/ # Pricing plans
│ │ ├── products/ # Merch products
│ │ ├── settings/ # Feature toggles (admin)
│ │ ├── users.ts # User management
│ │ ├── payments.ts # Payment history
│ │ ├── invoices/ # Invoice management
│ │ ├── subscriptions/ # Subscription management
│ │ ├── refunds/ # Refund processing
│ │ └── stats.ts # Analytics data
│ ├── blogs/ # Public blog endpoints
│ ├── podcasts/ # Public podcast endpoints
│ ├── payments/ # Payment processing
│ ├── subscriptions/ # Subscription operations
│ ├── merch/ # Merchandise endpoints
│ ├── users/ # User profile & data
│ ├── pricing-plans/ # Public pricing data
│ ├── categories/ # Public categories
│ ├── tags/ # Public tags
│ ├── newsletter/ # Newsletter subscription
│ ├── refunds/ # Refund requests
│ ├── settings/ # Public settings (feature flags)
│ ├── og-image.tsx # Dynamic OG images
│ └── rss.ts # RSS feed
├── drizzle/ # Database migrations
├── public/ # Static assets
│ ├── favicon.svg
│ ├── manifest.json
│ ├── og-image.svg
│ └── sitemap.xml
├── scripts/
│ ├── seed.ts # Database seeding
│ └── supabase-setup.sql # Supabase configuration
├── src/
│ ├── api/ # Frontend API clients
│ ├── components/
│ │ ├── auth/ # AuthModal
│ │ ├── blog/ # BlogCard
│ │ ├── cart/ # CartDrawer
│ │ ├── effects/ # StarField, FloatingOrbs
│ │ ├── layout/ # Navbar, Footer
│ │ ├── podcast/ # PodcastCard, MediaPlayer
│ │ ├── ui/ # Button, Input, Modal, Select, Toggle, etc.
│ │ ├── FeatureGuard.tsx # Route protection by feature
│ │ ├── ErrorBoundary.tsx # Error handling
│ │ ├── SEO.tsx # Meta tags & Open Graph
│ │ └── CustomCursor.tsx # Desktop cursor effect
│ ├── db/
│ │ └── schema.ts # Drizzle schema
│ ├── lib/
│ │ ├── supabase.ts # Supabase client
│ │ ├── razorpay.ts # Razorpay integration
│ │ └── storage.ts # Storage utilities
│ ├── pages/
│ │ ├── admin/ # Admin pages
│ │ │ ├── AdminDashboard.tsx
│ │ │ ├── PodcastManager.tsx
│ │ │ ├── PodcastEditor.tsx
│ │ │ ├── BlogManager.tsx
│ │ │ ├── BlogEditor.tsx
│ │ │ ├── UsersManager.tsx
│ │ │ ├── PaymentsManager.tsx
│ │ │ ├── InvoicesManager.tsx
│ │ │ ├── SubscriptionsManager.tsx
│ │ │ ├── RefundsManager.tsx
│ │ │ ├── ProductsManager.tsx
│ │ │ ├── PlansManager.tsx
│ │ │ └── SettingsManager.tsx # Feature toggles & maintenance
│ │ ├── legal/ # Legal pages
│ │ │ ├── PrivacyPolicy.tsx
│ │ │ ├── TermsOfService.tsx
│ │ │ └── RefundPolicy.tsx
│ │ ├── Home.tsx
│ │ ├── Browse.tsx
│ │ ├── PodcastDetail.tsx
│ │ ├── Blog.tsx
│ │ ├── BlogDetail.tsx
│ │ ├── Pricing.tsx
│ │ ├── Store.tsx
│ │ ├── Dashboard.tsx
│ │ ├── Settings.tsx
│ │ ├── Billing.tsx
│ │ ├── Downloads.tsx
│ │ ├── AuthCallback.tsx
│ │ ├── NotFound.tsx
│ │ └── Maintenance.tsx # Maintenance mode page
│ ├── stores/ # Zustand stores
│ │ ├── authStore.ts
│ │ ├── podcastStore.ts
│ │ ├── blogStore.ts
│ │ ├── userStore.ts
│ │ ├── cartStore.ts
│ │ ├── merchStore.ts
│ │ └── settingsStore.ts # Feature toggles state
│ ├── App.tsx
│ ├── index.css
│ └── main.tsx
├── .env.example
├── .gitignore
├── .prettierrc
├── drizzle.config.ts
├── eslint.config.js
├── index.html
├── package.json
├── postcss.config.js
├── tailwind.config.js
├── tsconfig.json
├── vercel.json
└── vite.config.ts
-
Clone the repository
git clone https://github.com/Afnanksalal/tendertalks.git cd tendertalks -
Install dependencies
npm install
-
Set up environment variables
cp .env.example .env
Fill in your credentials (see Environment Variables)
-
Set up Supabase
- Create a new project at supabase.com
- Run the SQL from
scripts/supabase-setup.sqlin SQL Editor - Create storage buckets:
podcasts,blogs,products - Enable Google OAuth in Authentication > Providers
-
Set up the database
npm run db:push npm run db:seed # Optional: seed sample data -
Start development server
npm run dev
Create a .env file with the following variables:
# Supabase (Authentication & Storage)
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
# Neon Database
DATABASE_URL=postgresql://user:password@host/database?sslmode=require
# Razorpay Payments
VITE_RAZORPAY_KEY_ID=rzp_test_xxxxx
RAZORPAY_KEY_ID=rzp_test_xxxxx
RAZORPAY_KEY_SECRET=your-secret
# App Configuration
VITE_APP_URL=http://localhost:5173
VITE_APP_NAME=TenderTalks| Command | Description |
|---|---|
npm run dev |
Start development server |
npm run build |
TypeScript check + Vite build |
npm run preview |
Preview production build |
npm run lint |
Run ESLint |
npm run lint:fix |
Fix ESLint issues |
npm run format |
Format with Prettier |
npm run format:check |
Check formatting |
npm run typecheck |
TypeScript type checking |
npm run db:generate |
Generate Drizzle migrations |
npm run db:push |
Push schema to database |
npm run db:studio |
Open Drizzle Studio |
npm run db:seed |
Seed database with sample data |
npm run clean |
Clean build artifacts |
- Push to GitHub
- Import project in Vercel
- Add environment variables in Project Settings
- Deploy
Set all variables from .env.example in Vercel:
- Use production Razorpay keys (
rzp_live_xxx) - Set
VITE_APP_URLto your domain (e.g.,https://tendertalks.live) - Configure OAuth redirect URLs in Supabase Dashboard
- Add your production domain to Authentication > URL Configuration
- Set Site URL to your domain
- Add redirect URLs:
https://yourdomain.com/auth/callback
To grant admin access to a user:
UPDATE users SET role = 'admin' WHERE email = 'your-email@example.com';Run this in Neon Console or Drizzle Studio after the user has signed in.
The platform includes a powerful admin settings system accessible at /admin/settings:
Toggle features on/off without code changes:
- Blog: Enable/disable the blog section
- Merchandise Store: Enable/disable the store
- Subscriptions: Enable/disable subscription plans
- Downloads: Enable/disable podcast downloads
- Newsletter: Enable/disable newsletter signup
When a feature is disabled:
- Navigation links are hidden
- Routes redirect to home page
- API endpoints return appropriate errors
When enabled:
- Non-admin users see a styled maintenance page
- Admins see a warning banner but can still access the site
- Toggle from Admin Settings → Maintenance Mode
Settings are stored in the site_settings table and cached in the frontend via Zustand.
Key tables:
users- User accounts with rolespodcasts- Audio/video contentblogs- Blog articles (content stored in Supabase Storage)categories- Content categoriestags- Content tagspricing_plans- Subscription tierssubscriptions- User subscriptionspurchases- Individual podcast purchasespayment_history- All transactionsrefund_requests- Refund processingmerch_items- Store productsmerch_orders- Store ordersdownloads- Download trackingplay_history- Playback progressnewsletter_subscribers- Email listsite_settings- Feature toggles & platform configuration
Contributions are welcome! Please read our Contributing Guide for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
For security issues, please see our Security Policy.
Do not create public issues for security vulnerabilities. Email security@tendertalks.live instead.
This project is licensed under the MIT License - see the LICENSE file for details.
- Website: tendertalks.live
- Support: support@tendertalks.live
- Sales: sales@tendertalks.live
- Security: security@tendertalks.live
- Twitter: @tendertalks_
- Instagram: @tendertalks.live
- YouTube: @tendertalkslive
- LinkedIn: TenderTalks
Made with ❤️ by Afnan & Jenna
