50 Commits

Author SHA1 Message Date
Dorian
99dd6894fd fix: default APP_PORT to 7755 to avoid conflicts 2026-03-17 00:44:23 +00:00
Dorian
e1f7394a6d fix: use POSTGRES_USER env var in healthcheck 2026-03-17 00:24:29 +00:00
Dorian
38293b1f95 feat: add comprehensive logging to payment cron for debugging
Every 10 minutes, the cron now logs:
- When it triggers and completes
- Satoshi rate fetched (or failure)
- Number of eligible shareholders found
- If 0 found: warns about shareholders with revenue but mismatched criteria
- Per-shareholder: revenue, filmmaker ID, lightning address
- Payment preparation: amount in sats, destination address
- Duplicate detection
- Payment send result (completed or failed with error)
- Revenue deduction confirmation

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 23:07:31 +00:00
Dorian
0e2f2b0a73 feat: allow dismissing sovereign flow to use traditional auth form
- "Go back" replaced with red italic "fuck you, I wanna be lame"
- After dismissing, sovereign trap no longer intercepts clicks
- Form fields become real inputs (email/password) for actual use
- sovereignDismissed state resets when modal reopens or closes

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 23:05:24 +00:00
Dorian
d8b8237300 copy: change sovereign flow text from NAH! to STOP!
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 23:02:47 +00:00
Dorian
169e03d72d style: keep Films rows as horizontal scroll with responsive card sizes
Cards now scale to match the Algos grid proportions at each breakpoint
(1/3, 1/4, 1/5, 1/6 of viewport) while remaining in a horizontally
scrolling flex row with nav buttons on desktop.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 23:02:27 +00:00
Dorian
0559876649 fix: make Algos/filter grid match Films rows at 6 cards per row
The filter grid was using md:grid-cols-3 (3 cards) while Films
horizontal rows showed 6. Updated to md:4 lg:5 xl:6 so both
views scale consistently across breakpoints.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:58:46 +00:00
Dorian
989dd75a84 style: change content grid from 5 to 6 cards per row on desktop
Cards were feeling too large at 5 per row. Updated calc to fit 6
cards uniformly across ContentRow and Browse (My List sections).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:56:35 +00:00
Dorian
ae97cbe67b fix: resolve AES-128 key delivery blocking HLS video playback
Root cause: HLS content is AES-128 encrypted, but the key endpoint
required mandatory auth (HybridAuthGuard). HLS.js fetches the key
without auth headers, causing a silent 401 and playback failure.

Backend:
- Changed key.controller.ts to use OptionalHybridAuthGuard
- Free content (price <= 0) now serves keys without authentication
- Paid content still requires auth, returns 401 for anon requests
- Added Content entity injection to look up pricing

Frontend:
- Configured HLS.js xhrSetup to attach Bearer token on /key requests
- Uses nostr_token or auth_token from sessionStorage
- Ensures logged-in users can play paid encrypted content

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:54:52 +00:00
Dorian
31a225ec15 fix: set Nostr Extension and Amber login buttons to exact 48px height
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:48:28 +00:00
Dorian
37b0bc654a style: left-to-right fade animations on sovereign phases + match close button to film modal
- NAH! text now slides in from the left with a scale punch and glow
- Own your privacy phase slides in from the left with a smooth fade
- Close button restyled to match ContentDetailModal (circular, glassmorphism, blur)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:47:56 +00:00
Dorian
19e8186a30 fix: default auth modal to 'Join IndeeHub' register mode
- Modal now opens in register mode by default instead of login
- Removed the subtitle text under the heading
- Fake form fields update based on mode (Create a password vs Enter)
- Toggle text reads "Already have an account? Sign in" first
- Forgot password only shows in login mode

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:46:46 +00:00
Dorian
90cdd030e1 feat: sovereign identity flow — NAH! animation + keypair generation
When users click on the legacy email/password form, the form zooms
out and a bold "NAH!" animates in. This transitions to an
"Own your privacy" message with a "Generate Sovereign Identity"
button that creates a new Nostr keypair, logs the user in, and
presents a red glassmorphism "Download your new identity" button
that saves the nsec/npub keypair to a text file.

