Commit Graph

108 Commits

Author SHA1 Message Date
741e0c3387 docs: update README for custom backend replacing Directus
All checks were successful
Build and Push Backend Image / build (push) Successful in 17s
Build and Push Frontend Image / build (push) Successful in 17s
Replace all Directus references with the new Fastify + GraphQL Yoga
stack, update CI/CD references to dev.pivoine.art Gitea Actions,
add DB schema overview, auth flow, image transform presets table,
and fix all links to use https and correct registry URLs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 22:01:46 +01:00
662e3e8fe2 fix: model join date used join_date but API returns date_created
All checks were successful
Build and Push Backend Image / build (push) Successful in 17s
Build and Push Frontend Image / build (push) Successful in 4m13s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 21:42:34 +01:00
fa159feffa fix: remove black border below video controls
Some checks failed
Build and Push Backend Image / build (push) Successful in 16s
Build and Push Frontend Image / build (push) Has been cancelled
- video: inline → block w-full (eliminates baseline descender gap)
- media-controller: fill parent container with absolute inset-0 w-full h-full

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 21:41:07 +01:00
124f0bfb22 fix: video src used movie.id but movie is already the UUID string
All checks were successful
Build and Push Backend Image / build (push) Successful in 17s
Build and Push Frontend Image / build (push) Successful in 4m18s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 21:27:06 +01:00
df89cc59f5 fix: use preview transform for home page video teasers
Some checks failed
Build and Push Backend Image / build (push) Has been cancelled
Build and Push Frontend Image / build (push) Has been cancelled
thumbnail (300x300 square) was double-cropping inside the wide h-48
container. preview (800px, aspect-ratio preserved) lets object-cover
do the only crop, matching the videos and model pages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 21:24:59 +01:00
845e3df223 fix: image transforms — preserve aspect ratio, increase quality
Some checks failed
Build and Push Backend Image / build (push) Successful in 40s
Build and Push Frontend Image / build (push) Has been cancelled
- preview/medium use fit:inside (no forced crop, preserves aspect ratio)
- Only mini/thumbnail/banner force square/fixed crops
- Increase WebP quality 85 → 92
- Increase preview width 480 → 800, medium 960 → 1400

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 21:22:30 +01:00
05cb6a66e3 fix: image transforms via Sharp, model photos crash, video duration
All checks were successful
Build and Push Backend Image / build (push) Successful in 46s
Build and Push Frontend Image / build (push) Successful in 5m7s
- Backend: add Sharp image transform endpoint (/assets/:id?transform=X)
  with presets: mini(64), thumbnail(200), preview(480), medium(960), banner(1280)
  Transformed images are cached as webp next to originals
- Frontend: fix model photos crash (p.directus_files_id → p)
- Frontend: fix model banner URL (data.model.banner.id → data.model.banner)
- Frontend: fix video duration display (video.movie.duration → video.movie_file?.duration)
  across models/[slug], videos, videos/[slug], and home pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 20:56:33 +01:00
273aa42510 fix: serve assets via DB lookup to resolve file path correctly
All checks were successful
Build and Push Backend Image / build (push) Successful in 38s
Build and Push Frontend Image / build (push) Successful in 4m11s
Files are stored as <UPLOAD_DIR>/<id>/<filename>. The previous static
serving attempted to serve <UPLOAD_DIR>/<id> (a directory) which failed.
Custom /assets/:id route now looks up filename from DB and uses sendFile.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 20:40:22 +01:00
1e930baccb fix: resolve GraphQL request hang in Fastify integration
All checks were successful
Build and Push Backend Image / build (push) Successful in 39s
Build and Push Frontend Image / build (push) Successful in 4m7s
- Pass FastifyRequest/FastifyReply directly to yoga.handleNodeRequestAndResponse
  per the official graphql-yoga Fastify integration docs. Yoga v5 uses req.body
  (already parsed by Fastify) when available, avoiding the dead raw stream issue.
- Add proper TypeScript generics for server context including db and redis
- Wrap sendVerification/sendPasswordReset in try/catch so missing SMTP
  does not crash register/requestPasswordReset mutations
