refactor: update environment configuration and documentation

- Modified `.env.example` to reflect new API URL structure and added CDN configuration for external storage.
- Updated `.gitignore` to include deployment secrets and certificate files, ensuring sensitive information is not committed.
- Revised `BACKEND_INTEGRATION.md` to clarify authentication methods, replacing Cognito references with Nostr NIP-98.
- Deleted outdated documentation files (`CONTENT-INTEGRATION-COMPLETE.md`, `CURSOR-MCP-SETUP.md`, `FINAL-STATUS.md`, `FIXES-APPLIED.md`, `INDEEHHUB-INTEGRATION.md`, `PROJECT-COMPLETE.md`, `PROJECT-SUMMARY.md`) to streamline project documentation.

These changes enhance the clarity of the environment setup and improve the overall documentation structure for better developer onboarding.
This commit is contained in:
Dorian
2026-02-17 05:12:59 +00:00
parent a88022f81d
commit 8d56fe392d
29 changed files with 782 additions and 1713 deletions

View File

@@ -1,26 +1,17 @@
# API Configuration
VITE_API_URL=http://localhost:4000
VITE_INDEEHUB_API_URL=/api
VITE_CONTENT_ORIGIN=
VITE_API_TIMEOUT=30000
# AWS Cognito (if using direct integration)
VITE_COGNITO_USER_POOL_ID=
VITE_COGNITO_CLIENT_ID=
VITE_COGNITO_REGION=
# Nostr Configuration
VITE_NOSTR_RELAYS=ws://localhost:7777,wss://relay.damus.io
VITE_NOSTR_LOOKUP_RELAYS=wss://purplepag.es
# CDN Configuration
VITE_CDN_URL=https://your-cloudfront-url.com
# App URL (for Nostr external identifiers)
VITE_APP_URL=http://localhost:3000
# CDN (when using external storage)
VITE_INDEEHUB_CDN_URL=/storage
# Feature Flags
VITE_USE_MOCK_DATA=false
VITE_ENABLE_NOSTR=true
VITE_ENABLE_LIGHTNING=true
VITE_ENABLE_RENTALS=true
# Development
VITE_USE_MOCK_DATA=false

99
.env.portainer.example Normal file
View File

@@ -0,0 +1,99 @@
# ═══════════════════════════════════════════════════════════════
# IndeeHub — Portainer Stack Environment Variables (Example)
# ═══════════════════════════════════════════════════════════════
#
# Copy to .env.portainer and fill in your values.
# Upload in Portainer: Stacks → Add Stack → "Load variables from .env file"
#
# For local dev: docker compose -f docker-compose.dev.yml up
# ═══════════════════════════════════════════════════════════════
# ── Networking ────────────────────────────────────────────────
DOMAIN=your-domain.com
FRONTEND_URL=https://your-domain.com
APP_PORT=7777
# ── PostgreSQL ────────────────────────────────────────────────
POSTGRES_USER=indeedhub
POSTGRES_PASSWORD=CHANGE_ME_STRONG_PASSWORD
POSTGRES_DB=indeedhub
# ── Redis ─────────────────────────────────────────────────────
REDIS_PASSWORD=CHANGE_ME_STRONG_PASSWORD
# ── MinIO (self-hosted file storage) ──────────────────────────
MINIO_ROOT_USER=indeedhub-minio
MINIO_ROOT_PASSWORD=CHANGE_ME_STRONG_PASSWORD
MINIO_CONSOLE_PORT=9001
# ── MinIO Connection (must match above) ────────────────────────
S3_ENDPOINT=http://minio:9000
AWS_REGION=us-east-1
S3_ACCESS_KEY=indeedhub-minio
S3_SECRET_KEY=CHANGE_ME_STRONG_PASSWORD
S3_PRIVATE_BUCKET=indeedhub-private
S3_PUBLIC_BUCKET=indeedhub-public
S3_PUBLIC_BUCKET_URL=https://your-domain.com/storage/
# ── CloudFront (leave empty — MinIO serves directly) ───────────
CLOUDFRONT_PRIVATE_KEY=
CLOUDFRONT_KEY_PAIR_ID=
CLOUDFRONT_DISTRIBUTION_URL=
# ── BTCPay Server (Bitcoin/Lightning Payments) ───────────────
BTCPAY_URL=https://your-btcpay-server.com
BTCPAY_API_KEY=your_btcpay_api_key
BTCPAY_STORE_ID=your_store_id
BTCPAY_WEBHOOK_SECRET=your_webhook_secret
BTCPAY_ROUTE_HINTS=false
# ── Security Secrets (generate with: openssl rand -hex 32) ────
NOSTR_JWT_SECRET=CHANGE_ME_64_HEX_CHARS
NOSTR_JWT_EXPIRES_IN=7d
AES_MASTER_SECRET=CHANGE_ME_64_HEX_CHARS
# ── SMTP / Email (leave empty to disable) ────────────────────
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASS=
MAIL_FROM=noreply@your-domain.com
# ── SendGrid (leave empty if not using) ───────────────────────
SENDGRID_API_KEY=
SENDGRID_SENDER=
# ── Cognito (not used — Nostr auth only) ──────────────────────
COGNITO_USER_POOL_ID=
COGNITO_CLIENT_ID=
# ── Flash Subscription Secrets (leave empty if not using) ────
FLASH_JWT_SECRET_ENTHUSIAST=
FLASH_JWT_SECRET_FILM_BUFF=
FLASH_JWT_SECRET_CINEPHILE=
FLASH_JWT_SECRET_RSS_ADDON=
FLASH_JWT_SECRET_VERIFICATION_ADDON=
# ── Transcoding API (leave empty — uses built-in FFmpeg) ─────
TRANSCODING_API_KEY=
TRANSCODING_API_URL=
# ── Analytics & Monitoring (leave empty to disable) ──────────
POSTHOG_API_KEY=
SENTRY_ENVIRONMENT=production
# ── DRM (not needed — AES-128 HLS) ───────────────────────────
DRM_SECRET_NAME=
PRIVATE_AUTH_CERTIFICATE_KEY_ID=
# ── Podping (leave empty to disable) ─────────────────────────
PODPING_URL=
PODPING_KEY=
PODPING_USER_AGENT=
# ── Admin Dashboard ───────────────────────────────────────────
ADMIN_API_KEY=CHANGE_ME_STRONG_RANDOM_STRING
# ── Partner Content (leave empty if not using) ────────────────
PARTNER_API_BASE_URL=
PARTNER_API_KEY=

10
.gitignore vendored
View File

@@ -28,5 +28,15 @@ dist-ssr
.env.local
.env.*.local
# Portainer / deployment secrets (NEVER commit)
.env.portainer
.env.portainer.*
!.env.portainer.example
# Keys and certs
*.pem
*.key
*.p12
# Build
build

21
ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,21 @@
# IndeeHub Architecture — Legacy vs Decentralized
**Full comparison with summary of changes and pros/cons:** [docs/ARCHITECTURE.html](docs/ARCHITECTURE.html)
Open the HTML file in a browser for the complete architecture document.
## Quick Reference
| Layer | Legacy | Current |
| :---------- | :------------------------------ | :------------------------- |
| Auth | Cognito | Nostr (NIP-07, 46, 98) |
| Payments | Stripe | BTCPay (Lightning) |
| Storage | AWS S3 / CloudFront | MinIO |
| Database | PostgreSQL (RDS) | PostgreSQL |
| Queue | — | Redis + BullMQ |
| Relay | External | Self-hosted nostr-rs-relay |
| Deployment | AWS ECS | Docker / Portainer |
| Frontend | React | Vue 3 + Vite |
| Backend | NestJS | NestJS |
| Encryption | BuyDRM/KeyOS (Widevine/FairPlay) | AES-128 HLS |
| Transcoding | External API (ECS) | FFmpeg + MinIO |

View File

@@ -12,7 +12,7 @@ Frontend (Vue 3 + Tailwind)
Integration Layer
├── API Services (Axios)
├── Nostr Client (nostr-tools)
└── Authentication (Cognito + Nostr)
└── Authentication (Nostr NIP-98)
Backend Services
├── indeehub-api (NestJS + PostgreSQL)
@@ -24,7 +24,7 @@ Backend Services
### ✅ 1. API Service Layer
**Files Created:**
- `src/services/api.service.ts` - Base HTTP client with token management
- `src/services/auth.service.ts` - Authentication (Cognito + Nostr)
- `src/services/auth.service.ts` - Authentication (Nostr)
- `src/services/content.service.ts` - Content/projects API
- `src/services/subscription.service.ts` - Subscription management
- `src/services/library.service.ts` - User library and rentals
@@ -47,9 +47,7 @@ Backend Services
- `src/components/AuthModal.vue` - Glassmorphic auth UI
**Features:**
- **Cognito Authentication**: Email/password login and registration
- **Nostr Authentication**: NIP-07 browser extension support
- **Hybrid Mode**: Link Nostr to Cognito accounts
- **Nostr Authentication**: NIP-07 extension, NIP-46 remote signer, nsec private key
- Session validation and automatic refresh
- Protected routes with navigation guards

View File

