138 Commits

Author SHA1 Message Date
TehRiehlDeal d05a6f1733 chore(release): 1.0.1
backend-ci / sast (push) Successful in 7s
backend-ci / secrets-scan (push) Successful in 4s
backend-ci / fs-scan (push) Successful in 14s
backend-ci / typecheck (push) Successful in 23s
backend-ci / test (push) Successful in 26s
backend-ci / push (push) Successful in 1m40s
backend-ci / lint (push) Successful in 27s
backend-ci / build (push) Successful in 1m57s
Bumps backend for the prisma-client TS-extension rewrite fix that
unblocks the production image bootloop. Versioning is kept in
lockstep with frontend.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:57:02 -07:00
TehRiehlDeal 2c1299bd51 fix(build): make prisma-client output runnable after nest build
Production image bootlooped with:
  Cannot find module './internal/class.ts'
  at /app/dist/generated/prisma/client.js:40:29

The Prisma 7 `prisma-client` generator (provider="prisma-client" in
schema.prisma) emits TypeScript source whose internal imports use
explicit `.ts` extensions (import x from "./internal/class.ts").
With module=nodenext, tsc preserves those extensions in the emitted
JS unless rewriteRelativeImportExtensions is on, so the compiled
client did `require("./internal/class.ts")` at runtime → ENOENT.