- Fix migrate.ts path resolution to work with both tsx (src/) and compiled (dist/)
- Expose postgres:5432 and redis:6379 ports in compose.yml for local dev

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 20:31:18 +01:00
012bb176d9 fix: convert Web API ReadableStream to Node.js Readable for Fastify
Some checks failed
Build and Push Backend Image / build (push) Failing after 26s
Build and Push Frontend Image / build (push) Successful in 4m17s
graphql-yoga's handleNodeRequestAndResponse returns a Response with a
Web API ReadableStream body. Fastify's reply.send() requires a Node.js
Readable stream, causing all GraphQL requests to hang indefinitely.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 20:11:08 +01:00
ed7ac0c573 fix: downgrade nanoid to v3 for CommonJS compatibility
All checks were successful
Build and Push Backend Image / build (push) Successful in 2m28s
Build and Push Frontend Image / build (push) Successful in 5m12s
nanoid v5 is ESM-only and cannot be require()'d in a CommonJS module.
v3 is the last version with native CJS support.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:43:44 +01:00
4565038be3 fix: cast recording duration float to integer in data migration
Some checks failed
Build and Push Backend Image / build (push) Successful in 39s
Build and Push Frontend Image / build (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:39:52 +01:00
fbafbeca5d fix: pass tags as native arrays not JSON strings in data migration
Some checks failed
Build and Push Backend Image / build (push) Successful in 38s
Build and Push Frontend Image / build (push) Has been cancelled
PostgreSQL text[] columns require native array values, not JSON strings.
Parse string tags from Directus and pass as JS arrays directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:36:04 +01:00
480369aa4e fix: correct column names in data migration script to match actual Directus schema
Some checks failed
Build and Push Backend Image / build (push) Successful in 37s
Build and Push Frontend Image / build (push) Has been cancelled
- directus_files: uploaded_on → date_created alias
- directus_users: join_date → date_created, remove email_notifications_key
- junction_directus_users_files: remove non-existent sort column
- sexy_videos: remove non-existent likes_count/plays_count (default 0)
- sexy_recordings: remove non-existent featured column (schema has default false)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:33:33 +01:00
ceb57ec1c4 fix: copy root node_modules to runner stage in backend Dockerfile
All checks were successful
Build and Push Backend Image / build (push) Successful in 30s
Build and Push Frontend Image / build (push) Successful in 15s
pnpm hoists workspace dependencies to the root node_modules.
Without copying it, modules like pg are not found at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:29:36 +01:00
4f8271217c fix: set CI=true for pnpm install in backend Dockerfile
All checks were successful
Build and Push Backend Image / build (push) Successful in 1m4s
Build and Push Frontend Image / build (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:26:25 +01:00
046689e363 fix: set CI=true for pnpm install -rP in frontend Dockerfile
Some checks failed
Build and Push Backend Image / build (push) Failing after 28s
Build and Push Frontend Image / build (push) Successful in 4m50s
pnpm requires CI=true to allow non-interactive removal of node_modules
in CI environments without a TTY.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:19:45 +01:00
9ba71239b7 fix: use correct 'file' parameter in docker/build-push-action (not 'dockerfile')
Some checks failed
Build and Push Frontend Image / build (push) Failing after 4m12s
Build and Push Backend Image / build (push) Failing after 25s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:09:58 +01:00
757bbe9e3b fix: skip buttplug Rust build in backend Dockerfile via --ignore-scripts
Some checks failed
Build and Push Backend Image / build (push) Has been cancelled
Build and Push Frontend Image / build (push) Has been cancelled
Copy all workspace package.json files so pnpm can resolve the lockfile,
but install with --ignore-scripts to prevent buttplug's Rust/WASM build
from running. Only explicitly rebuild argon2 native bindings.
Also restore the missing migrations COPY line.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:08:48 +01:00
73f7a4f2f0 ci: replace combined workflow with separate frontend and backend workflow files
Some checks failed
Build and Push Frontend Image / build (push) Has been cancelled
Build and Push Backend Image / build (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:05:54 +01:00
3bd8d95576 ci: disable registry cache for backend build to fix poisoned buildcache
All checks were successful
Build and Push Docker Image to Gitea / build-frontend (push) Successful in 15s
Build and Push Docker Image to Gitea / build-backend (push) Successful in 4m44s
The backend buildcache was contaminated with frontend image layers, causing
the backend image to be built with the wrong content. Using no-cache forces
a fresh build until the cache can be reliably separated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 18:57:39 +01:00
14e816241d ci: split frontend and backend into separate jobs to fix image tag mix-up
All checks were successful
Build and Push Docker Image to Gitea / build-frontend (push) Successful in 17s
Build and Push Docker Image to Gitea / build-backend (push) Successful in 16s
Both builds in the same job shared the same docker buildx instance,
causing the backend image to be incorrectly tagged with the frontend image.
Separate jobs get isolated buildx instances and separate build caches.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 18:53:16 +01:00
4102f9990c fix: switch backend to CommonJS, generate Drizzle migrations, add migrate script
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 4m23s
- Remove "type": "module" and switch tsconfig to CommonJS/Node resolution
  to fix drizzle-kit ESM/CJS incompatibility
- Strip .js extensions from all backend TypeScript imports
- Fix gamification resolver: combine two .where() calls using and()
- Fix index.ts: wrap top-level awaits in async main(), fix Fastify+yoga
  request handling via handleNodeRequestAndResponse
- Generate initial Drizzle SQL migration (0000_pale_hellion.sql) for all
  15 tables
- Add src/scripts/migrate.ts: programmatic Drizzle migrator for production
- Copy migrations folder into Docker image (Dockerfile.backend)
- Add schema:migrate npm script

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 18:42:58 +01:00
2565e6c28b fix: resolve pnpm frozen-lockfile error and argon2 native build
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 5m19s
- Run pnpm install to update lockfile with packages/backend dependencies
- Add argon2 to root onlyBuiltDependencies (pnpm-workspace.yaml + package.json)
- Add explicit `pnpm rebuild argon2` in Dockerfile.backend to ensure native
  bindings compile regardless of pnpm v10 build approval state
- Remove pnpm.onlyBuiltDependencies from packages/backend/package.json
  (ineffective in workspace packages, warned by pnpm)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 18:19:52 +01:00
493ddd7e78 chore: remove packages/bundle (Directus extension)
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 1m26s
All custom logic (endpoints, hooks, gamification) has been ported to
packages/backend. The Directus bundle is no longer needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 18:11:22 +01:00
33dd076a50 ci: add backend image build to docker workflow
Adds a second build+push step for the backend image (valknar/sexy-backend)
using Dockerfile.backend. Both images share the same tag strategy and
separate build caches. Summary step updated to show both images.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 18:10:06 +01:00
9d7afbe1b5 feat: replace Directus with custom Node.js GraphQL backend
Removes Directus 11 and replaces it with a lean, purpose-built backend:
- packages/backend/: Fastify v5 + GraphQL Yoga v5 + Pothos (code-first)
  with Drizzle ORM, Redis sessions (session_token cookie), argon2 auth,
  Nodemailer, fluent-ffmpeg, and full gamification system ported from bundle
- Frontend: @directus/sdk replaced by graphql-request v7; services.ts fully
  rewritten with identical signatures; directus.ts now re-exports from api.ts
- Cookie renamed directus_session_token → session_token
- Dev proxy target updated 8055 → 4000
- compose.yml: Directus service removed, backend service added (port 4000)
- Dockerfile.backend: new multi-stage image with ffmpeg
- Dockerfile: bundle build step and ffmpeg removed from frontend image
- data-migration.ts: one-time script to migrate all Directus/sexy_ tables

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 18:07:18 +01:00
de16b64255 fix: use env object from \$env/dynamic/public instead of named imports
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 5m13s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 17:19:26 +01:00
1e69d0b158 fix: create env placeholder file inline in Dockerfile for dynamic public env
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 4m6s
.dockerignore excludes .env files so the previous COPY failed silently.
$env/dynamic/public requires variable names to be declared at build time
to generate named exports; empty placeholders satisfy this while actual
values still come from process.env at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 17:09:42 +01:00
865787fb45 feat: switch PUBLIC_API_URL and PUBLIC_URL to dynamic env for runtime configurability
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 3m3s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 17:01:37 +01:00
3915dbc115 fix: .env inclusion
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 5m31s
2026-03-04 16:47:54 +01:00
83ca9d4fb5 chore: update all dependencies to latest versions
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 46s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 16:43:56 +01:00
225b9d41f5 chore: clean up repo and fix docker compose configuration
- Remove outdated docs (COMPOSE.md, DOCKER.md, QUICKSTART.md, REBUILD_GUIDE.md)
- Remove build.sh, compose.production.yml, gamification-schema.sql, directus.yaml
- Simplify compose.yml for local dev (remove env var indirection)
- Add directus.yml schema snapshot and schema.sql from VPS
- Add schema:export and schema:import scripts to package.json
- Ignore .env files (vars set via compose environment)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 16:36:49 +01:00
ad83fb553a feat: switch to dynamic env for Umami to allow runtime configuration
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 4m41s
2026-02-21 11:47:32 +01:00
2be36a679d fix: resolve buttplug-wasm build error by using Vec and slices
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 5m26s
2026-02-21 11:33:12 +01:00
75d4b4227c chore: update buttplug dependencies to commit fad6c9d
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 2m10s
2026-02-21 11:29:36 +01:00
2277e4f686 fix: resolve buttplug-wasm build error by using as_ref() for JS arrays
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 2m7s
2026-02-21 11:13:53 +01:00
13c6977e59 feat: add PUBLIC_UMAMI_SCRIPT variable and integrate into layout
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 2m13s
2026-02-21 11:05:30 +01:00
c85fa7798e chore: remove Letterspace newsletter integration and all LETTERSPACE_* variables 2026-02-21 10:56:43 +01:00
ce30eca574 chore: new imprint address 2026-02-21 10:37:19 +01:00
6724afa939 fix: use correct Directus preset parameter for asset transforms
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 6m4s
Changed ?transform= to ?key= so Directus storage asset presets
(mini, thumbnail, preview, medium, banner) are actually applied.
Previously all images were served at full resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 08:42:38 +01:00
e744d1e40f fix: clean up stale sorter entries and fix battery reactivity
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 5m44s
ButtplugMessageSorter never deleted entries from _waitingMsgs after
resolving, causing unsolicited DeviceList messages (with reused Ids)
to be swallowed. Also fix battery level not updating in UI by accessing
the device through the Svelte $state proxy array.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:07:13 +01:00
82be8b8859 fix: resolve device listing bug after buttplug v10 upgrade
Unwrap DeviceList wrapper message before passing to parseDeviceList(),
and rename FeatureDescriptor to FeatureDescription to match Rust v10 serde output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 12:11:53 +01:00
27d86fff8b fix: vite wasm rollup
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 5m33s
2026-02-06 15:08:32 +01:00
6ea4ed1933 feat: upgrade buttplug package to protocol v4 and WASM v10
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 7m30s
Upgrade the buttplug TypeScript client from class-based v3 protocol to
interface-based v4 protocol, and the Rust/WASM server from the monolithic
buttplug 9.0.9 crate to the split buttplug_core/buttplug_server/
buttplug_server_device_config 10.0.0 crates.

TypeScript changes:
- Messages are now plain interfaces with msgId()/setMsgId() helpers
- ActuatorType → OutputType, SensorType → InputType
- ScalarCmd/RotateCmd/LinearCmd → OutputCmd, SensorReadCmd → InputCmd
- Client.ts → ButtplugClient.ts, new DeviceCommand/DeviceFeature files
- Devices getter returns Map instead of array
- Removed class-transformer/reflect-metadata dependencies

Rust/WASM changes:
- Split imports across buttplug_core, buttplug_server, buttplug_server_device_config
- Removed ButtplugServerDowngradeWrapper (use ButtplugServer directly)
- Replaced ButtplugFuture/ButtplugFutureStateShared with tokio::sync::oneshot
- Updated Hardware::new for new 6-arg signature
- Uses git fork (valknarthing/buttplug) to fix missing wasm deps in buttplug_core

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 14:46:47 +01:00
fed2dd65e5 feat: display play count on video detail page
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 4m32s
- Add play count display below video title with play icon
- Query actual plays count from sexy_video_plays table for accuracy
- Apply same pattern as likes_count for consistency
- Show singular/plural ("play" vs "plays") based on count

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 19:23:36 +01:00
756d767d59 fix: align sharing button height with like button
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Has been cancelled
Remove size="sm" from SharingPopupButton to use default button height (h-9)
instead of small size (h-8), ensuring consistent button heights across all
action buttons on video, model, and article pages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 19:20:30 +01:00
ac09d544d4 fix: query actual likes count from database instead of cached field
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Has been cancelled
The likes_count field on videos was becoming inaccurate due to the manually
maintained counter getting out of sync with actual like records. Now we count
likes directly from the sexy_video_likes table for accurate counts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 19:17:32 +01:00
2c010c98d0 fix: use registry cache instead of GitHub Actions cache for Gitea compatibility
All checks were successful
Build and Push Docker Image to Gitea / build-and-push (push) Successful in 5m4s
2025-11-15 18:09:46 +01:00
3bdf58a827 fix: rename GITEA_TOKEN to REGISTRY_TOKEN to avoid reserved name conflict
Some checks failed
Build and Push Docker Image to Gitea / build-and-push (push) Failing after 5m45s
2025-11-15 18:02:48 +01:00