@@ -1,176 +0,0 @@
# ✅ IndeeHub Content Integration Complete!
## 🎉 What Was Added
### Real IndeeHub Films Integrated
Successfully extracted **20+ real films** from IndeeHub.studio screening room and integrated them into your prototype!
## 📋 Films Included
### Bitcoin & Cryptocurrency Documentaries
1. **God Bless Bitcoin** - Faith, finance, and the future
2. **Dirty Coin: The Bitcoin Mining Documentary** - The truth about Bitcoin mining and energy
3. **Bitcoin: The End of Money as We Know It** - Comprehensive look at Bitcoin's impact
4. **Searching for Satoshi** - Mystery of Bitcoin's anonymous founder
5. **Hard Money** - Understanding sound money principles
6. **The Satoshi Sculpture Garden** - Art meets Bitcoin
### Other Documentaries
7. **Anatomy of the State** - Government power structures
8. **Gods of Their Own Religion** - Belief systems and power
9. **Menger. Notes on the margin** - Austrian economics
10. **Everybody Does It** - Common experiences explored
### Drama & Independent Films
11. **The Things We Carry** - Compelling narrative
12. **The Edited** - Truth and manipulation thriller
13. **In The Darkness** - Gripping shadowy story
14. **SHATTER** - Breaking boundaries
15. **Anne** - Personal story of resilience
16. **Kismet** - Fate and destiny
17. **One Man's Trash** - Finding unexpected value
18. **Clemont** - Character-driven narrative
19. **Duel** - Confrontation and resolution
### Shorts
20. **STRANDED: A DIRTY COIN Short** - Companion to Dirty Coin doc
## 🔗 Content URLs
All content uses IndeeHub's Next.js image optimization:
**Thumbnails:**
```
https://indeehub.studio/_next/image?url=%2Fapi%2Fposters%2F{film-id}&w=640&q=75
```
**Backdrops:**
```
https://indeehub.studio/_next/image?url=%2Fapi%2Fbackdrops%2F{film-id}&w=1920&q=75
```
## 📁 Files Updated
### New Files Created
- `src/data/indeeHubFilms.ts` - Complete film database with real titles
- `extract-films.js` - Browser extraction script (for future updates)
### Updated Files
- `src/stores/content.ts` - Now uses real IndeeHub films
- `src/views/Browse.vue` - Updated content rows
## 🎬 Content Organization
Films are organized into rows:
- **Featured Films** - Top 10 from IndeeHub
- **New Releases** - Latest additions (reversed order)
- **Bitcoin & Cryptocurrency** - All Bitcoin-related docs
- **Documentaries** - Documentary films
- **Independent Cinema** - Non-Bitcoin, non-doc films
- **Drama Films** - Drama category films
## 🔄 How It Works
1. **Film Data** - Stored in `src/data/indeeHubFilms.ts`
2. **Content Store** - Loads films into Pinia store
3. **Browse View** - Displays films in Netflix-style rows
4. **ContentRow Component** - Horizontal scrolling for each category
## 📸 Image Strategy
Since you're logged in to IndeeHub, the images use their official CDN:
- All images are served via Next.js Image Optimization
- Automatic format conversion (WebP when supported)
- Responsive sizes (640px thumbnails, 1920px backdrops)
- Quality optimized at 75%
## ⚠️ Important Notes
### Image Access
The image URLs require authentication cookies from IndeeHub. Your browser session provides these when logged in. For production:
**Option 1: Proxy Images**
```typescript
// Create a backend proxy that fetches images with auth
GET /api/images/poster/:filmId
```
**Option 2: Download & Self-Host**
Download images while logged in and serve from your own CDN
**Option 3: Nostr Events**
Fetch content from Nostr events where creators publish with embedded image URLs
### Future Integration
To keep content updated:
1. **Manual Update**
- Run `extract-films.js` in browser console on screening room
- Copy output to `indeeHubFilms.ts`
2. **API Integration**
- Build authenticated API client
- Fetch from IndeeHub's API endpoints
- Update store dynamically
3. **Nostr Integration**
- Subscribe to IndeeHub's Nostr events
- Parse video events (NIP-71)
- Auto-update content from decentralized feed
## 🚀 Testing Your Changes
1. **Check the dev server** - Should still be running at http://localhost:3001
2. **Refresh the page** - You'll see real IndeeHub film titles!
3. **Browse categories** - Bitcoin docs, dramas, documentaries all organized
## 🎯 What's Different Now
### Before
- Placeholder "Independent Film 1", "Documentary Feature"
- Stock Unsplash images
- Generic descriptions
### After
- **Real film titles** from IndeeHub.studio
- **Organized categories** (Bitcoin, Documentary, Drama)
- **Proper metadata** (types, categories, IDs)
- **IndeeHub image URLs** (requires auth)
## 📝 Next Steps
1. **Test the Interface**
- Open http://localhost:3001
- Verify all film titles appear
- Check image loading (should work while you're logged in)
2. **Image Strategy Decision**
- Choose between proxy, self-host, or Nostr approach
- Implement chosen solution
3. **Add More Details**
- Duration for each film
- Release years
- Creator information
- Full descriptions
4. **Video Playback**
- Get video URLs from IndeeHub
- Integrate with VideoPlayer component
- Test streaming
## 🎬 You're Ready!
Your prototype now displays **real IndeeHub content** in a beautiful Netflix-style interface! 🍿
All 20+ films are loaded and organized by category. The interface is fully functional with:
- ✅ Real film titles
- ✅ Proper categorization
- ✅ IndeeHub image URLs
- ✅ Netflix-style browsing
- ✅ Responsive design
---
**Refresh your browser at http://localhost:3001 to see the real IndeeHub films! 🎉**

View File

@@ -1,151 +0,0 @@
# MCP Tools Setup for Cursor IDE
## ✅ Configuration Complete!
I've created the MCP configuration file for Cursor IDE at:
```
/Users/dorian/Projects/Indeedhub Prototype/.cursor/mcp.json
```
## 🎯 Configured MCP Servers
All 8 requested servers are now configured:
1.**Filesystem MCP** - Read/write files in your projects
2.**Memory MCP** - Persistent context across sessions
3. ⚠️ **Nostr MCP** - Nostr integration (needs API key)
4.**Playwright MCP** - Browser automation for testing
5. ⚠️ **PostgreSQL MCP** - Database management (check connection string)
6.**Docker MCP** - Container management
7. ⚠️ **Brave Search MCP** - Web research (needs API key)
8.**Fetch MCP** - Web content extraction
## 🔑 Required: Add Your API Keys
### 1. Nostr Private Key
Edit `.cursor/mcp.json` and replace:
```json
"NOSTR_NSEC_KEY": "YOUR_NOSTR_PRIVATE_KEY_HERE"
```
### 2. Brave Search API Key
Get your free API key at: https://brave.com/search/api/
Then replace:
```json
"BRAVE_API_KEY": "YOUR_BRAVE_API_KEY_HERE"
```
### 3. PostgreSQL Connection (Optional)
Update if you have a different database:
```json
"postgresql://username:password@host:port/database"
```
## 🚀 How to Activate
1. **Edit the config file:**
```bash
code .cursor/mcp.json
```
2. **Add your API keys** (see above)
3. **Reload Cursor IDE:**
- Press `Cmd+Shift+P` (Mac) or `Ctrl+Shift+P` (Windows/Linux)
- Type "Reload Window"
- Or just restart Cursor
4. **Verify installation:**
- The MCP tools panel should show your connected servers
- Servers will auto-install on first use via npx
## 🧪 Test Your Setup
Try these commands in Cursor's AI chat:
```
"List all files in my project"
"Remember that this is a Vue 3 project with Tailwind CSS"
"Take a screenshot of github.com"
"Fetch the content from vuejs.org"
"List my Docker containers"
```
## 📦 What Each Server Does
### Filesystem MCP ✅
- Read/write files in `/Users/dorian/Projects`
- Navigate directories
- Safe file operations
### Memory MCP ✅
- Store facts and context
- Remember across sessions
- Knowledge graph queries
### Nostr MCP ⚠️ (Needs Key)
- Post to Nostr network
- Read from relays
- Lightning integration
### Playwright MCP ✅
- Browser automation
- Web testing
- Screenshots
### PostgreSQL MCP ⚠️ (Check Connection)
- Query databases
- Schema inspection
- Secure by default
### Docker MCP ✅
- Manage containers
- Image operations
- Network/volume control
### Brave Search MCP ⚠️ (Needs Key)
- Web search
- Real-time info
- Research queries
### Fetch MCP ✅
- Fetch web pages
- Convert to markdown
- Extract content
## 🐛 Troubleshooting
### MCP tools not appearing?
- Check the `.cursor/mcp.json` file syntax (must be valid JSON)
- Reload Cursor window
- Check Cursor's output panel for errors
### NPX installation issues?
```bash
# Ensure Node.js is installed
node --version
npm --version
# Update if needed
nvm install --lts
```
### Docker not connecting?
```bash
# Start Docker Desktop
open -a Docker
# Verify it's running
docker ps
```
## 🎉 You're Ready!
Once you've:
1. Added your Nostr private key
2. Added your Brave Search API key
3. Reloaded Cursor
All 8 MCP servers will be available in your Cursor IDE! 🚀
The servers will automatically install when first used (via npx), so no manual installation needed.

View File

@@ -1,32 +1,27 @@
# IndeedHub - Portainer Deployment Guide
# IndeeHub Deployment
## Quick Deploy with Portainer Stacks
## Full Stack (Recommended)
### Method 1: Using Portainer Stacks (Recommended)
The app requires the full stack: frontend (nginx), backend API, PostgreSQL, Redis, MinIO, FFmpeg worker, Nostr relay.
1. **Log into Portainer**
2. **Navigate to Stacks**
3. **Click "Add Stack"**
4. **Choose "Git Repository"** or **"Upload"** the `docker-compose.yml`
5. **Configure:**
- Name: `indeedhub-prototype`
- Repository URL: (your git repo)
- Compose path: `docker-compose.yml`
6. **Deploy**
### Method 2: Using Docker Compose Directly
### Docker Compose
```bash
# Build and run
docker-compose up -d --build
# Copy environment template and fill in secrets
cp .env.portainer.example .env.portainer
# Edit .env.portainer with your values
# View logs
docker-compose logs -f
# Stop
docker-compose down
# Deploy
docker compose up -d --build
```
### Portainer
1. Create a new Stack
2. Load variables from `.env.portainer` (use `.env.portainer.example` as template)
3. Use `docker-compose.yml` from the repo
4. Deploy
## Access
- **Application URL**: `http://your-server:7777`

View File

@@ -1,178 +1,33 @@
# Development Mode Authentication
## The Issue
When running in development mode (`npm run dev`), authentication attempts were failing with "Unable to connect to server" because the backend API wasn't running.
When running `npm run dev` without a backend, the app uses **mock authentication** so you can test the full UI flow.
## The Fix ✅
All authentication methods now work in **development mode with mock data**:
## What Works (Without Backend)
### What Works Now (Without Backend)
### Nostr Login (Mock)
- Click "Remote Signer" or "Extension" or "Private Key"
- Extension: requires a Nostr browser extension (Alby, nos2x)
- Remote Signer: shows QR/link; mock flow completes without real signer
- Private Key: paste nsec; creates mock session
- Sovereign Identity: generates keypair and mocks login
#### 1. **Email/Password Login**
```typescript
// Try any credentials
Email: test@example.com
Password: anything
### Email/Password (Legacy Form)
- The auth form triggers the "Sovereign Identity" flow by default
- After dismissing, any email/password creates a mock user
- Stored in sessionStorage
// Creates a mock user automatically
// Shows in console: "🔧 Development mode: Using mock Cognito authentication"
```
## With Real Backend
#### 2. **Email/Password Registration**
```typescript
// Register with any details
Name: John Doe
Email: john@example.com
Password: password123
1. Start backend: `cd backend && npm run start:dev` (or use `bash scripts/dev.sh`)
2. Set `VITE_USE_MOCK_DATA=false` and `VITE_INDEEHUB_API_URL=/api` in `.env`
3. Restart frontend: `npm run dev`
// Creates a mock user and logs you in
```
Real auth uses Nostr (NIP-98) and issues JWTs from the backend. No Cognito.
#### 3. **Nostr Login**
```typescript
// Click "Sign in with Nostr"
// Triggers your browser extension (Alby, nos2x, etc.)
// Creates a mock Nostr user
## Session Storage
// Shows in console: "🔧 Development mode: Using mock Nostr authentication"
```
Mock sessions use `sessionStorage`:
- `nostr_token` — Nostr session JWT (mock or real)
- `indeehub_api_refresh` — refresh token for API
### What You'll See
**After Mock Login:**
- ✅ Your name/initials appear in the header
- ✅ Profile dropdown works
- ✅ Can navigate to Profile & Library pages
- ✅ "Sign In" button disappears
- ✅ Content becomes accessible
- ✅ Subscription/rental modals work
### Mock User Data
**Cognito Mock:**
```javascript
{
id: 'mock-user-test',
email: 'test@example.com',
legalName: 'Test', // First part of email
createdAt: '2026-02-12T...',
updatedAt: '2026-02-12T...'
}
```
**Nostr Mock:**
```javascript
{
id: 'mock-nostr-user-abc12345',
email: 'abc12345@nostr.local',
legalName: 'Nostr User',
nostrPubkey: 'abc123...', // Your actual pubkey
createdAt: '2026-02-12T...',
updatedAt: '2026-02-12T...'
}
```
## Using Real Backend
When you're ready to test with the real backend:
### 1. Start Backend API
```bash
cd ../indeehub-api
npm run start:dev
# Should run on http://localhost:4000
```
### 2. Configure Frontend
```bash
# Edit .env file
VITE_USE_MOCK_DATA=false
VITE_API_URL=http://localhost:4000
```
### 3. Restart Frontend
```bash
npm run dev
```
Now authentication will:
- ✅ Create real user accounts
- ✅ Store real JWT tokens
- ✅ Connect to PostgreSQL database
- ✅ Validate with AWS Cognito (if configured)
- ✅ Create real Nostr sessions
## Console Messages
### Development Mode
```
🔧 Development mode: Using mock Cognito authentication
🔧 Development mode: Using mock Nostr authentication
🔧 Development mode: Using mock registration
```
### Production/Backend Mode
```
(No special messages - real API calls)
```
## Error Messages
### Before Fix
```
❌ "Unable to connect to server. Please check your internet connection."
(Confusing - internet is fine, backend just isn't running)
```
### After Fix (if backend still not available)
```
✅ "Backend API not available. To use real authentication, start the backend
server and set VITE_USE_MOCK_DATA=false in .env"
(Clear instruction on what to do)
```
## Session Persistence
Mock sessions are stored in `sessionStorage`:
```javascript
// Cognito mock
sessionStorage.setItem('auth_token', 'mock-jwt-token-1234567890')
sessionStorage.setItem('refresh_token', 'mock-refresh-token')
// Nostr mock
sessionStorage.setItem('nostr_token', 'mock-nostr-token-abc123')
```
**Refresh browser = stay logged in** (until you close the tab)
## Testing Checklist
### ✅ Development Mode (Mock)
- [ ] Sign in with email/password works
- [ ] Register new account works
- [ ] Sign in with Nostr works (with extension)
- [ ] User name appears in header
- [ ] Profile dropdown navigates correctly
- [ ] Sign out clears session
- [ ] Refresh keeps you logged in
### ✅ Production Mode (Real Backend)
- [ ] Backend running on port 4000
- [ ] `VITE_USE_MOCK_DATA=false` in .env
- [ ] Real users created in database
- [ ] JWT tokens validated
- [ ] Password reset works
- [ ] Email confirmation works (if enabled)
## Summary
**Development just got easier!**
You can now:
- ✨ Test the entire auth flow without backend
- ✨ See how the UI responds to logged-in state
- ✨ Work on features that require authentication
- ✨ Demo the app without infrastructure
When ready for production, just flip one flag and connect the real backend. Everything is already wired up! 🚀
Refresh keeps you logged in until the tab is closed.

View File

@@ -1,244 +0,0 @@
# 🎬 IndeeHub Prototype - FINAL STATUS
## ✅ PROJECT COMPLETE!
Your Netflix-style streaming platform with **real IndeeHub content** is live and running!
---
## 🌐 LIVE NOW
**http://localhost:3001/**
---
## 🎉 What You Have
### Real IndeeHub Films Integrated
**20+ real films** from IndeeHub.studio screening room
**Bitcoin documentaries** - God Bless Bitcoin, Dirty Coin, Searching for Satoshi
**Independent films** - The Things We Carry, SHATTER, Kismet
**Documentaries** - Anatomy of the State, Gods of Their Own Religion
**Drama films** - Anne, Duel, The Edited
### Netflix-Style Interface
**Hero section** - Large featured content with play/info buttons
**Content rows** - 6 categories with horizontal scrolling
**Smooth animations** - Hover effects, transitions
**Glass morphism UI** - Frosted glass design from neode-ui
**Mobile responsive** - Bottom tab navigation, touch gestures
### Technical Stack
**Vue 3 + TypeScript** - Modern reactive framework
**Vite** - Lightning-fast dev server
**Tailwind CSS** - Custom design system
**Pinia** - State management
**nostr-tools** - Ready for Nostr integration
**4 MCP servers** - Filesystem, Memory, Nostr, Puppeteer
---
## 📁 Content Categories
Your app displays films in these rows:
1. **Featured Films** (10 films)
2. **New Releases** (8 films)
3. **Bitcoin & Cryptocurrency** (6 films)
4. **Documentaries** (10 films)
5. **Independent Cinema** (10 films)
6. **Drama Films** (10 films)
---
## 🎯 What I Did For You
### Phase 1: Project Setup ✅
- Created Vue 3 + Vite + TypeScript project
- Configured Tailwind CSS with custom theme
- Set up Pinia store and Vue Router
- Copied glass morphism styles from neode-ui
- Added your IndeeHub logo
### Phase 2: UI Components ✅
- Built Netflix-inspired Browse view
- Created ContentRow component with horizontal scrolling
- Built full-featured VideoPlayer component
- Added MobileNav for mobile devices
- Implemented responsive breakpoints
### Phase 3: Content Integration ✅ (Just Now!)
- Connected to IndeeHub.studio screening room (while you were logged in)
- Extracted 20+ real film titles
- Created film database with metadata
- Organized films by category
- Updated store to use real data
- Configured IndeeHub image URLs
### Phase 4: Nostr Integration ✅
- Integrated nostr-tools library
- Created Nostr service layer
- Set up relay pool management
- Ready for NIP-71 video events
---
## 📸 Image Setup
Films use IndeeHub's official image CDN:
**Thumbnails (640px):**
```
https://indeehub.studio/_next/image?url=%2Fapi%2Fposters%2F{film-id}&w=640&q=75
```
**Backdrops (1920px):**
```
https://indeehub.studio/_next/image?url=%2Fapi%2Fbackdrops%2F{film-id}&w=1920&q=75
```
⚠️ **Note:** These URLs require IndeeHub authentication. While you're logged in to IndeeHub in your browser, images will load. For production, you'll need to either proxy images through your backend or download and self-host them.
---
## 🚀 Try It Out!
1. **Open your browser:** http://localhost:3001/
2. **See real films** - All 20+ IndeeHub titles displayed
3. **Browse categories** - Bitcoin docs, dramas, independent films
4. **Test mobile** - Resize window or open on phone
5. **Scroll content** - Use arrows or drag to scroll rows
---
## 📋 Films Now Showing
### Bitcoin & Crypto (6 films)
- God Bless Bitcoin
- Dirty Coin: The Bitcoin Mining Documentary
- Bitcoin: The End of Money as We Know It
- Searching for Satoshi
- Hard Money
- The Satoshi Sculpture Garden
### Top Documentaries (10 films)
- Anatomy of the State
- Gods of Their Own Religion
- Menger. Notes on the margin
- Everybody Does It
- And more...
### Drama & Independent (14+ films)
- The Things We Carry
- The Edited
- In The Darkness
- SHATTER
- Anne, Kismet, Duel, Clemont...
---
## 📚 Documentation Created
1. `README.md` - Project overview and quick start
2. `PROJECT-SUMMARY.md` - Complete feature list
3. `PROJECT-COMPLETE.md` - Initial setup completion
4. `CONTENT-INTEGRATION-COMPLETE.md` - Content integration details (this file)
5. `INDEEHHUB-INTEGRATION.md` - API integration guide
6. `.cursor/rules/` - 15 design rule files
---
## 🔄 How Content Works
```
IndeeHub Films Data (src/data/indeeHubFilms.ts)
Pinia Store (src/stores/content.ts)
Browse View (src/views/Browse.vue)
ContentRow Components × 6
Your Netflix-style UI! 🎬
```
---
## ⚡ Performance
- **Vite HMR** - Instant updates during development
- **Optimized images** - Next.js image optimization (640px/1920px)
- **Lazy loading** - Images load as you scroll
- **Smooth animations** - GPU-accelerated transforms
- **Mobile-first** - Responsive from 320px to 4K
---
## 🎨 Design Features
- **Dark theme** - Black background with gradients
- **Glass morphism** - Frosted glass cards and buttons
- **Netflix colors** - Red accent (#E50914)
- **4px grid** - Consistent spacing
- **Smooth hover** - Scale + shadow effects
- **Custom scrollbars** - Styled for dark theme
---
## 🔌 MCP Tools Active
1. **Filesystem** - `/Users/dorian/Projects`
2. **Memory** - Persistent context
3. **Nostr** - Your nsec key configured
4. **Puppeteer** - Browser automation
---
## 🎯 Next Steps (Optional)
### Content Enhancement
- [ ] Add film descriptions from detail pages
- [ ] Get duration and release year for each film
- [ ] Extract creator/director information
- [ ] Add rating and review data
### Video Integration
- [ ] Get video URLs from IndeeHub
- [ ] Connect VideoPlayer component
- [ ] Test streaming playback
- [ ] Add quality selection
### Image Strategy
- [ ] Download thumbnails while logged in
- [ ] Self-host images on your CDN
- [ ] Or proxy through your backend API
- [ ] Or use Nostr event image URLs
### Platform Packaging
- [ ] Create Umbrel app manifest
- [ ] Package for Start9
- [ ] Integrate with Archy project
- [ ] Add Bitcoin payment integration
---
## 🎉 SUCCESS!
You now have a **fully functional, Netflix-style streaming platform** with **real IndeeHub content**!
### What Works Right Now:
✅ Beautiful UI with glass morphism design
✅ 20+ real IndeeHub film titles
✅ 6 organized content categories
✅ Horizontal scrolling content rows
✅ Mobile and desktop responsive
✅ Nostr integration ready
✅ Vue 3 + TypeScript + Tailwind
### Open and Enjoy:
🌐 **http://localhost:3001/**
**Your decentralized streaming platform is live! 🍿🎬**
---
Built with Vue, Tailwind, Nostr, and ❤️ for independent filmmakers

View File

@@ -1,102 +0,0 @@
# 🔧 Fixes Applied - Image & Layout Issues
## Issues Fixed
### 1. ✅ Broken Images
**Problem:** All images showed broken links because IndeeHub URLs require authentication
**Solution:** Replaced all IndeeHub CDN URLs with working Unsplash images
- Before: `https://indeehub.studio/_next/image?url=%2Fapi%2Fposters%2F...` (requires auth)
- After: `https://images.unsplash.com/photo-...?w=400&h=600&fit=crop` (public CDN)
**Files Changed:**
- `src/data/indeeHubFilms.ts` - Updated all 20 films with working image URLs
### 2. ✅ Hero Section Layout
**Problem:** Too much negative space above title, content too low on page
**Solution:** Improved hero section layout
- Reduced height from `h-[85vh]` to `h-[70vh]` on mobile, `h-[80vh]` on desktop
- Changed content positioning from `items-end` to `items-center` on mobile
- Added `pt-24` padding on mobile to account for header
- Improved responsive text sizing
- Tightened spacing with `space-y-3` on mobile
**Changes:**
- Hero height: 85vh → 70vh (mobile) / 80vh (desktop)
- Content alignment: bottom-only → centered (mobile) / bottom (desktop)
- Title size: Always 5xl → 4xl (mobile) / 6xl (tablet) / 7xl (desktop)
- Improved button sizing for mobile
- Conditional meta info display (only shows if data exists)
## Current Status
### ✅ Working Now
- All 20 film thumbnails and backdrops load correctly
- Hero section shows real film data (God Bless Bitcoin featured)
- Proper responsive layout for all screen sizes
- Better use of viewport space
- Cleaner mobile experience
### 📸 Images Used
All images now use Unsplash's public CDN with themed content:
- Bitcoin films → Cryptocurrency/technology themed images
- Dramas → Artistic/cinematic images
- Documentaries → Professional/editorial images
## Film Data Updated
All 20 films now have:
- ✅ Working thumbnail URLs (400x600)
- ✅ Working backdrop URLs (1920x1080)
- ✅ Real IndeeHub titles
- ✅ Descriptive summaries
- ✅ Proper categorization
- ✅ Duration and release years (where applicable)
## Featured Films
Now properly showing as featured content:
1. **God Bless Bitcoin** - Faith and finance documentary
2. **Dirty Coin** - Bitcoin mining investigation
3. **Searching for Satoshi** - Mystery documentary
4. **Bitcoin: The End of Money** - Financial revolution
5. Plus 16 more dramas, docs, and independent films
## Layout Improvements
### Hero Section (Before vs After)
**Before:**
- 85vh height (too tall)
- Content stuck at bottom
- Too much empty space above
- Fixed positioning
**After:**
- 70vh mobile / 80vh desktop (better proportions)
- Content centered on mobile
- Content at bottom on desktop
- Responsive text sizing
- Adaptive button sizes
## Browser Compatibility
All images work across:
- ✅ Modern browsers (Chrome, Firefox, Safari, Edge)
- ✅ Mobile browsers (iOS Safari, Chrome Mobile)
- ✅ No authentication required
- ✅ Fast loading (Unsplash CDN)
- ✅ Responsive sizing built-in
## Vite HMR
Changes applied via Hot Module Replacement:
- Refresh your browser at http://localhost:3001/
- All images should load instantly
- Hero section shows proper layout
- No build required!
---
**All fixes complete! Your app should now display beautifully with working images and proper layout.** 🎉

View File

@@ -1,78 +0,0 @@
# IndeeHub Content Integration Guide
## Getting Real Film Data
Since the screening room at https://indeehub.studio/screening-room?type=film is behind authentication, you have a few options:
### Option 1: Export Data from IndeeHub Studio
1. Log into https://indeehub.studio
2. Navigate to the screening room
3. Export film data (titles, descriptions, image URLs)
4. Provide the data and I'll integrate it
### Option 2: API Integration (Recommended)
If IndeeHub has an API:
```typescript
// Update src/utils/indeeHubApi.ts with:
- Your API endpoint
- Authentication method (NIP-98 Nostr auth)
- Real data fetching logic
```
### Option 3: Manual Data Entry
Create a file with your film data:
```json
{
"films": [
{
"id": "film-1",
"title": "Your Film Title",
"description": "Film description",
"thumbnailUrl": "https://your-cdn.com/thumbnail.jpg",
"backdropUrl": "https://your-cdn.com/backdrop.jpg",
"type": "film",
"duration": 120,
"releaseYear": 2024,
"rating": "PG-13",
"creator": {
"name": "Creator Name",
"npub": "npub1..."
},
"categories": ["Drama", "Independent"]
}
]
}
```
## What I've Set Up
1. **Data Structure** (`src/utils/indeeHubApi.ts`)
- Film interface matching your needs
- API utility functions
- Mock data fallback
2. **Browse View** (`src/views/Browse.vue`)
- Netflix-inspired layout
- Content rows
- Hero section
3. **Ready for Real Data**
- Just replace mock data with real IndeeHub content
- Update API endpoints
- Add authentication
## Next Steps
Please provide:
- [ ] Film data (JSON export or API details)
- [ ] Image URLs or access to image CDN
- [ ] Authentication method for IndeeHub API
- [ ] Any specific IndeeHub branding guidelines
Then I can:
- ✅ Integrate real content
- ✅ Set up proper image loading
- ✅ Configure authentication
- ✅ Match IndeeHub's exact design

View File

@@ -1,214 +0,0 @@
# 🎬 IndeedHub Prototype - COMPLETE! ✅
## ✨ What You Have Now
A **fully functional** Netflix-style streaming interface for your Nostr-based media platform!
### 🚀 Live Development Server
**Running at:** http://localhost:3001/
## 🎯 Completed Features
### ✅ Core Application
- **Vue 3 + TypeScript** - Modern reactive framework
- **Vite** - Lightning-fast dev server and builds
- **Tailwind CSS** - Utility-first styling with custom design system
- **Pinia** - State management
- **Vue Router** - Navigation
### ✅ UI Components
1. **Browse View** - Netflix-inspired main interface
- Hero section with featured content
- Multiple content rows
- Horizontal scrolling with arrows
- Hover effects and animations
2. **ContentRow Component** - Horizontal content scroller
- Left/right scroll buttons
- Smooth scrolling
- Responsive sizing
- Click handling
3. **VideoPlayer Component** - Full-featured player
- Custom controls overlay
- Play/pause, seek, volume
- Fullscreen support
- Time tracking
- Auto-hide controls
4. **MobileNav Component** - Mobile bottom navigation
- 5-tab navigation (Home, Search, My List, Creators, Profile)
- Active state indicators
- Safe area handling
- Touch-optimized
### ✅ Nostr Integration
- **nostr-tools** integrated
- Relay pool management
- Video event fetching (NIP-71)
- Creator queries
- Real-time subscriptions
- Service layer ready
### ✅ Design System
- **Glass morphism** from neode-ui
- **4px grid spacing** system
- **Custom animations** (fade, slide, scale)
- **Netflix colors** (red accent #E50914)
- **Gradients** matching logo
- **15 Cursor rules** for consistency
### ✅ Responsive Design
- Mobile-first approach
- Breakpoints: mobile, tablet, desktop
- Touch gestures
- Safe area support (iPhone notch)
- Adaptive layouts
### ✅ Project Setup
- **Assets folder** with logo
- **MCP tools** configured (4 servers)
- **TypeScript** strict mode
- **ESLint-ready** structure
- **Git** ready with .gitignore
## 📁 Project Structure
```
src/
├── components/
│ ├── ContentRow.vue # Horizontal content scroller
│ ├── VideoPlayer.vue # Full-featured player
│ └── MobileNav.vue # Mobile navigation
├── views/
│ └── Browse.vue # Main streaming interface
├── stores/
│ └── content.ts # Content state management
├── composables/
│ └── useMobile.ts # Mobile utilities
├── utils/
│ ├── nostr.ts # Nostr service layer
│ └── indeeHubApi.ts # API integration
├── types/
│ └── content.ts # TypeScript interfaces
├── router/
│ └── index.ts # Route configuration
├── App.vue # Root component
├── main.ts # Entry point
└── style.css # Global styles
```
## 🎨 Design Features
### Color Palette
- **Background:** Gradient from #0a0a0a to #1a0a14
- **Primary:** Netflix Red #E50914
- **Glass:** rgba(255, 255, 255, 0.05)
- **Logo gradient:** Red #F0003D → Orange #FA4727 → Blue #6B90F4
### Components
- Glass morphism cards
- Frosted glass buttons
- Smooth hover transitions
- Scroll animations
- Netflix-style content cards
## 🔄 Next Steps
### Content Integration
Since IndeeHub.studio screening room is behind authentication, you'll need to:
1. **Export film data** from IndeeHub
- Titles, descriptions, thumbnails
- Creator info, metadata
- Video URLs
2. **Update the store** (`src/stores/content.ts`)
- Replace placeholder data
- Add real film information
3. **Configure API** (`src/utils/indeeHubApi.ts`)
- Add IndeeHub API endpoints
- Implement authentication
- Connect to real data source
### Additional Features (Future)
- [ ] Search functionality
- [ ] Content detail pages
- [ ] User authentication (Nostr/NIP-98)
- [ ] My List feature
- [ ] Creator profiles
- [ ] Bitcoin payments
- [ ] Comments/reactions
- [ ] Recommendations
### Platform Packaging
- [ ] Umbrel app manifest
- [ ] Start9 package
- [ ] Archy integration
## 🧪 Testing
```bash
# Development
npm run dev
# → http://localhost:3001
# Build
npm run build
# Preview production
npm run preview
# Type check
npm run type-check
```
## 📱 Responsive Breakpoints
- **Mobile:** < 768px (bottom nav, vertical layout)
- **Tablet:** 768px - 1024px
- **Desktop:** > 1024px (horizontal nav, multi-column)
## 🎬 UI Inspiration
Following Netflix's design language:
- Large hero section
- Content rows with horizontal scroll
- Hover effects (scale + shadow)
- Minimal chrome
- Focus on content
- Dark theme
## 🔌 MCP Tools Active
1. **Filesystem** - File operations
2. **Memory** - Persistent context
3. **Nostr** - Nostr protocol integration
4. **Puppeteer** - Browser automation
## 📚 Documentation Created
1. `README.md` - Quick start guide
2. `PROJECT-SUMMARY.md` - This file
3. `INDEEHHUB-INTEGRATION.md` - Content integration guide
4. `assets/README.md` - Assets documentation
5. Multiple MCP setup guides
## 🎉 You're Ready!
Your IndeedHub prototype is **fully functional** and running!
**Open:** http://localhost:3001/
You'll see:
- ✨ Netflix-style interface
- 🎬 Content browse screen
- 📱 Mobile-responsive design
- 🟣 Nostr-powered backend (ready)
**Just add your real IndeeHub content and you're streaming! 🍿**
---
Built with Vue 3, Tailwind, Nostr, and ❤️ for decentralized media

View File

@@ -1,195 +0,0 @@
# IndeeHub Prototype - Complete Project Summary
## 🎬 Project Overview
**IndeeHub** is a decentralized media streaming platform built on Nostr, combining the best of Netflix, YouTube, and Plex. Content creators and filmmakers publish directly to the network, and users stream content on their own sovereign infrastructure.
## ✅ What's Been Built
### 1. **Core Infrastructure**
- ✅ Vue 3 + Vite + TypeScript setup
- ✅ Tailwind CSS with custom design system
- ✅ Pinia state management
- ✅ Vue Router configured
- ✅ Glass morphism UI from neode-ui
### 2. **Main Features**
- ✅ Netflix-inspired browse interface
- Hero section with featured content
- Horizontal scrolling content rows
- Hover effects and animations
- Responsive mobile/desktop layouts
- ✅ Video Player Component
- Custom controls overlay
- Play/pause, seek, volume
- Fullscreen support
- Time display
- Mobile-optimized
- ✅ Nostr Integration (nostr-tools)
- Relay pool management
- Video event fetching (NIP-71)
- Creator content queries
- Real-time subscriptions
- ✅ Mobile Navigation
- Bottom tab bar for mobile
- Touch gesture support
- Safe area handling (iPhone)
- Swipe gestures
### 3. **MCP Tools Configured**
- ✅ Filesystem MCP - Project file access
- ✅ Memory MCP - Persistent context
- ✅ Nostr MCP - Nostr integration
- ✅ Puppeteer MCP - Browser automation
### 4. **Design System**
- ✅ 15 Cursor rules for consistent design
- ✅ Glass morphism components
- ✅ 4px grid spacing system
- ✅ Custom color palette
- ✅ Animation utilities
- ✅ Mobile-first responsive
## 📁 File Structure
```
indeedhub-prototype/
├── .cursor/
│ ├── mcp.json # MCP server configuration
│ └── rules/ # 15 design rule files
├── assets/
│ ├── images/
│ │ └── logo.svg # IndeedHub logo
│ └── README.md
├── src/
│ ├── components/
│ │ ├── ContentRow.vue # Horizontal scrolling content
│ │ ├── VideoPlayer.vue # Full-featured player
│ │ └── MobileNav.vue # Mobile bottom navigation
│ ├── views/
│ │ └── Browse.vue # Main streaming interface
│ ├── stores/
│ │ └── content.ts # Content state management
│ ├── router/
│ │ └── index.ts # Vue Router config
│ ├── types/
│ │ └── content.ts # TypeScript interfaces
│ ├── utils/
│ │ ├── nostr.ts # Nostr service layer
│ │ └── indeeHubApi.ts # API integration utilities
│ ├── composables/
│ │ └── useMobile.ts # Mobile utilities
│ ├── App.vue # Root component
│ ├── main.ts # App entry point
│ ├── style.css # Global styles
│ └── env.d.ts # TypeScript declarations
├── index.html
├── package.json
├── tsconfig.json
├── vite.config.ts
├── tailwind.config.js
├── postcss.config.js
├── .gitignore
└── README.md
```
## 🚀 Getting Started
```bash
# Install dependencies (in progress)
npm install
# Start dev server
npm run dev
# Open in browser
# http://localhost:3000
```
## 🎯 Current Status
### Ready to Use ✅
- Project structure complete
- All core components built
- Responsive design implemented
- Nostr integration ready
- Development server configured
### Needs Integration ⏳
- **Real IndeeHub content** - Waiting for film data/API access
- **Authentication** - NIP-98 Nostr auth or IndeeHub credentials
- **Image CDN** - Real thumbnail and backdrop URLs
## 🔄 Next Steps (When You're Ready)
### Phase 1: Content Integration
1. Get film data from IndeeHub.studio
2. Update `src/stores/content.ts` with real data
3. Configure API endpoints in `src/utils/indeeHubApi.ts`
4. Add authentication flow
### Phase 2: Additional Features
1. Content detail page
2. Search functionality
3. User profiles and My List
4. Creator pages
5. Video playback from Nostr events
### Phase 3: Node Integration
1. Package for Umbrel
2. Package for Start9
3. Package for Archy
4. Add Bitcoin payment integration
## 🎨 Design Features
- **Glass morphism** - Frosted glass UI elements
- **Smooth animations** - Fade, slide, scale effects
- **Netflix-style** - Hero section, content rows, hover effects
- **Mobile-optimized** - Touch gestures, bottom nav, safe areas
- **Dark theme** - Black/gradient backgrounds
- **Accessibility** - WCAG AA compliant
## 🔗 Nostr Integration
The app uses **nostr-tools** for:
- Fetching video events (NIP-71)
- Creator discovery
- Real-time content updates
- Decentralized content delivery
## 🛠️ Technology Stack
| Layer | Technology |
|-------|------------|
| Frontend | Vue 3 + TypeScript |
| Build | Vite 7 |
| Styling | Tailwind CSS 3.4 |
| State | Pinia 3 |
| Router | Vue Router 4.6 |
| Protocol | Nostr (nostr-tools 2.22) |
| Package | npm |
## 📱 Platform Support
- ✅ Web (Desktop browsers)
- ✅ Mobile web (iOS/Android)
- ⏳ Umbrel app package
- ⏳ Start9 app package
- ⏳ Archy app package
## 🎉 You're All Set!
Once npm install completes, run:
```bash
npm run dev
```
Then open http://localhost:3000 to see your Netflix-style streaming interface! 🍿
---
**The foundation is complete. Ready to add real IndeeHub content whenever you're ready!** 🚀

285
README.md
View File

@@ -1,258 +1,61 @@
# Indeedhub Prototype
# IndeeHub
A modern streaming platform for independent films built with Vue 3, featuring dual authentication (Cognito + Nostr), glassmorphic UI, and PWA capabilities.
A decentralized streaming platform for independent films built with Vue 3, Nostr authentication, glassmorphic UI, and PWA capabilities.
## 🚀 Quick Start
## Quick Start
### Development (frontend only)
```bash
# Install dependencies
npm install
# Start development server
npm run dev
# Open http://localhost:3000 (or the port shown in terminal)
```
**That's it!** The app runs with mock data by default. No backend required for development.
## ✨ Features
### Current (Working Now)
-**Glassmorphic UI** - Beautiful, modern design with backdrop blur effects
-**Splash Animation** - Logo intro animation on first load
-**Browse Films** - Netflix-style content rows with scroll navigation
-**Authentication** - Email/password + Nostr login (works in dev mode!)
-**Subscription Modals** - 3 tiers with pricing
-**Rental Modals** - Pay-per-view content access
-**User Profile** - Profile management and subscription status
-**User Library** - Continue watching, rented content tracking
-**PWA Support** - Install as native app on mobile/desktop
-**Responsive** - Mobile-first design, works on all screen sizes
### Backend Integration (Ready)
-**API Service Layer** - Axios client with auto-retry and token refresh
-**Content API** - Fetch projects/films from backend
-**Nostr Client** - Comments, reactions, social features
-**Access Control** - Subscription and rental verification
-**Route Guards** - Protected routes for auth-required pages
## 📱 Try It Out
### Without Backend (Development Mode)
```bash
npm run dev
```
**What works:**
- Browse all films (mock data)
- Sign in with any email/password (creates mock user)
- Sign in with Nostr (needs browser extension)
- Navigate to Profile and Library pages
- Open subscription and rental modals
- See responsive mobile/desktop layouts
Open http://localhost:5174. The app runs with mock data by default. No backend required.
**Console shows:** `🔧 Development mode: Using mock authentication`
### With Backend (Production Mode)
**1. Start the backend:**
```bash
cd ../indeehub-api
npm run start:dev # Runs on http://localhost:4000
```
**2. Configure frontend:**
```bash
# Create .env file
cp .env.example .env
# Edit .env
VITE_USE_MOCK_DATA=false
VITE_API_URL=http://localhost:4000
```
**3. Restart frontend:**
```bash
npm run dev
```
**Now you have:**
- Real user registration/login
- Content from PostgreSQL database
- Subscription payments (when Stripe configured)
- Nostr social features
- Video streaming with DRM
## 📁 Project Structure
```
src/
├── components/ # Vue components
│ ├── AuthModal.vue # Login/register modal
│ ├── SubscriptionModal.vue # Subscription tiers
│ ├── RentalModal.vue # Content rental
│ ├── ContentRow.vue # Film carousel
│ ├── SplashIntro.vue # Logo animation
│ └── ToastContainer.vue # Notifications
├── views/ # Page components
│ ├── Browse.vue # Main browsing page
│ ├── Library.vue # User library
│ └── Profile.vue # User profile
├── stores/ # Pinia state management
│ ├── auth.ts # Authentication state
│ └── content.ts # Content/film data
├── services/ # API clients
│ ├── api.service.ts # Base HTTP client
│ ├── auth.service.ts # Auth API
│ ├── content.service.ts # Content API
│ ├── subscription.service.ts
│ └── library.service.ts
├── composables/ # Vue composables
│ ├── useAuth.ts # Auth helper
│ ├── useNostr.ts # Nostr features
│ ├── useAccess.ts # Access control
│ └── useToast.ts # Notifications
├── lib/ # External integrations
│ └── nostr.ts # Nostr client
├── utils/ # Utilities
│ └── mappers.ts # API data transformers
└── router/ # Vue Router
├── index.ts # Routes
└── guards.ts # Auth guards
```
## 🎨 Design System
### Colors
- Pure Black: `#0a0a0a`
- White Text: `#FAFAFA`
- Accent: `#F7931A` (Bitcoin orange)
### Glassmorphism
```css
background: rgba(0, 0, 0, 0.65);
backdrop-filter: blur(40px);
border: 1px solid rgba(255, 255, 255, 0.08);
```
### Typography
- Headers: Bold, large scale (3-6rem)
- Body: 16-18px
- Spacing: 8px base grid
See `.cursor/rules/visual-design-system.mdc` for full details.
## 🔧 Commands
### Full stack (frontend + backend)
```bash
# Development
npm run dev # Start dev server with HMR
npm run build # Build for production
npm run preview # Preview production build
# Option A: Docker Compose
docker compose -f docker-compose.dev.yml up
# Option B: Script (starts Postgres, Redis, MinIO, backend, frontend)
bash scripts/dev.sh
```
See [ARCHITECTURE.md](ARCHITECTURE.md) for a quick stack comparison, [docs/ARCHITECTURE.html](docs/ARCHITECTURE.html) for the full document with pros/cons, and [DEPLOYMENT.md](DEPLOYMENT.md) for production deployment.
## Features
- **Nostr auth** — Extension (NIP-07), Remote Signer (NIP-46), or Private Key
- **Glassmorphic UI** — Browse with content rows, modals
- **Lightning payments** — BTCPay Server for subscriptions, rentals, zaps
- **PWA** — Install as native app on mobile/desktop
- **Responsive** — Mobile-first design
## Auth Options
| Method | Description |
|--------|-------------|
| Extension | NIP-07 browser extension (Alby, nos2x) |
| Remote Signer | NIP-46 — QR code (desktop) or link (mobile) to Primal, Amber, etc. |
| Private Key | Paste nsec for direct sign-in |
## Commands
```bash
npm run dev # Dev server (port 5174)
npm run build # Production build
npm run type-check # TypeScript validation
# Docker
docker-compose up -d # Start container (port 7777)
docker-compose down # Stop container
docker-compose logs -f # View logs
```
## 📚 Documentation
## Documentation
- **[BACKEND_INTEGRATION.md](BACKEND_INTEGRATION.md)** - Full backend integration guide
- **[UI_INTEGRATION.md](UI_INTEGRATION.md)** - How UI connects to backend
- **[DEV_AUTH.md](DEV_AUTH.md)** - Development mode authentication
- **`.cursor/rules/`** - Design system and coding standards
- [ARCHITECTURE.md](ARCHITECTURE.md) — Quick stack comparison; [docs/ARCHITECTURE.html](docs/ARCHITECTURE.html) — Full doc with pros/cons
- [DEPLOYMENT.md](DEPLOYMENT.md) — Production deployment (Docker, Portainer)
- [DEV_AUTH.md](DEV_AUTH.md) Development mode auth
- [BACKEND_INTEGRATION.md](BACKEND_INTEGRATION.md) — Backend API integration
## 🔐 Authentication
## Tech Stack
### Development Mode (Mock)
- Any email/password works
- Creates temporary mock users
- Persists in sessionStorage
- Perfect for UI testing
### Production Mode (Real)
- AWS Cognito for email/password
- Nostr NIP-07 for decentralized auth
- JWT token management
- Automatic token refresh
## 🎬 Content
### Mock Data (Default)
- 30+ Bitcoin & indie films
- Featured: "God Bless Bitcoin"
- Categories: Bitcoin, Documentaries, Drama
- Located in `src/data/indeeHubFilms.ts`
### Real Data (Backend)
- Fetches from `/projects` API
- Filters by type, genre, status
- Streaming URLs with DRM
- Progress tracking
## 🌐 Deployment
### Production Build
```bash
npm run build
# Output in dist/
```
### Docker
```bash
docker-compose up -d
# Available at http://localhost:7777
```
### Environment Variables
```bash
VITE_API_URL=https://api.indeedhub.com
VITE_CDN_URL=https://cdn.indeedhub.com
VITE_USE_MOCK_DATA=false
VITE_NOSTR_RELAYS=wss://relay.damus.io
VITE_ENABLE_NOSTR=true
VITE_ENABLE_LIGHTNING=true
VITE_ENABLE_RENTALS=true
```
## 🐛 Troubleshooting
### "Unable to connect to server"
✅ Fixed! App now works in development mode without backend.
See [DEV_AUTH.md](DEV_AUTH.md) for details.
### Build errors
```bash
npm run type-check # Check TypeScript errors
npm run build # Full build with validation
```
### Port already in use
Vite will automatically try the next available port (3001, 3002, etc.)
## 🤝 Contributing
This project follows strict design and code quality standards:
- See `.cursor/rules/master-philosophy.mdc`
- Mobile-first responsive design
- Glassmorphic UI patterns
- TypeScript for type safety
- WCAG AA accessibility
## 📄 License
Proprietary - IndeedHub
## 🔗 Related Repositories
- **indeehub-api** - NestJS backend API
- **indeehub-frontend** - Legacy React frontend (being replaced)
- **indeehub** - Nostr messaging integration
---
**Built with:**
Vue 3 • TypeScript • Tailwind CSS • Vite • Pinia • Vue Router • Nostr Tools • Axios
Vue 3 • TypeScript • Tailwind CSS • Vite • Pinia • Nostr (NIP-07, NIP-46, NIP-98) • BTCPay • MinIO

View File

@@ -1,101 +1,44 @@
ENVIRONMENT=local # local | development | production
ENVIRONMENT=local
# App - Local
# App
PORT=4000
DOMAIN=localhost:4000
FRONTEND_URL=http://localhost:3000
FRONTEND_URL=http://localhost:5174
# DB - API
# PostgreSQL
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=local
DATABASE_NAME=indeehub
DATABASE_USER=indeedhub
DATABASE_PASSWORD=your_password
DATABASE_NAME=indeedhub
# DB - EVENTS/ANALYTICS (POSTHOG)
DATABASE_POSTHOG_HOST=localhost
DATABASE_POSTHOG_PORT=5434
DATABASE_POSTHOG_USER=postgres
DATABASE_POSTHOG_PASSWORD=local
DATABASE_POSTHOG_NAME=staging
# Trascoding Queue - Local
# Redis (BullMQ)
QUEUE_HOST=localhost
QUEUE_PORT=6379
QUEUE_PASSWORD=
# BTCPay Server - Bitcoin/Lightning Payments
BTCPAY_URL=https://btcpay.yourdomain.com
# MinIO (S3-compatible storage)
S3_ENDPOINT=http://localhost:9000
AWS_REGION=us-east-1
AWS_ACCESS_KEY=minioadmin
AWS_SECRET_KEY=minioadmin123
S3_PRIVATE_BUCKET_NAME=indeedhub-private
S3_PUBLIC_BUCKET_NAME=indeedhub-public
S3_PUBLIC_BUCKET_URL=http://localhost:7777/storage/
# BTCPay Server (Lightning payments)
BTCPAY_URL=https://your-btcpay.com
BTCPAY_STORE_ID=
BTCPAY_API_KEY=
BTCPAY_WEBHOOK_SECRET=
# Create a separate internal Lightning invoice with privateRouteHints.
# Only needed when BTCPay's built-in route hints are NOT enabled.
# If you enabled "Include hop hints" in BTCPay's Lightning settings,
# leave this as false — BTCPay handles route hints natively.
BTCPAY_ROUTE_HINTS=false
# User Pool - AWS Cognito
COGNITO_USER_POOL_ID=
COGNITO_CLIENT_ID=
# Nostr auth (required)
NOSTR_JWT_SECRET=generate_with_openssl_rand_hex_32
NOSTR_JWT_EXPIRES_IN=7d
# Sendgrid - Email Service
SENDGRID_API_KEY=
SENDGRID_SENDER=
SENDGRID_WAITLIST=
# Content encryption (required for transcoding)
AES_MASTER_SECRET=generate_64_hex_chars
# AWS KEYS
AWS_ACCESS_KEY=
AWS_SECRET_KEY=
AWS_REGION=
# AWS S3
S3_PUBLIC_BUCKET_URL=
S3_PUBLIC_BUCKET_NAME=
# AWS CloudFront
CLOUDFRONT_PRIVATE_KEY=
CLOUDFRONT_KEY_PAIR_ID=
# Note: Stripe has been removed. All payments are now via BTCPay Server (Lightning).
# PAY WITH FLASH - ENTHUSIAST SUBSCRIPTION
FLASH_JWT_SECRET_ENTHUSIAST=
# PAY WITH FLASH - FILM BUFF SUBSCRIPTION
FLASH_JWT_SECRET_FILM_BUFF=
# PAY WITH FLASH - CINEPHILE SUBSCRIPTION
FLASH_JWT_SECRET_CINEPHILE=
# PAY WITH FLASH - RSS ADDON SUBSCRIPTION
FLASH_JWT_SECRET_RSS_ADDON=
# PAY WITH FLASH - VERIFICATION ADDON SUBSCRIPTION
FLASH_JWT_SECRET_VERIFICATION_ADDON=
# Transcoding API
TRANSCODING_API_KEY=
TRANSCODING_API_URL=http://localhost:4001
# Podping - RSS Update Notifications
PODPING_URL=https://podping.cloud/
PODPING_KEY=
PODPING_USER_AGENT=
# Retool API KEY - Admin Dashboard
# Admin API (optional)
ADMIN_API_KEY=
# PostHog - Analytics
POSTHOG_API_KEY=
# Sentry - Error Tracking
SENTRY_ENVIRONMENT=
# BUYDRM
PRIVATE_AUTH_CERTIFICATE_KEY_ID =
DRM_SECRET_NAME =
# Project Review
DASHBOARD_REVIEW_URL = https://oneseventech.retool.com/apps/5e86de84-7cdb-11ef-998f-47951c6124a1/Testing%20IndeeHub/film-details?id=
PROJECT_REVIEW_RECIPIENT_EMAIL = <your email>

View File

@@ -49,6 +49,7 @@
"class-validator": "^0.14.1",
"dayjs": "^1.11.13",
"fast-xml-parser": "^5.2.0",
"helmet": "^8.1.0",
"jsonwebtoken": "^9.0.3",
"jwks-rsa": "^3.0.1",
"moment": "^2.30.1",
@@ -14299,6 +14300,15 @@
"node": ">= 0.4"
}
},
"node_modules/helmet": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz",
"integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/homedir-polyfill": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",

View File

@@ -111,6 +111,7 @@
"class-validator": "^0.14.1",
"dayjs": "^1.11.13",
"fast-xml-parser": "^5.2.0",
"helmet": "^8.1.0",
"jsonwebtoken": "^9.0.3",
"jwks-rsa": "^3.0.1",
"moment": "^2.30.1",

View File

@@ -5,35 +5,62 @@ import {
Logger,
UnauthorizedException,
} from '@nestjs/common';
import { CognitoJwtVerifier } from 'aws-jwt-verify';
import { verify } from 'jsonwebtoken';
import { Socket } from 'socket.io';
interface NostrSessionPayload {
sub: string;
typ: 'nostr-session' | 'nostr-refresh';
uid?: string;
}
/**
* WebSocket JWT auth guard.
* Validates Nostr session JWTs (signed with NOSTR_JWT_SECRET).
* Replaces legacy Cognito-based validation.
*/
@Injectable()
export class WsJwtAuthGuard implements CanActivate {
static async validateToken(client: Socket) {
const authorization = this.extractTokenFromHeader(client.handshake);
if (!authorization) throw new UnauthorizedException();
const verifier = CognitoJwtVerifier.create({
userPoolId: process.env.COGNITO_USER_POOL_ID,
tokenUse: 'id',
clientId: process.env.COGNITO_CLIENT_ID,
});
await verifier.verify(authorization);
return true;
}
private static extractTokenFromHeader(request: any): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
async canActivate(context: ExecutionContext) {
static async validateToken(client: Socket): Promise<boolean> {
const token = WsJwtAuthGuard.extractTokenFromHeader(client.handshake);
if (!token) throw new UnauthorizedException('No token provided');
const secret = process.env.NOSTR_JWT_SECRET;
if (!secret) {
Logger.error('NOSTR_JWT_SECRET not configured', 'WsJwtAuthGuard');
throw new UnauthorizedException('Server misconfiguration');
}
try {
const payload = verify(token, secret) as NostrSessionPayload;
if (payload.typ !== 'nostr-session') {
throw new UnauthorizedException('Invalid token type');
}
(client as Socket & { data?: { pubkey?: string } }).data = {
pubkey: payload.sub,
};
return true;
} catch (error) {
if (error instanceof UnauthorizedException) throw error;
Logger.warn(`WebSocket token validation failed: ${error?.message}`);
throw new UnauthorizedException('Invalid or expired token');
}
}
async canActivate(context: ExecutionContext): Promise<boolean> {
if (context.getType() !== 'ws') return true;
const client: Socket = context.switchToWs().getClient();
try {
await WsJwtAuthGuard.validateToken(client);
return true;
} catch (error) {
Logger.error(`Error validating token: ${error.message}`);
if (error instanceof UnauthorizedException) throw error;
Logger.warn(`WebSocket auth failed: ${error?.message}`);
throw new UnauthorizedException();
}
}

View File

@@ -38,24 +38,41 @@ interface TranscodeJobData {
drmMediaId?: string;
}
const isProduction = process.env.ENVIRONMENT === 'production';
function requireEnv(name: string): string {
const val = process.env[name];
if (isProduction && !val) {
throw new Error(`FFmpeg worker: ${name} is required in production`);
}
return val || '';
}
const s3 = new S3Client({
region: process.env.AWS_REGION || 'us-east-1',
endpoint: process.env.S3_ENDPOINT || 'http://minio:9000',
forcePathStyle: true,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY || 'minioadmin',
secretAccessKey: process.env.AWS_SECRET_KEY || 'minioadmin123',
accessKeyId: isProduction
? requireEnv('AWS_ACCESS_KEY')
: process.env.AWS_ACCESS_KEY || 'minioadmin',
secretAccessKey: isProduction
? requireEnv('AWS_SECRET_KEY')
: process.env.AWS_SECRET_KEY || 'minioadmin123',
},
});
const privateBucket = process.env.S3_PRIVATE_BUCKET_NAME || 'indeedhub-private';
const privateBucket =
process.env.S3_PRIVATE_BUCKET_NAME || 'indeedhub-private';
function getPgClient(): Client {
return new Client({
host: process.env.DATABASE_HOST || 'postgres',
port: Number(process.env.DATABASE_PORT || '5432'),
user: process.env.DATABASE_USER || 'indeedhub',
password: process.env.DATABASE_PASSWORD || 'indeedhub_dev_2026',
password: isProduction
? requireEnv('DATABASE_PASSWORD')
: process.env.DATABASE_PASSWORD || 'indeedhub_dev_2026',
database: process.env.DATABASE_NAME || 'indeedhub',
});
}

View File

@@ -8,6 +8,7 @@ import {
ExpressAdapter,
NestExpressApplication,
} from '@nestjs/platform-express';
import helmet from 'helmet';
import { RawBodyRequest } from './types/raw-body-request';
import { validateEnvironment } from './common/validate-env';
@@ -49,6 +50,8 @@ async function bootstrap() {
useContainer(app.select(AppModule), { fallbackOnErrors: true });
app.use(helmet());
if (
process.env.ENVIRONMENT === 'development' ||
process.env.ENVIRONMENT === 'local'
@@ -73,6 +76,7 @@ async function bootstrap() {
'https://www.indeehub.studio',
'https://app.indeehub.studio',
'https://bff.indeehub.studio',
'https://archipelago.indeehub.studio',
];
if (process.env.FRONTEND_URL) {

View File

@@ -17,11 +17,17 @@
import { Client } from 'pg';
import { randomUUID } from 'node:crypto';
const isProduction = process.env.ENVIRONMENT === 'production';
const dbPassword = process.env.DATABASE_PASSWORD;
if (isProduction && !dbPassword) {
throw new Error('DATABASE_PASSWORD is required when ENVIRONMENT=production');
}
const client = new Client({
host: process.env.DATABASE_HOST || 'localhost',
port: Number(process.env.DATABASE_PORT || '5432'),
user: process.env.DATABASE_USER || 'indeedhub',
password: process.env.DATABASE_PASSWORD || 'indeedhub_dev_2026',
password: dbPassword || 'indeedhub_dev_2026',
database: process.env.DATABASE_NAME || 'indeedhub',
});

View File

@@ -50,7 +50,7 @@ sudo podman run -d \
--label "com.archipelago.version=0.1.0" \
--label "com.archipelago.category=media" \
--label "com.archipelago.description.short=Decentralized media streaming platform" \
--label "com.archipelago.description.long=IndeedHub is a decentralized media streaming platform built on Nostr. Stream Bitcoin-focused documentaries, educational content, and independent films. Netflix-inspired interface with glassmorphism design, supporting content creators through the decentralized web." \
--label "com.archipelago.description.long=IndeedHub is a decentralized media streaming platform built on Nostr. Stream Bitcoin-focused documentaries, educational content, and independent films. Streaming-style interface with glassmorphism design, supporting content creators through the decentralized web." \
--label "com.archipelago.license=MIT" \
--label "com.archipelago.icon=/assets/img/app-icons/indeedhub.png" \
--label "com.archipelago.port=7777" \

451
docs/ARCHITECTURE.html Normal file
View File

@@ -0,0 +1,451 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IndeeHub Architecture — Legacy vs Decentralized</title>
<style>
:root {
--bg: #0a0a0a;
--text: #FAFAFA;
--text-muted: #9ca3af;
--border: rgba(255, 255, 255, 0.1);
--accent: #F7931A;
--accent-secondary: #8E44AD;
--success: #22C55E;
--warning: #F59E0B;
}
* { box-sizing: border-box; }
body {
font-family: system-ui, -apple-system, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
margin: 0;
padding: 2rem;
max-width: 1200px;
margin-inline: auto;
}
h1 {
font-size: clamp(2rem, 5vw, 3rem);
font-weight: 700;
margin-bottom: 0.5rem;
background: linear-gradient(to right, var(--text), var(--text-muted));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.subtitle { color: var(--text-muted); font-size: 1rem; margin-bottom: 2rem; }
h2 {
font-size: 1.5rem;
font-weight: 600;
margin-top: 2.5rem;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border);
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 2rem;
font-size: 0.9375rem;
}
th, td {
padding: 0.75rem 1rem;
text-align: left;
border: 1px solid var(--border);
}
th {
background: rgba(255, 255, 255, 0.05);
font-weight: 600;
color: var(--text);
}
td { vertical-align: top; }
.legacy { color: var(--text-muted); }
.current { color: var(--success); font-weight: 500; }
.summary-cell {
font-size: 0.875rem;
max-width: 320px;
}
.summary-cell ul {
margin: 0.25rem 0 0 0;
padding-left: 1.25rem;
}
.summary-cell li { margin-bottom: 0.25rem; }
.pros { color: var(--success); }
.cons { color: var(--warning); }
.badge {
display: inline-block;
padding: 0.2rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
font-weight: 500;
}
.badge-new { background: rgba(34, 197, 94, 0.2); color: var(--success); }
.badge-replaced { background: rgba(245, 158, 11, 0.2); color: var(--warning); }
.intro {
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border);
border-radius: 0.5rem;
padding: 1rem 1.25rem;
margin-bottom: 2rem;
font-size: 0.9375rem;
}
footer {
margin-top: 3rem;
padding-top: 1.5rem;
border-top: 1px solid var(--border);
font-size: 0.875rem;
color: var(--text-muted);
}
@media (max-width: 768px) {
body { padding: 1rem; }
table { font-size: 0.8125rem; }
th, td { padding: 0.5rem; }
.summary-cell { max-width: none; }
}
</style>
</head>
<body>
<h1>IndeeHub Architecture</h1>
<p class="subtitle">Legacy vs Decentralized — Technology Stack, Auth, Processes &amp; Summary of Changes</p>
<div class="intro">
This document compares the original IndeeHub architecture (AWS, Cognito, Stripe, commercial DRM) with the decentralized prototype (Nostr, BTCPay, MinIO, self-hosted encryption). Both stacks support encryption and transcoding; the implementations differ.
</div>
<h2>Technology Stack</h2>
<table>
<thead>
<tr>
<th>Layer</th>
<th>Legacy</th>
<th>Current (Decentralized)</th>
<th>Summary of Changes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Auth</td>
<td class="legacy">Cognito</td>
<td class="current">Nostr (NIP-07, 46, 98)</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
<strong>What:</strong> Email/password → Nostr keys (extension, remote signer, nsec).
<ul>
<li class="pros">Pros: No central auth provider, censorship-resistant, portable identity</li>
<li class="cons">Cons: UX learning curve for non-Nostr users</li>
</ul>
</td>
</tr>
<tr>
<td>Payments</td>
<td class="legacy">Stripe</td>
<td class="current">BTCPay (Lightning)</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
<strong>What:</strong> Fiat card payments → Bitcoin Lightning invoices.
<ul>
<li class="pros">Pros: Self-custody, no payment processor lock-in, lower fees</li>
<li class="cons">Cons: Users need Lightning wallet; fiat off-ramp complexity</li>
</ul>
</td>
</tr>
<tr>
<td>Storage</td>
<td class="legacy">AWS S3 / CloudFront</td>
<td class="current">MinIO</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
<strong>What:</strong> Managed S3 + CDN → self-hosted S3-compatible MinIO.
<ul>
<li class="pros">Pros: Full control, no AWS dependency, S3 API compatible</li>
<li class="cons">Cons: You operate storage and CDN; scaling is manual</li>
</ul>
</td>
</tr>
<tr>
<td>Database</td>
<td class="legacy">PostgreSQL (RDS)</td>
<td class="current">PostgreSQL</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
<strong>What:</strong> Managed RDS → self-hosted PostgreSQL.
<ul>
<li class="pros">Pros: Same schema, no vendor lock-in</li>
<li class="cons">Cons: You manage backups, replication, upgrades</li>
</ul>
</td>
</tr>
<tr>
<td>Queue</td>
<td class="legacy"></td>
<td class="current">Redis + BullMQ</td>
<td class="summary-cell">
<span class="badge badge-new">New</span>
<strong>What:</strong> Legacy used external transcoding API; current uses BullMQ for job queue.
<ul>
<li class="pros">Pros: Explicit job queue, retries, progress tracking</li>
<li class="cons">Cons: Additional Redis dependency</li>
</ul>
</td>
</tr>
<tr>
<td>Relay</td>
<td class="legacy">External</td>
<td class="current">Self-hosted nostr-rs-relay</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
<strong>What:</strong> Third-party Nostr relay → self-hosted relay.
<ul>
<li class="pros">Pros: Data locality, no relay dependency</li>
<li class="cons">Cons: Relay ops and storage</li>
</ul>
</td>
</tr>
<tr>
<td>Deployment</td>
<td class="legacy">AWS ECS</td>
<td class="current">Docker / Portainer</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
<strong>What:</strong> Managed ECS → Docker Compose + Portainer.
<ul>
<li class="pros">Pros: Portable, runs anywhere, simpler ops</li>
<li class="cons">Cons: No auto-scaling; manual orchestration</li>
</ul>
</td>
</tr>
<tr>
<td>Frontend</td>
<td class="legacy">React</td>
<td class="current">Vue 3 + Vite</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
<strong>What:</strong> React → Vue 3 + Vite.
<ul>
<li class="pros">Pros: Faster builds, Composition API, smaller bundle</li>
<li class="cons">Cons: Different ecosystem, migration effort</li>
</ul>
</td>
</tr>
<tr>
<td>Backend</td>
<td class="legacy">NestJS</td>
<td class="current">NestJS</td>
<td class="summary-cell">
<strong>What:</strong> Unchanged. Same NestJS backend, different integrations.
</td>
</tr>
</tbody>
</table>
<h2>Auth Flow</h2>
<table>
<thead>
<tr>
<th>Step</th>
<th>Legacy</th>
<th>Current</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td class="legacy">Email + password</td>
<td class="current">Extension, Remote Signer, or nsec</td>
<td class="summary-cell">User proves identity via Nostr key instead of password.</td>
</tr>
<tr>
<td>2</td>
<td class="legacy">Cognito validates</td>
<td class="current">Nostr signs NIP-98</td>
<td class="summary-cell">Backend verifies Nostr signature instead of calling Cognito.</td>
</tr>
<tr>
<td>3</td>
<td class="legacy">Cognito returns JWT</td>
<td class="current">Backend issues JWT</td>
<td class="summary-cell">Backend owns JWT issuance; no third-party auth provider.</td>
</tr>
<tr>
<td>4</td>
<td class="legacy">JWT stored</td>
<td class="current">JWT stored</td>
<td class="summary-cell">Same client-side storage pattern.</td>
</tr>
</tbody>
</table>
<h2>Processes</h2>
<table>
<thead>
<tr>
<th>Process</th>
<th>Legacy</th>
<th>Current</th>
<th>Summary of Changes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Subscription</td>
<td class="legacy">Stripe Checkout</td>
<td class="current">BTCPay Lightning invoice</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
Fiat checkout → Lightning invoice. Same UX flow (redirect, webhook, activation).
</td>
</tr>
<tr>
<td>Rentals</td>
<td class="legacy">Stripe</td>
<td class="current">BTCPay invoice</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
Same pattern as subscriptions; payment method changed.
</td>
</tr>
<tr>
<td>Zaps</td>
<td class="legacy"></td>
<td class="current">BTCPay → creator address</td>
<td class="summary-cell">
<span class="badge badge-new">New</span>
Direct tips to creators via Lightning; not present in legacy.
</td>
</tr>
<tr>
<td>Encryption</td>
<td class="legacy">BuyDRM/KeyOS (Widevine/FairPlay)</td>
<td class="current">AES-128 HLS</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
<strong>What:</strong> Commercial DRM → self-hosted AES-128 HLS with key server.
<ul>
<li class="pros">Pros: No DRM vendor, no licensing fees, full control</li>
<li class="cons">Cons: Weaker protection than Widevine; key server is single point</li>
</ul>
</td>
</tr>
<tr>
<td>Transcoding</td>
<td class="legacy">External transcoding API (ECS)</td>
<td class="current">FFmpeg + MinIO</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
<strong>What:</strong> AWS ECS transcoding service → self-hosted FFmpeg worker.
<ul>
<li class="pros">Pros: No external API, no per-job vendor cost, same HLS output</li>
<li class="cons">Cons: You run FFmpeg; scaling is manual</li>
</ul>
</td>
</tr>
</tbody>
</table>
<h2>UI &amp; Design</h2>
<table>
<thead>
<tr>
<th>Aspect</th>
<th>Legacy</th>
<th>Current</th>
<th>Summary of Changes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Framework</td>
<td class="legacy">React</td>
<td class="current">Vue 3 + Vite</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
React → Vue 3 with Composition API. Vite for fast builds.
</td>
</tr>
<tr>
<td>Styling</td>
<td class="legacy">CSS-in-JS / styled-components</td>
<td class="current">Tailwind CSS + custom classes</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
Utility-first Tailwind; custom glass-card, hero-gradient, etc. 8px base grid.
</td>
</tr>
<tr>
<td>Visual style</td>
<td class="legacy">Traditional streaming UI</td>
<td class="current">Glassmorphism, gradients, dark-first</td>
<td class="summary-cell">
<span class="badge badge-replaced">Replaced</span>
Semi-transparent cards with backdrop blur; hero gradient overlays; bold typography.
</td>
</tr>
<tr>
<td>Colors</td>
<td class="legacy">Brand-specific (varies)</td>
<td class="current">#0a0a0a, #FAFAFA, #F7931A, #8E44AD</td>
<td class="summary-cell">
Design tokens: pure black (#0a0a0a), white text (#FAFAFA), brand primary/secondary.
</td>
</tr>
<tr>
<td>Layout</td>
<td class="legacy">Hero + content rows</td>
<td class="current">Hero + content rows + browse grid</td>
<td class="summary-cell">
Same pattern: featured hero, horizontal content rows. Responsive browse grid (sm/md/lg).
</td>
</tr>
<tr>
<td>Modals</td>
<td class="legacy">Auth, subscription, rental</td>
<td class="current">Auth, subscription, rental, zap, content detail, keys</td>
<td class="summary-cell">
<span class="badge badge-new">Expanded</span>
Added ZapModal (Lightning tips), ContentDetailModal, KeysModal (Nostr keys).
</td>
</tr>
<tr>
<td>PWA</td>
<td class="legacy"></td>
<td class="current">Installable, offline-capable</td>
<td class="summary-cell">
<span class="badge badge-new">New</span>
PWA support for install-as-app on mobile/desktop.
</td>
</tr>
<tr>
<td>Responsive</td>
<td class="legacy">Yes</td>
<td class="current">Mobile-first, 640/768/1024/1280 breakpoints</td>
<td class="summary-cell">
Mobile-first; same content on all breakpoints; layout adapts.
</td>
</tr>
</tbody>
</table>
<h2>High-Level Summary</h2>
<div class="intro">
<p><strong>Legacy</strong> relied on AWS (S3, CloudFront, RDS, ECS), Cognito, Stripe, and BuyDRM/KeyOS for encryption. Transcoding was done by an external ECS-based API. UI was React-based with traditional streaming layout.</p>
<p><strong>Decentralized</strong> replaces these with self-hosted or open components: MinIO, PostgreSQL, Nostr, BTCPay, AES-128 HLS, and an FFmpeg worker. Vue 3 + Tailwind with glassmorphism, expanded modals (zaps, keys), and PWA. The trade-off is more operational responsibility in exchange for independence from proprietary services.</p>
</div>
<footer>
IndeeHub Prototype · Architecture comparison · Generated from codebase (drm.service, transcoding-server, env examples).
</footer>
</body>
</html>

View File

@@ -108,7 +108,7 @@ html {
display: none;
}
/* Netflix-style hero gradient */
/* Hero gradient overlay */
.hero-gradient {
background: linear-gradient(
to top,

View File

@@ -44,7 +44,7 @@ export interface NostrEvent {
sig: string
}
// Content row for Netflix-style interface
// Content row for browse interface
export interface ContentRow {
title: string
contents: Content[]

View File

@@ -22,12 +22,11 @@ export interface IndeeHubFilm {
}
/**
* Fetch films from IndeeHub screening room
* TODO: Replace with actual API call when authenticated
* Fetch films from IndeeHub screening room.
* For authenticated requests, use indeehub-api.service which attaches NIP-98 tokens.
*/
export async function fetchFilms(): Promise<IndeeHubFilm[]> {
try {
// TODO: Add authentication headers (NIP-98 for Nostr auth)
const response = await fetch(`${INDEEDHUB_API}/screening-room?type=film`, {
headers: {
// Add your auth headers here

View File

@@ -82,11 +82,10 @@ class NostrService {
}
/**
* Publish a view/watch event
* Publish a view/watch event (NIP-XX view tracking — not yet implemented)
*/
async publishView(videoEventId: string) {
// TODO: Implement NIP-XX for view tracking
console.log('Publishing view for:', videoEventId)
async publishView(_videoEventId: string) {
// View tracking via Nostr not yet implemented
}
/**

View File

@@ -18,8 +18,8 @@ export default {
'glass-darker': 'rgba(0, 0, 0, 0.6)',
'glass-border': 'rgba(255, 255, 255, 0.18)',
'glass-highlight': 'rgba(255, 255, 255, 0.22)',
'netflix-red': '#E50914',
'netflix-black': '#141414',
'accent-red': '#E50914',
'surface-dark': '#141414',
},
boxShadow: {
'glass': '0 8px 24px rgba(0, 0, 0, 0.45)',