Uses applesauce PrivateKeyAccount.fromKey() for proper account
registration and persistence.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:43:23 +00:00
Dorian
941d8917f3 style: dark glass button for Nostr Extension login + or-divider
Replaced the hero-info-button class with a dark glass morphism style
matching the nav buttons — dark translucent background, subtle inset
highlight, backdrop blur, and hover lift. Added an -or- divider
between the Nostr Extension and Amber login options.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:39:34 +00:00
Dorian
6480d02b11 style: use deep black glass morphism for content detail modal
Replace the flat #141414 grey background with a dark glass container
matching the header's floating-glass style — rgba(6,6,6,0.92) with
backdrop-filter blur, subtle white/6% border, and layered shadows.
Updated the hero gradient to blend seamlessly into the new base.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:38:45 +00:00
Dorian
7da4104aa2 fix: move search icon to the left of Sign In button on desktop
Reordered the right-side header actions so the search icon appears
before the Sign In button when the user is not authenticated.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:37:44 +00:00
Dorian
0917410c9e fix: add stream diagnostics and project-ID fallback for video playback
- Stream endpoint now accepts both content ID and project ID,
  falling back to project lookup when content ID is not found
- Added /contents/:id/stream-debug diagnostic endpoint that checks
  file existence in both private and public MinIO buckets
- Stream endpoint now verifies raw file exists before generating
  presigned URL, returning a clear error if file is missing
- Added comprehensive logging throughout the stream pipeline
- VideoPlayer now logs stream URL, API responses, and playback errors
  to browser console for easier debugging
- Bumped CACHEBUST for frontend (19), API (11), and ffmpeg-worker (13)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:36:41 +00:00
Dorian
f715534c06 fix: show exactly 5 content cards per row on desktop across all tabs
Cards used a fixed 280px width which showed ~6 on most desktops.
Algorithm filter tabs used a 5-column grid. This mismatch caused
layout jumping when switching tabs.

Now uses calc((100vw - 12rem) / 5) so exactly 5 cards are visible
on desktop for all scroll rows (Films, My List, Rentals, etc.),
matching the 5-column grid in filter views. Mobile stays at 200px.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:26:40 +00:00
Dorian
6bb95fd004 fix: Amber login on mobile with two-phase clipboard flow
Mobile browsers block navigator.clipboard.readText() unless called
inside a user gesture (tap/click). The old flow relied on the
visibilitychange event to auto-read the clipboard when the user
returned from Amber, which silently failed.

New flow:
1. User taps "Sign in with Amber" → opens Amber via Android intent
2. User approves in Amber → pubkey copied to clipboard
3. User returns to browser → sees "Complete Sign-in" button
4. User taps "Complete Sign-in" → clipboard read succeeds (user gesture)
5. Pubkey decoded, account registered, backend session created

Also handles npub/nprofile decoding and provides clear error messages
for empty clipboard, missing permissions, and non-Android devices.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:23:34 +00:00
Dorian
2fdb119ee5 fix: show backstage films on all content sources, not just IndeeHub API
The filmmakerService.usesSelfHosted() was tied to the content source
toggle, returning true only for 'indeehub-api'. When the user switched
to 'topdocfilms' or 'indeehub', the mergePublishedFilmmakerProjects()
function routed filmmaker API calls to the wrong (external) API, so
backstage-created films never appeared.

Now in production (USE_MOCK=false), filmmaker operations always use
the self-hosted backend regardless of which content catalog is active.
The content source toggle only affects the browse page catalog display.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:20:14 +00:00
Dorian
faa419fc28 fix: serve service worker with no-cache headers via exact-match location
The sw.js and workbox-*.js files were being caught by the immutable
static asset regex (expires 1y), causing stale service workers and
potential 502 errors during re-registration. Use location = /sw.js
(exact match, highest Nginx priority) and a regex for workbox files
that appears before the asset cache block.

