- 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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
.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>
- 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>
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>
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>
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>
- 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>