Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a822ba6
feat: update dev tooling (ESLint 9, Jest 29, Stylelint 16, TypeScript)
dpuscher Feb 19, 2026
d12bccb
feat: remove abandonware and update safe packages
dpuscher Feb 19, 2026
7d01985
feat: update Redis v2→v5 and connect-redis v4→v9
dpuscher Feb 19, 2026
1eb1c35
feat: update Mongoose v5→v8
dpuscher Feb 19, 2026
283e983
feat: update Express v4→v5, remove body-parser, update Helmet v3→v8
dpuscher Feb 19, 2026
4ba82ad
feat: update React ecosystem 16→18
dpuscher Feb 19, 2026
60ff13a
feat: update Next.js 9→14
dpuscher Feb 19, 2026
8e11de3
feat: migrate codebase to TypeScript
dpuscher Feb 19, 2026
4537bb4
feat: migrate Express routes to Next.js API routes
dpuscher Feb 19, 2026
bb213f2
feat: remove Express server, use Next.js exclusively
dpuscher Feb 19, 2026
5b6bcb4
fix: resolve React 18 warnings from docker logs
dpuscher Feb 19, 2026
fe93b52
fix: prevent OverwriteModelError in Next.js dev mode
dpuscher Feb 19, 2026
dc5f2c2
fix: handle unauthenticated session state correctly
dpuscher Feb 19, 2026
bbd65f9
fix: convert detected/scrobbled to dynamic routes
dpuscher Feb 19, 2026
fc02621
fix: pass full app props to useWrappedStore in _app.tsx
dpuscher Feb 19, 2026
5cf480d
refactor: replace propTypes/defaultProps with TypeScript interfaces
dpuscher Feb 19, 2026
2514503
refactor: migrate profile page from getInitialProps to getServerSideP…
dpuscher Feb 19, 2026
2dbee93
fix: update ProfileHistoryItem link href to use dynamic route path
dpuscher Feb 19, 2026
de51d92
fix: guard against null state.data in autoScrobbleReducer
dpuscher Feb 19, 2026
b4b3ddf
fix: check response.ok before parsing json in history and autoscrobbl…
dpuscher Feb 19, 2026
3a93a0f
fix: serialize error message correctly in history api error response
dpuscher Feb 19, 2026
47129d2
fix: rename ProfileHistorys class to ProfileHistory
dpuscher Feb 19, 2026
ad3244f
fix: update QueryRelease link href to use dynamic route path
dpuscher Feb 19, 2026
e2564bb
fix: surface Discogs errors and guard release fetch response
dpuscher Feb 19, 2026
6db9410
fix: handle duplicate key race condition in Release.firstOrCreate
dpuscher Feb 19, 2026
d77b593
fix: guard against undefined release.data in shouldFetchRelease
dpuscher Feb 19, 2026
8ea0c64
refactor: convert app/modules to TypeScript
dpuscher Feb 23, 2026
f66854d
Merge pull request #10 from dpuscher/modernize-dependencies
dpuscher Feb 23, 2026
3d8ac58
fix: use ConnectedProps to resolve TypeScript error in QueryRelease
dpuscher Feb 23, 2026
192112d
chore(tooling): add eslint prettier and pre-commit checks
dpuscher Feb 23, 2026
91d05fe
chore: run prettier
dpuscher Feb 23, 2026
f412aac
fix(lint): resolve all ESLint errors
dpuscher Feb 24, 2026
05efd05
Merge pull request #13 from dpuscher/add-eslint-prettier
dpuscher Feb 24, 2026
d39f003
feat: add PR CI and modernize deployment workflows
dpuscher Feb 23, 2026
a552658
fix: configure stylelint to lint styled-components files
dpuscher Feb 24, 2026
f3a9f54
Merge pull request #12 from dpuscher/add-review-apps
dpuscher Feb 24, 2026
6c2cf89
fix: replace raw API calls with gh pr commands in staging auto-PR wor…
dpuscher Feb 24, 2026
12311df
chore: update lavamoat allowscripts list
dpuscher Feb 24, 2026
019510e
chore(test): migrate jest to vitest with happy-dom
dpuscher Feb 23, 2026
db4e1f0
fix(ci): remove Jest-only flags from Vitest PR check
dpuscher Feb 24, 2026
d9b3cfb
Merge pull request #14 from dpuscher/migrate-to-vitest
dpuscher Feb 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"presets": [
"next/babel"
],
"presets": ["next/babel"],
"plugins": [
["styled-components", {
"displayName": false,
"ssr": true
}],
"transform-class-properties"
[
"styled-components",
{
"displayName": false,
"ssr": true
}
]
]
}
5 changes: 0 additions & 5 deletions .eslintignore

This file was deleted.

27 changes: 0 additions & 27 deletions .eslintrc.js

This file was deleted.

16 changes: 8 additions & 8 deletions .github/workflows/build-production.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3

- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: .
platforms: ${{ matrix.platform }}
Expand All @@ -49,7 +49,7 @@ jobs:
touch "/tmp/digests/${digest#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: digest-production-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
path: /tmp/digests/*
Expand All @@ -65,17 +65,17 @@ jobs:

steps:
- name: Download digests
uses: actions/download-artifact@v4
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
path: /tmp/digests
pattern: digest-production-*
merge-multiple: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3

- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/build-staging.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3

- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: .
platforms: ${{ matrix.platform }}
Expand All @@ -49,7 +49,7 @@ jobs:
touch "/tmp/digests/${digest#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: digest-staging-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}
path: /tmp/digests/*
Expand All @@ -65,17 +65,17 @@ jobs:

steps:
- name: Download digests
uses: actions/download-artifact@v4
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
with:
path: /tmp/digests
pattern: digest-staging-*
merge-multiple: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3

- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand Down
53 changes: 53 additions & 0 deletions .github/workflows/pr-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: PR CI

on:
pull_request:
types:
- opened
- synchronize
- reopened
- ready_for_review

permissions:
contents: read

concurrency:
group: pr-ci-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
validate:
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-latest
timeout-minutes: 20
env:
NEXT_TELEMETRY_DISABLED: 1

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Enable Corepack
run: corepack enable

- name: Set up Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
with:
node-version-file: .nvmrc
cache: yarn
cache-dependency-path: yarn.lock

- name: Install dependencies
run: yarn install --immutable

- name: Lint JS/TS
run: yarn lint

- name: Lint CSS
run: yarn lint:css

- name: Run tests
run: yarn test

- name: Build
run: yarn build
98 changes: 85 additions & 13 deletions .github/workflows/staging-auto-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,90 @@ on:

jobs:
pull-request:
name: Open PR to main
name: Open or Update PR to Production
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
concurrency:
group: staging-auto-pr
cancel-in-progress: true
steps:
- uses: actions/checkout@v2
name: checkout

- uses: repo-sync/pull-request@v2
name: pull-request
with:
destination_branch: "production"
pr_title: "Staging to Production"
pr_body: "This PR was auto-generated via a workflow action."
pr_reviewer: ${{ github.actor }}
source_branch: "staging"
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Create or update staging -> production PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
OWNER: ${{ github.repository_owner }}
SOURCE_BRANCH: staging
DESTINATION_BRANCH: production
PR_TITLE: Staging to Production
REVIEWER: ${{ github.actor }}
run: |
set -euo pipefail

compare_json="$(gh api "repos/${REPO}/compare/${DESTINATION_BRANCH}...${SOURCE_BRANCH}")"
compare_url="$(echo "${compare_json}" | jq -r '.html_url')"
ahead_by="$(echo "${compare_json}" | jq -r '.ahead_by')"

if [ "${ahead_by}" -eq 0 ]; then
echo "staging is not ahead of production (ahead_by=0). Nothing to do."
exit 0
fi

prs_tsv="$(mktemp)"
while IFS= read -r sha; do
[ -n "${sha}" ] || continue
gh api "repos/${REPO}/commits/${sha}/pulls" \
--jq '.[] | select(.merged_at != null) | "\(.number)\t\(.title)\t\(.html_url)"' \
>> "${prs_tsv}" || true
done < <(echo "${compare_json}" | jq -r '.commits[].sha')

if [ -s "${prs_tsv}" ]; then
prs_markdown="$(sort -t $'\t' -k1,1n -u "${prs_tsv}" | awk -F '\t' '{printf "- #%s %s (%s)\n", $1, $2, $3}')"
else
prs_markdown="- No linked pull requests found (direct commits or metadata unavailable)."
fi

pr_body_file="$(mktemp)"
{
echo "This PR was auto-generated via a workflow action."
echo
echo "## Included Pull Requests"
echo "${prs_markdown}"
echo
echo "## Diff"
echo "- Source: \`${SOURCE_BRANCH}\`"
echo "- Target: \`${DESTINATION_BRANCH}\`"
echo "- Commits ahead: ${ahead_by}"
echo "- Compare: ${compare_url}"
} > "${pr_body_file}"

pr_number="$(gh pr list \
--repo "${REPO}" \
--base "${DESTINATION_BRANCH}" \
--head "${SOURCE_BRANCH}" \
--state open \
--json number \
--jq '.[0].number // empty')"

if [ -z "${pr_number}" ]; then
echo "No open PR found for ${SOURCE_BRANCH} -> ${DESTINATION_BRANCH}. Creating one."
pr_url="$(gh pr create \
--repo "${REPO}" \
--base "${DESTINATION_BRANCH}" \
--head "${SOURCE_BRANCH}" \
--title "${PR_TITLE}" \
--body-file "${pr_body_file}")"
pr_number="${pr_url##*/}"
else
echo "Updating existing PR #${pr_number}."
gh pr edit "${pr_number}" \
--repo "${REPO}" \
--title "${PR_TITLE}" \
--body-file "${pr_body_file}"
fi

gh pr edit "${pr_number}" \
--repo "${REPO}" \
--add-reviewer "${REVIEWER}" || \
echo "Reviewer assignment skipped for ${REVIEWER}."
2 changes: 2 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env sh
yarn lint-staged
11 changes: 11 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.next
node_modules
coverage
dist
build
out
test-results
public/static
.yarn
.pnp.*
yarn.lock
7 changes: 7 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"arrowParens": "avoid",
"printWidth": 120
}
10 changes: 0 additions & 10 deletions .stylelintrc

This file was deleted.

5 changes: 1 addition & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_OPTIONS=--openssl-legacy-provider
RUN yarn build

FROM base AS runner
Expand All @@ -28,8 +27,6 @@ RUN addgroup --system --gid 1001 nodejs && \
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/server.js ./server.js
COPY --from=builder /app/config ./config
COPY --from=builder /app/app ./app
COPY --from=builder /app/lib ./lib
COPY package.json ./
Expand All @@ -38,4 +35,4 @@ USER nextjs

EXPOSE 3000

CMD ["node", "server.js"]
CMD ["node_modules/.bin/next", "start"]
Loading
Loading