Also removes the dead duplicate location blocks at the bottom of
the config that were never reached due to regex priority.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 22:16:13 +00:00
Dorian
ad4a9f48b6 ui: hide Persona switcher and Extension button from header
These are dev/testing tools that shouldn't be visible in production.
Commented out for now so they can be re-enabled easily.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 21:58:24 +00:00
Dorian
c84c4e92b7 fix: widen rents.usd_amount column, add webhook alias, silence cron spam
- Migration to ALTER rents.usd_amount from numeric(5,2) to numeric(15,2)
  which was causing "numeric field overflow" 500 errors when saving
  rental prices >= 1000 sats (e.g. 1200 sats)
- Also widen season_rents.usd_amount for consistency
- Add /webhooks/btcpay route alias (BTCPay was posting to /btcpay but
  the endpoint was /btcpay-webhook, causing 404s on payment callbacks)
- Skip ECS autoscaling cron when TRANSCODING_API_URL is not set
  (eliminates "security token invalid" error spam every minute)
- Reduce payment cron from EVERY_MINUTE to EVERY_10_MINUTES to avoid
  429 rate limiting on the BTC price API
- Bump API CACHEBUST to 10

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 21:30:29 +00:00
Dorian
5244fdef50 Fix poster 404: add ^~ to /storage/ locations to override static asset regex
Nginx was serving /storage/.../*.jpg from the local filesystem instead of
proxying to MinIO because the static asset regex location (~* \.(jpg|...)$)
takes priority over plain prefix locations. Adding ^~ ensures the /storage/
and /storage-private/ prefix locations always win over regex matches.

Same root cause as the earlier 405 on thumbnail uploads.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 21:18:11 +00:00
Dorian
7f78ac9ba6 Fix FFmpeg worker: align job data format with API and update content status
The worker was completely broken because of 4 mismatches with the API:

1. Field names: API sends {correlationId, inputKey, outputKey, inputBucket,
   outputBucket} but worker expected {contentId, sourceKey, outputPrefix}.
   All fields were undefined, so jobs silently failed.

2. No status callback: Worker never updated content status to 'completed',
   so projects never appeared as published (content stuck in 'processing').
   Now updates status directly in PostgreSQL.

3. Wrong bucket: Worker uploaded HLS to private bucket, but the stream
   controller checks the public bucket. Now uploads to outputBucket (public).

4. Wrong manifest name: Worker output index.m3u8 but codebase expects
   file.m3u8. Aligned with helper.ts convention.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 21:07:24 +00:00
Dorian
f6c4b9f06c Fix false "Rented" state for project owners + add "Your project" badge
The rental check catch block was incorrectly setting hasActiveRental=true
for project owners when the API call failed (e.g. auth token not synced).
This showed a "Rented" badge with no time remaining and hid the rent button.

- Separate "owner can play" from "has active rental" via new isOwner computed
- canPlay now includes isOwner so owners always have playback access
- Catch block no longer fakes a rental — keeps the badge accurate
- New purple "Your project" badge for owners (distinct from green "Rented")

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 20:48:58 +00:00
Dorian
3e4279e252 Fix 405 on thumbnail uploads: move MinIO proxy above static asset regex
Nginx regex locations are evaluated in order — the static asset caching
rule (.jpg, .png, etc.) was matching image upload URLs before the MinIO
bucket proxy could handle them, causing PUT requests to return 405.

Moved the /indeedhub-*/ proxy location to the top of the regex block.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 20:36:03 +00:00
Dorian
fc20c625fa Fix Mixed Content on file uploads: presigned URLs now use public domain
The backend was generating presigned S3 URLs pointing to the internal
MinIO endpoint (http://minio:9000), which browsers block on HTTPS pages.

- Add a second S3 client in upload.service.ts configured with FRONTEND_URL
  for generating browser-facing presigned URLs (both upload and download)
- Add nginx proxy location for /indeedhub-private/ and /indeedhub-public/
  paths that forwards to MinIO without rewriting (preserves S3v4 signatures)
- Keep internal S3 client for server-side operations (copy, delete, etc.)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 20:30:49 +00:00
Dorian
abb83fe164 Bump CACHEBUST to v8 for backend and frontend rebuilds; update Nginx and NostrAuthGuard to handle X-Forwarded-Prefix for NIP-98 compliance 2026-02-13 20:20:32 +00:00
Dorian
dea2d2e768 Bump CACHEBUST to v7 to force rebuild with payment_methods fix
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 20:08:36 +00:00
Dorian
4f7fdd4413 Fix missing payment_methods table creation + bump CACHEBUST to v6
Migration AddedWithdrawalFrequency1733770884555 referenced payment_methods
table that was never created. Modified to CREATE TABLE IF NOT EXISTS with
all columns, then drop lightning_address from filmmakers.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 19:47:46 +00:00
Dorian
34c48d9f6e Fix apostrophe in Children's Animation migration + bump CACHEBUST to v5
Escape single quote in seed-episodic-subgenres migration that caused
"column Children's Animation does not exist" PostgreSQL error.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 19:34:31 +00:00
Dorian
f52e7dda7e Bump CACHEBUST to v4 to force backend rebuild with migration fixes
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 19:13:59 +00:00
Dorian
20718c547e Remove image tags that cause Portainer pull failures
Portainer tries to pull named images from Docker Hub before building.
Removing image: tags so it builds directly from Dockerfiles. The
CACHEBUST build arg handles cache invalidation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:41:21 +00:00
Dorian
82a5c0a5cf Fix entity-based migrations that crash on missing columns
MusicVideosUpdate and AddEpisodicGenres migrations used TypeORM
entity classes which reference columns that don't exist at their
migration timestamp (e.g. trailer_old, later entity fields).
Rewrote both to use raw SQL INSERT/UPDATE statements.

Also bumped CACHEBUST to v3 to force backend image rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:30:37 +00:00
Dorian
eeffce4baa Add versioned image tags to force Portainer to rebuild images
Docker was reusing old cached images even on redeploy. By adding
explicit image names with version tags (e.g. indeehub-app:v2),
Docker must build new images since the old ones had no tag or a
different tag. Bump the version (v2 -> v3) to force future rebuilds.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:11:51 +00:00
Dorian
bb281b488b Add CACHEBUST build arg to force Docker image rebuilds
Docker's build cache was preventing Portainer from picking up
code changes. Adding a CACHEBUST ARG before COPY invalidates
all subsequent layers when the value changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 18:05:40 +00:00
Dorian
330345c1ac Hardcode postgres healthcheck user to avoid variable substitution issues
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 17:54:46 +00:00
Dorian
e9c5c50ca3 Remove MinIO console port mapping to avoid host port conflicts
The MinIO S3 API is accessed internally via the Docker network.
The admin console is not needed externally and was causing
port 9001 conflicts with other services on the host.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 17:50:37 +00:00
Dorian
a66842d771 Update environment variables and refactor Docker configurations for improved deployment
- Revised .env.portainer to update sensitive credentials and streamline comments for clarity.
- Adjusted docker-compose.yml to remove unnecessary variable references, enhancing readability and maintainability.
- Updated VideoPlayer component to improve type handling and refactor seeking logic for better performance.
- Enhanced library service to include providerId in the rentContent method for improved data handling.
- Refactored auth store to integrate account management functionality.
- Cleaned up ProjectEditor and Settings views by removing unused computed properties and refining method types.
2026-02-13 16:40:10 +00:00
Dorian
a8dc82dc59 Update environment variables and enhance Docker configurations for improved deployment
- Modified .env.portainer to include new environment variables for S3 private bucket URL, Nostr JWT secrets, and SendGrid options.
- Updated docker-compose.yml to support the new environment variables, enhancing service configurations.
- Added a seed content script to the backend package.json for initializing the database with sample data.
- Refactored helper functions to construct S3 URLs more robustly, accommodating potential missing configurations.
- Enhanced dev.sh script to seed the database if empty, ensuring content availability during development.
2026-02-13 16:27:51 +00:00
Dorian
3ca43b62e4 Enhance Docker and backend configurations for improved deployment
- Updated docker-compose.yml to include environment variable support for services, enhancing flexibility in configuration.
- Refactored Dockerfile to utilize build arguments for VITE environment variables, allowing for better customization during builds.
- Improved Nginx configuration to handle larger video uploads by increasing client_max_body_size to 5GB.
- Enhanced backend Dockerfile to include wget for health checks and improved startup logging for database migrations.
- Added validation for critical environment variables in the backend to ensure necessary configurations are present before application startup.
- Updated content streaming logic to support direct HLS URL construction, improving streaming reliability and user experience.
- Refactored various components and services to streamline access checks and improve error handling during content playback.
2026-02-13 12:35:03 +00:00
Dorian
cdd24a5def Implement backend API and database services in Docker setup
- Added a new `api` service for the NestJS backend, including health checks and dependencies on PostgreSQL, Redis, and MinIO.
- Introduced PostgreSQL and Redis services with health checks and configurations for data persistence.
- Added MinIO for S3-compatible object storage and a one-shot service to initialize required buckets.
- Updated the Nginx configuration to proxy requests to the new backend API and MinIO storage.
- Enhanced the Dockerfile to support the new API environment variables and configurations.
- Updated the `package.json` and `package-lock.json` to include new dependencies for QR code generation and other utilities.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 20:14:39 +00:00
Dorian
dd4d5e99a4 Fix seeder: skip heavy devDeps, decouple app from seeder success
- Use npm ci --omit=dev to avoid building sharp (needs native libvips
  not available on Alpine) then install tsx separately
- Change app depends_on from seeder (service_completed_successfully)
  to relay only, so the app still starts even if seeding fails

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 12:56:31 +00:00
Dorian
42bd54783a Remove container_name from docker-compose to fix redeploy conflicts
Portainer fails to redeploy when the old containers still exist
with the same hardcoded names. Letting Compose auto-name them
based on the stack/project avoids the conflict.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 12:50:02 +00:00
Dorian
0a7543cf32 Add Nostr relay + seed data to Docker deployment
- Add nostr-rs-relay service to docker-compose for persistent
  comments, reactions, and profiles on the dev server
- Add one-shot seeder container that auto-populates the relay
  with test personas, reactions, and comments on first deploy
- Proxy WebSocket connections through nginx at /relay so the
  frontend connects to the relay on the same host (no CORS)
- Make relay URL dynamic: reads from VITE_NOSTR_RELAYS in dev,
  auto-detects /relay proxy path in production Docker builds
- Make seed scripts configurable via RELAY_URL and ORIGIN env vars
- Add wait-for-relay script for reliable container orchestration
- Add "Resume last played" hero banner on My List tab

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 12:33:22 +00:00
Dorian
a61da35357 Fix health check - use curl instead of wget
Issues fixed:
1. Removed duplicate health check from Dockerfile (docker-compose overrides it)
2. Switched from wget to curl (more reliable in alpine)
3. Installed curl in the Docker image
4. Simplified health check command

The health check now properly tests if Nginx is serving content on port 7777.
Container should show as healthy after 40s start period.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-03 00:22:04 +00:00
Dorian
3f99aaec43 Fix Docker health check - use root path instead of /health
The health check was failing because /health endpoint doesn't exist.
Changed to check the root path (/) which serves the Vue app.
This should prevent the container from restarting.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-03 00:16:18 +00:00
Dorian
04926961b7 Fix Docker image pull error by removing image tag
- Remove 'image: indeedhub-prototype:latest' line
- Force Docker to build from Dockerfile instead of trying to pull
- Fixes Portainer deployment error: 'pull access denied'

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-02 23:57:04 +00:00
Dorian
3f3849e76f Add Docker deployment support and PWA enhancements
- Add Dockerfile with multi-stage build (Node.js + Nginx)
- Add docker-compose.yml for Portainer stack deployment on port 7777
- Add nginx.conf with PWA support, gzip compression, and security headers
- Add .dockerignore for optimized Docker builds
- Add DEPLOYMENT.md with comprehensive deployment guide
- Configure Vite PWA plugin with service worker and offline support
- Add PWA manifest.json with app icons and shortcuts
- Enhance logo.svg with iOS-style glass effects (filters, gradients, highlights)
- Add app-icon.svg for PWA installation
- Update mobile nav with glassmorphic active tab styling
- Fix mobile tab bar layout shift issues with flex-1 and consistent sizing
- Update index.html with PWA meta tags and Apple-specific settings
- Add health check endpoint at /health for container monitoring

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-02 23:43:42 +00:00