Set rewriteRelativeImportExtensions: true in tsconfig.json (added in
TS 5.7, we're on 5.7.3). tsc now rewrites .ts → .js in the emitted
require calls, matching the .js files actually present.

Also add a .dockerignore. The local smoke test was passing because
the COPY . . step was overlaying a pre-existing generated/prisma/
(left over from a previous prisma-client-js install with .js output)
on top of the fresh .ts output from `npm ci`'s postinstall. CI's
clean checkout had no override, so the bug was visible there first.
Excluding generated/, node_modules/, and dist/ from the build
context forces every build (local and CI) to use the fresh
regenerated output — same code path everywhere.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:53:52 -07:00
TehRiehlDeal 05651e4aca fix(ci): read HARBOR_HOST from vars, not secrets
backend-ci / typecheck (push) Successful in 21s
backend-ci / test (push) Successful in 23s
backend-ci / lint (push) Successful in 25s
backend-ci / build (push) Successful in 1m18s
backend-ci / push (push) Successful in 1m37s
backend-ci / secrets-scan (push) Successful in 5s
backend-ci / sast (push) Successful in 9s
backend-ci / fs-scan (push) Successful in 12s
HARBOR_HOST is configured as a Gitea Actions *variable*, not a
secret. Gitea (like GitHub) keeps the two stores separate — secrets.X
resolves to empty if X is a variable. Every prior CI failure on the
push job (docker/login-action exit 1, curl exit 6, docker login
falling back to registry-1.docker.io, the recent empty-check) was
the same root cause: secrets.HARBOR_HOST was always empty.

Switch the env binding to vars.HARBOR_HOST and drop the protocol-
strip defensive code that was added based on a wrong premise — the
value (harbor.tehriehldeal.com) is already a clean bare hostname.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:09:41 -07:00
TehRiehlDeal b86a0915ef fix(ci): clean HARBOR_HOST once and propagate via GITHUB_ENV
backend-ci / secrets-scan (push) Successful in 6s
backend-ci / fs-scan (push) Successful in 14s
backend-ci / sast (push) Successful in 16s
backend-ci / typecheck (push) Successful in 20s
backend-ci / test (push) Successful in 23s
backend-ci / lint (push) Successful in 24s
backend-ci / build (push) Successful in 1m22s
backend-ci / push (push) Failing after 8s
Previous run made it past the pre-check (which cleaned the host
locally) but failed at docker login with "Get registry-1.docker.io"
— docker fell back to Docker Hub because HARBOR_HOST still had the
protocol prefix the pre-check stripped. Subsequent steps (login,
push, cosign) read the raw secret directly.

Move the cleanup into the Compute step and write the normalized
value to \$GITHUB_ENV. That overrides the job-level env: HARBOR_HOST
for every step that runs after Compute, so login/push/cosign all
see the same clean hostname.

Also fail fast with a clear message if HARBOR_HOST is empty, so a
missing secret never silently lands us at Docker Hub again.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:55:46 -07:00
TehRiehlDeal 56022ac4c6 fix(ci): better diagnostics for Harbor pre-check
backend-ci / secrets-scan (push) Successful in 5s
backend-ci / sast (push) Successful in 8s
backend-ci / fs-scan (push) Successful in 13s
backend-ci / typecheck (push) Successful in 21s
backend-ci / lint (push) Successful in 24s
backend-ci / test (push) Successful in 23s
backend-ci / build (push) Successful in 1m19s
backend-ci / push (push) Failing after 9s
The Harbor pre-check died with bare exit code 6 (curl: couldn't
resolve host) and no diagnostic. Make it actually useful:

- Echo the URL being checked so a malformed HARBOR_HOST is obvious.
- Strip https://, http://, and trailing slash from HARBOR_HOST
  defensively — covers the common case of the secret being pasted as
  a full URL.
- Capture curl's exit status with || echo "000" and use a case
  statement to handle each outcome: 200 fails (exists), 404 proceeds
  (clean), 000 fails with a "check HARBOR_HOST" message, 401/403
  fails with a "check creds / robot perms" message, other statuses
  warn but proceed.
- Drop `set -e`; the script handles errors explicitly now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:46:03 -07:00
TehRiehlDeal 8b6e7d688a Merge branch 'main' of ssh://git.tehriehldeal.com:2222/TehRiehlDeal/movieloop-backend
backend-ci / secrets-scan (push) Successful in 5s
backend-ci / sast (push) Successful in 8s
backend-ci / fs-scan (push) Successful in 12s
backend-ci / test (push) Successful in 22s
backend-ci / lint (push) Successful in 23s
backend-ci / typecheck (push) Successful in 26s
backend-ci / build (push) Successful in 1m19s
backend-ci / push (push) Failing after 8s
2026-05-13 12:37:56 -07:00
TehRiehlDeal aa535612c2 Merge branch 'feature/movie-year-display' 2026-05-13 12:36:15 -07:00
TehRiehlDeal 20e60cf7e2 fix(ci): replace flaky docker/login-action, add cosign and tag back
backend-ci / secrets-scan (push) Successful in 4s
backend-ci / fs-scan (push) Successful in 11s
backend-ci / sast (push) Successful in 13s
backend-ci / typecheck (push) Successful in 19s
backend-ci / test (push) Successful in 22s
backend-ci / push (push) Has been skipped
backend-ci / lint (push) Successful in 21s
backend-ci / build (push) Successful in 1m22s
backend-ci / secrets-scan (pull_request) Successful in 5s
backend-ci / sast (pull_request) Successful in 8s
backend-ci / fs-scan (pull_request) Successful in 12s
backend-ci / typecheck (pull_request) Successful in 19s
backend-ci / test (pull_request) Successful in 22s
backend-ci / lint (pull_request) Successful in 23s
backend-ci / build (pull_request) Successful in 1m21s
backend-ci / push (pull_request) Has been skipped
The push job's docker/login-action@v3 was failing with a fast 1s exit
on the Gitea runner — the same nested-checkout/wrapper flakiness that
already burned us on gitleaks-action, trivy-action, and semgrep-action.
Replace it with a plain shell `docker login --password-stdin`.

While here, restructure the push job to match the pattern from the
companion project so subsequent steps work the same way across repos:

- Read VERSION from package.json (jq), SHA_SHORT from git, and use
  those as the published tags (:VERSION, :SHA_SHORT, :latest).
- Pre-check Harbor's API for an existing artifact at :VERSION and
  fail early with a clear "bump package.json" message, instead of
  silently overwriting a published version.
- Sign each pushed image with cosign (private key in env://COSIGN_KEY).
  Cosign resolves the SHA tag to a digest, so one signature covers
  all tags pointing at that digest.
- After a successful image push, create and push a `v${VERSION}` git
  tag back to origin using the auto-injected GITEA token. A failed
  tag push is downgraded to a warning so it can't undo a successful
  image push.
- Drop `tags: ["v*"]` from the workflow trigger — CI now creates the
  tag itself, so re-triggering on tag push would just loop.
- Drop the docker/metadata-action and the floating semver tags
  (:1.2, :1); the new scheme is :VERSION, :SHA_SHORT, :latest only.

Replaces the previous docker/build-push-action push with an explicit
buildx build + docker tag + docker push chain so cosign has a named
local reference (movieloop-backend:${SHA_SHORT}) to sign against.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:14:46 -07:00
TehRiehlDeal c168bcd9ac Add Keep-Me-Signed-In, movie release dates, and lint cleanup (#2)
backend-ci / secrets-scan (push) Successful in 4s
backend-ci / sast (push) Successful in 8s
backend-ci / fs-scan (push) Successful in 11s
backend-ci / typecheck (push) Successful in 22s
backend-ci / lint (push) Successful in 26s
backend-ci / test (push) Successful in 25s
backend-ci / build (push) Successful in 1m21s
backend-ci / push (push) Failing after 1m6s
Reviewed-on: #2
2026-05-13 11:58:55 -07:00
TehRiehlDeal 2a47168e26 fix(ci): pin setup-node cache-dependency-path on all jobs
backend-ci / secrets-scan (push) Successful in 5s
backend-ci / sast (push) Successful in 7s
backend-ci / fs-scan (push) Successful in 13s
backend-ci / typecheck (push) Successful in 19s
backend-ci / test (push) Successful in 22s
backend-ci / lint (push) Successful in 23s
backend-ci / build (push) Successful in 1m20s
backend-ci / push (push) Has been skipped
backend-ci / secrets-scan (pull_request) Successful in 5s
backend-ci / sast (pull_request) Successful in 7s
backend-ci / fs-scan (pull_request) Successful in 13s
backend-ci / typecheck (pull_request) Successful in 20s
backend-ci / test (pull_request) Successful in 22s
backend-ci / lint (pull_request) Successful in 25s
backend-ci / build (pull_request) Successful in 1m21s
backend-ci / push (pull_request) Has been skipped
The lint job set cache-dependency-path: package-lock.json explicitly;
typecheck and test left it to setup-node's auto-discovery, which can
fail on the Gitea runner (1s exit from the setup step). Make the
path explicit on every actions/setup-node@v4 invocation so cache key
resolution is deterministic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:48:20 -07:00
TehRiehlDeal 2fd628e663 fix(docker): strip global npm from runtime to drop inherited CVE
backend-ci / secrets-scan (push) Successful in 4s
backend-ci / sast (push) Successful in 7s
backend-ci / fs-scan (push) Successful in 12s
backend-ci / typecheck (push) Successful in 22s
backend-ci / test (push) Successful in 23s
backend-ci / lint (push) Successful in 27s
backend-ci / build (push) Successful in 1m22s
backend-ci / push (push) Has been skipped
Trivy's image scan flagged picomatch CVE-2026-33671 (ReDoS via crafted
extglob patterns) in the npm CLI bundled inside node:22-alpine
(/usr/local/lib/node_modules/npm/node_modules/picomatch). Our app's
own picomatch is clean — only npm's vendored copy is vulnerable, and
upstream npm hasn't shipped a fixed bundle yet.

The production container only needs `node` and the prisma CLI binary
at runtime. Switch entrypoint.sh from `npx prisma migrate deploy` to
calling ./node_modules/.bin/prisma directly, then delete the bundled
npm/yarn/corepack trees in the production stage. This removes the
vulnerable file rather than waiting on the upstream base image.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:35:45 -07:00
TehRiehlDeal c606fa8f27 fix(ci): drop flaky GHA cache and merge image-scan into build
backend-ci / secrets-scan (push) Successful in 8s
backend-ci / fs-scan (push) Successful in 13s
backend-ci / sast (push) Successful in 13s
backend-ci / typecheck (push) Successful in 21s
backend-ci / test (push) Successful in 23s
backend-ci / lint (push) Successful in 25s
backend-ci / build (push) Failing after 1m19s
backend-ci / push (push) Has been skipped
The Gitea runner timed out reaching the GHA artifact cache backend
during cache-to export, failing the build job after a fully successful
build. Drop type=gha cache-from/cache-to entirely; with no usable
cache backend, image-scan was also wasting ~5 min rebuilding from
scratch — fold the trivy image scan into the build job so it scans
the image that's already loaded in the local daemon.

Also chown at COPY time in the production Dockerfile stage. The
trailing `chown -R node:node /app` was taking 255s on CI because it
recursed the full node_modules tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:27:54 -07:00
TehRiehlDeal f5f25879a3 fix(deps): npm audit fix to clear high-severity CVEs
backend-ci / lint (push) Successful in 22s
backend-ci / typecheck (push) Successful in 18s
backend-ci / test (push) Successful in 20s
backend-ci / secrets-scan (push) Successful in 4s
backend-ci / sast (push) Successful in 7s
backend-ci / fs-scan (push) Successful in 11s
backend-ci / build (push) Failing after 7m2s
backend-ci / image-scan (push) Has been skipped
backend-ci / push (push) Has been skipped
Trivy fs-scan flagged 12 HIGH-severity vulnerabilities in
package-lock.json (axios prototype pollution, lodash RCE, hono auth
bypass, path-to-regexp DoS, socket.io-parser DoS, and others). All
fixes are within existing semver ranges in package.json — only the
lockfile changed, no direct dependency bumps.

Verified locally:
- npm run build (nest build) — green
- eslint — 0 errors
- /tmp/trivy fs --severity HIGH,CRITICAL — 0 vulnerabilities
- scripts/local-build-test.sh — full stack boots and serves /health

Remaining moderate-severity findings (@hono/node-server via @prisma/dev
chain, brace-expansion) are gated behind a Prisma major-version bump
that's out of scope here. CI scans HIGH,CRITICAL only, so these don't
block the pipeline.
2026-05-08 18:13:37 -07:00
TehRiehlDeal a63663c808 fix(ci): bump Trivy to v0.70.0 (v0.58.1 was never released)
backend-ci / lint (push) Successful in 22s
backend-ci / typecheck (push) Successful in 20s
backend-ci / test (push) Successful in 22s
backend-ci / secrets-scan (push) Successful in 4s
backend-ci / sast (push) Successful in 7s
backend-ci / fs-scan (push) Failing after 11s
backend-ci / image-scan (push) Has been cancelled
backend-ci / push (push) Has been cancelled
backend-ci / build (push) Has been cancelled
The previous pin to v0.58.1 returned a 404 — that tag doesn't exist in
the trivy releases. Latest is v0.70.0; pinning to that. Verified the
asset naming convention (trivy_X.Y.Z_Linux-64bit.tar.gz) is unchanged.
2026-05-08 18:05:50 -07:00
TehRiehlDeal 0ae10599f4 fix(ci): allowlist README.md in gitleaks config
backend-ci / sast (push) Successful in 6s
backend-ci / fs-scan (push) Failing after 4s
backend-ci / lint (push) Successful in 23s
backend-ci / typecheck (push) Successful in 20s
backend-ci / test (push) Successful in 21s
backend-ci / secrets-scan (push) Successful in 4s
backend-ci / image-scan (push) Has been cancelled
backend-ci / push (push) Has been cancelled
backend-ci / build (push) Has been cancelled
The NestJS starter README includes a placeholder CircleCI badge token
(?token=abc123def456) on a reference-style image link. README files
commonly contain placeholder secrets and badge URLs, so allowlist
README.md by path. Same pattern as the existing .env.example allowlist.

Verified locally: gitleaks scan now reports no leaks.
2026-05-08 18:00:14 -07:00
TehRiehlDeal a610c633de fix(ci): replace flaky trivy-action with direct binary install
backend-ci / lint (push) Successful in 23s
backend-ci / typecheck (push) Successful in 20s
backend-ci / fs-scan (push) Failing after 4s
backend-ci / test (push) Successful in 22s
backend-ci / secrets-scan (push) Failing after 4s
backend-ci / sast (push) Successful in 6s
backend-ci / build (push) Has been cancelled
backend-ci / image-scan (push) Has been cancelled
backend-ci / push (push) Has been cancelled
Same pattern as the gitleaks fix: aquasecurity/trivy-action@master does
a nested actions/checkout to fetch its install script, which fails on
the Gitea runner. Switch fs-scan and image-scan to download the trivy
binary release directly and invoke it. Pinned to v0.58.1.
2026-05-08 17:57:06 -07:00
TehRiehlDeal 105f347cac fix(ci): generate prisma client on install and fix test job hostnames
backend-ci / typecheck (push) Successful in 20s
backend-ci / test (push) Successful in 21s
backend-ci / sast (push) Successful in 6s
backend-ci / fs-scan (push) Failing after 32s
backend-ci / lint (push) Successful in 26s
backend-ci / secrets-scan (push) Failing after 4s
backend-ci / build (push) Has been cancelled
backend-ci / image-scan (push) Has been cancelled
backend-ci / push (push) Has been cancelled
- package.json: add `postinstall: prisma generate` so npm ci (CI and
  Docker) auto-generates the Prisma client. Without this, lint and
  typecheck failed in CI with "Cannot find module
  '../../generated/prisma/client.js'" and a flood of "Property X does
  not exist on type 'PrismaService'" errors.
- Dockerfile: copy `prisma/` and `prisma.config.ts` before `npm ci` so
  the postinstall hook finds the schema during the Docker build.
  Removed the now-redundant explicit `RUN npx prisma generate`.
- ci.yml test job: switched DATABASE_URL host from `localhost` to
  `postgres` and REDIS_HOST from `localhost` to `redis`. In Gitea
  Actions, service containers are reachable by service name on the
  job's bridge network, not via localhost. Removed unused `ports:`
  mappings.
- ci.yml secrets-scan: replaced gitleaks/gitleaks-action@v2 with a
  direct binary install + invocation. The action's license-key check
  flakes on Gitea; running the binary is more reliable.

Verified locally: postinstall regenerates the client cleanly, and
scripts/local-build-test.sh still passes end-to-end.
2026-05-08 17:54:16 -07:00
TehRiehlDeal f740b1a97f ci: add Gitea Actions pipeline, Harbor push, and migrate-on-boot
backend-ci / lint (push) Failing after 24s
backend-ci / typecheck (push) Failing after 21s
backend-ci / test (push) Failing after 23s
backend-ci / build (push) Has been skipped
backend-ci / image-scan (push) Has been skipped
backend-ci / secrets-scan (push) Failing after 8s
backend-ci / sast (push) Successful in 12s
backend-ci / push (push) Has been cancelled
backend-ci / fs-scan (push) Has been cancelled
Pipeline (backend/.gitea/workflows/ci.yml):
- lint, typecheck, test (postgres+redis service containers, prisma
  migrate deploy, jest), gitleaks, semgrep, Trivy fs+image scans,
  buildx build with gha cache, Harbor push gated on `main` or v* tags
- Image tags via docker/metadata-action: :latest (main only),
  :sha-<full>, semver-derived :1.2.3 / :1.2 / :1 from v* tags
- Secrets: HARBOR_HOST, MOVIELOOP_USERNAME, MOVIELOOP_PASSWORD,
  PRISMA_TEST_KEY

Production image hardening (docker/Dockerfile, docker/entrypoint.sh):
- New entrypoint runs `npx prisma migrate deploy` then
  `exec node dist/src/main` so migrations apply on container start
  (single-replica deploys only)
- Switched CMD -> ENTRYPOINT, added USER node + chown for non-root
  runtime

Versioning (package.json, .versionrc.json):
- Bumped to 1.0.0 baseline
- Added commit-and-tag-version devDep + release/release:minor/major/dry
  scripts. Conventional Commits drive bumps; CHANGELOG hides chore/ci/etc.

Scan configs:
- .gitleaks.toml allows .env.example
- .semgrepignore excludes node_modules/, dist/, generated/prisma/,
  coverage/, test/, prisma/migrations/
- .trivyignore placeholder with format docs

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 17:44:12 -07:00
TehRiehlDeal f0def62eef Add Keep-Me-Signed-In, movie release dates, and lint cleanup
Features:
- "Keep me signed in" — login/register accept a rememberMe flag and the
  backend signs JWTs with JWT_LONG_EXPIRATION (30d) when set, otherwise
  JWT_EXPIRATION (1d). DTOs, controller, and AuthService updated.
- Movie release dates — DailyChallenge, GameSession, and VersusMatch get
  nullable movieAReleaseDate / movieBReleaseDate columns (forward-only
  migration). Daily-challenges, games, versus-match, and versus-async
  services now persist and return release_date from TMDB. Versus waiting
  lobby payloads strip the new fields alongside the titles to avoid
  leaking the puzzle to non-joined players.

Lint cleanup (132 → 0 errors):
- Shared utilities: src/common/utils/error.util.ts (getErrorMessage) and
  src/auth/types/jwt-payload.ts (JwtPayload).
- Replaced catch(error: any){error.message} with getErrorMessage(error)
  across services and gateways.
- jwtService.verify<JwtPayload>(token) in versus / game-night / chat /
  notifications gateways.
- Typed Prisma JSON columns where they're read (game-night, leaderboards,
  admin score blobs).
- Removed redundant async on sync handlers, wrapped setTimeout/setInterval
  Promise callbacks with void IIFEs to satisfy no-misused-promises.
- eslint.config.mjs: allow `_`-prefixed unused vars (industry standard).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 16:40:00 -07:00
TehRiehlDeal 8b2812ca10 Merge branch 'main' of ssh://git.tehriehldeal.com:2222/TehRiehlDeal/movieloop-backend 2026-05-05 17:16:52 -07:00
TehRiehlDeal 0dc9697652 Add MIT license
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 17:15:50 -07:00
TehRiehlDeal e40bbe6066 Remove leaderboard re-linking from recalculateScores admin function (#1)
The leaderboard update step could set gameMode to 'freeplay' for entries
lacking a dailyChallengeId, causing them to disappear from the leaderboard
which filters by gameMode 'daily'. Since game completion now properly tags
leaderboard entries at submission time, this step is no longer needed.

Reviewed-on: #1
Co-authored-by: Kevin Riehl <kevinriehl@gmail.com>
Co-committed-by: Kevin Riehl <kevinriehl@gmail.com>
2026-05-04 15:05:17 -07:00
TehRiehlDeal 5892b3732c Bugfix/undo fix (#3)
* Add undoLink method to GamesService

* Add POST :id/undo endpoint to GamesController

* Format achievements service line wrapping

* Format admin service line wrapping

* Format versus match service line wrapping
2026-03-17 21:36:14 -07:00
TehRiehlDeal 21a11f8322 Feature/achievement handling (#2)
* Return full achievement details from checkAndAward

* Include new achievements in game completion response

* Include new achievements in versus match-finished result

* Fix admin service for updated checkAndAward return type
2026-03-15 17:07:17 -07:00
TehRiehlDeal 891c319610 Chores/code refactor (#1)
* Extract getUtcDate() into shared date utility

* Extract pickRandomPair() into shared movie-pair utility

* Extract SHA256 hashing into shared hash utility

* Extract streak calculation into shared streak utility

* Use shared date and movie-pair utils in daily-challenges

* Add missing import in daily-challenges controller

* Use shared date and streak utils in leaderboards

* Use Difficulty enum in leaderboard query DTO

* Update leaderboards controller imports

* Use shared hash and movie-pair utils in versus service

* Add VersusMatchService for sync match operations

* Add VersusAsyncService for async match operations

* Register split versus services in module

* Use CreateFriendChallengeDto in versus controller

* Use Difficulty enum in create-match DTO

* Use ScoreBreakdownDto in submit-async-score DTO

* Add CreateFriendChallengeDto

* Use VersusAsyncService in async-expiration

* Use shared hash utility in game-night service

* Use shared streak utility in admin service

* Use validated DTOs in admin controller

* Add admin DTOs for challenge and promote endpoints

* Add shared Difficulty enum

* Add ScoreBreakdownDto with class-validator decorators

* Fix currentPassword MinLength from 1 to 8

* Add ValidateLinkDto for chain validation endpoint

* Add POST validate-link endpoint to games controller

* Add server-side chain link validation logic

* Import MoviesModule in games module for TMDB validation

* Add UserRelationshipModule to resolve chat-friends circular dep

* Replace forwardRef FriendsModule with UserRelationshipModule

* Use UserRelationshipService in chat service

* Remove unused FriendsService import from chat gateway

* Import UserRelationshipModule in friends module

* Delegate areFriends to UserRelationshipService, add error logging

* Register UserRelationshipModule in app module

* Exported ChainItem Interface

* Fixed first actor in new game validation
2026-03-15 00:25:04 -07:00
TehRiehlDeal fac88c2f27 Fix easy puzzle par: use hardcoded par 4 instead of analyzeDifficulty 2026-03-14 21:51:10 -07:00
TehRiehlDeal f078a37fb5 Generate easy puzzles via shared cast instead of brute-force retries 2026-03-14 21:21:10 -07:00
TehRiehlDeal 56b87e6bbe Fix difficulty sort order (easy/medium/hard), bump retry cap to 50 2026-03-14 20:38:54 -07:00
TehRiehlDeal 23aed50ed1 Add generate-all endpoint for 3 daily challenges 2026-03-14 19:56:07 -07:00
TehRiehlDeal 7cb0635f93 Add generateAllChallenges, pass par in score recalculation 2026-03-14 19:56:04 -07:00
TehRiehlDeal 133076ce5b Pass difficulty filter to leaderboard, update me/today response 2026-03-14 19:55:57 -07:00
TehRiehlDeal e0e84ca132 Add optional difficulty field to leaderboard query DTO 2026-03-14 19:55:53 -07:00
TehRiehlDeal bc0fce487f Add difficulty to leaderboard: compound keys, filtering, streak dedup 2026-03-14 19:55:49 -07:00
TehRiehlDeal eeba018485 Update today endpoint description for multi-challenge response 2026-03-14 19:55:45 -07:00
TehRiehlDeal 775666a046 Generate 3 daily challenges, return arrays, use compound keys 2026-03-14 19:55:39 -07:00
TehRiehlDeal 604520adbf Look up par from daily challenge and pass difficulty to leaderboard 2026-03-14 19:55:33 -07:00
TehRiehlDeal 8b06c413d2 Rework scoring: add par param, average-based obscurity bonus 2026-03-14 19:55:29 -07:00
TehRiehlDeal ff3da4f6df Add migration for three daily challenges schema 2026-03-14 19:55:23 -07:00
TehRiehlDeal 84849c4452 Add compound unique constraints for multi-difficulty daily challenges 2026-03-14 19:55:18 -07:00
TehRiehlDeal 4c1d03154e Add in-app notification for chat messages alongside push 2026-03-11 21:34:59 -07:00
TehRiehlDeal 1c8ec72ec5 Import UsersModule in ChatModule for sender lookup 2026-03-11 21:34:58 -07:00
TehRiehlDeal 64cb23c0f0 Publish chat message notifications to RabbitMQ 2026-03-11 21:34:57 -07:00
TehRiehlDeal 2190e33e84 Database migrations 2026-03-11 21:20:02 -07:00
TehRiehlDeal b039ec95fc Remove public key methods from users service 2026-03-11 21:15:54 -07:00
TehRiehlDeal 72eac778d4 Remove public key endpoints from users controller 2026-03-11 21:15:53 -07:00
TehRiehlDeal 7f089a88c2 Emit new-message to both sender and recipient sockets 2026-03-11 21:15:53 -07:00
TehRiehlDeal 55c48799ed Use plaintext content field in chat service 2026-03-11 21:15:50 -07:00
TehRiehlDeal ffe79b46ef Remove chatPublicKey from User, simplify ChatMessage to plaintext 2026-03-11 21:15:48 -07:00
TehRiehlDeal eaf52c6f15 Add migration to remove E2E encryption fields from schema 2026-03-11 21:15:46 -07:00
TehRiehlDeal 70385a4b3d Lint auto-format fixes 2026-03-11 20:46:13 -07:00