119 Commits

Author SHA1 Message Date
b200498a10 fix: correct CI badge URLs to use Gitea workflow badge format
All checks were successful
Build and Push Backend Image / build (push) Successful in 16s
Build and Push Frontend Image / build (push) Successful in 15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 12:57:47 +01:00
1369d5c228 fix: copy packages/types into backend Docker build
All checks were successful
Build and Push Backend Image / build (push) Successful in 46s
Build and Push Frontend Image / build (push) Successful in 16s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 12:51:52 +01:00
e200514347 refactor: move flyout to left side, restore logo, remove close button
Some checks failed
Build and Push Backend Image / build (push) Failing after 47s
Build and Push Frontend Image / build (push) Successful in 5m13s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 12:34:57 +01:00
d7057c3681 refactor: improve mobile flyout header
- Replace inline mobile dropdown with sliding flyout panel from right
- Hide burger menu on lg breakpoint, desktop auth buttons use hidden lg:flex
- Add backdrop overlay with opacity transition
- Remove logo from flyout panel header
- Fix backdrop div accessibility with role="presentation"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 11:44:23 +01:00
d820a8f6be chore: relative uploads dir 2026-03-05 11:05:30 +01:00
9bef2469d1 refactor: rename RecordedEvent fields to snake_case
deviceIndex → device_index
deviceName → device_name
actuatorIndex → actuator_index
actuatorType → actuator_type

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 11:04:36 +01:00
97269788ee feat: add shared @sexy.pivoine.art/types package and fix type safety across frontend/backend
- Create packages/types with shared TypeScript domain model interfaces (User, Video, Model, Article, Comment, Recording, etc.)
- Wire both frontend and backend packages to use @sexy.pivoine.art/types via workspace:*
- Update backend Pothos objectRef types to use shared interfaces instead of inline types
- Update frontend $lib/types.ts to re-export from shared package
- Fix all type errors introduced by more accurate nullable types (avatar/banner as string|null UUIDs, author nullable, events/device_info as object[])
- Add artist_name to comment user select in backend resolver
- Widen utility function signatures (getAssetUrl, getUserInitials, calcReadingTime) to accept null/undefined

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 11:01:11 +01:00
c6126c13e9 feat: add backend logger matching frontend text format
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 10:22:49 +01:00
fd4050a49f refactor: remove directus.ts shim, import directly from api
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 10:19:05 +01:00
efc7624ba3 style: apply prettier formatting to all files
All checks were successful
Build and Push Backend Image / build (push) Successful in 46s
Build and Push Frontend Image / build (push) Successful in 5m12s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 22:27:54 +01:00
18116072c9 feat: add formidable ESLint + Prettier linting setup
Some checks failed
Build and Push Backend Image / build (push) Successful in 47s
Build and Push Frontend Image / build (push) Has been cancelled
- Root-level eslint.config.js (flat config): typescript-eslint,
  eslint-plugin-svelte, eslint-config-prettier, @eslint/js
- Root-level prettier.config.js with prettier-plugin-svelte
- svelte-check added to frontend for Svelte/TS type checking
- lint, lint:fix, format, format:check, check scripts in root
  and both packages
- All 60 lint errors fixed across backend and frontend:
  - Consistent type imports
  - Removed unused imports/variables
  - Added keys to all {#each} blocks for Svelte performance
  - Replaced mutable Set/Map with SvelteSet/SvelteMap
  - Fixed useless assignments and empty catch blocks
- 64 remaining warnings are intentional any usages in the
  Pothos/Drizzle GraphQL resolver layer

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 22:24:55 +01:00
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