Imported from NaferJ/luisardito-shop-backend (
AGENTS.md). Install upstream withnpx skills add NaferJ/luisardito-shop-backend. Copyright stays with the author.
Luisardito Backend
Node.js 20 REST API for the Luisardito gamified points and rewards system. Express 5.1, Sequelize 6.37 ORM over MySQL 8.0, Redis 7 cache (ioredis), TypeScript (CommonJS, tsx runtime), Jest tests. Integrates Kick (OAuth 2.0, chat bot, webhooks) and Discord (discord.js 14), with Cloudinary image storage, node-cron scheduled tasks, pdfkit PDF generation, and bcryptjs password hashing. Containerized with Docker Compose.
See .github/copilot-instructions.md for full code conventions and rules.
Commands
npm run dev— dev server with hot reload (the user runs this; AI should not)npm run build— TypeScript compile todist/(tsc -p tsconfig.build.json)npm run start— run from source withtsx app.tsnpm run start:prod— serve the compiled build (node dist/app.js)npm run lint— ESLintnpm run lint:fix— ESLint with--fixnpm run format/npm run format:check— Prettiernpm run typecheck—tsc --noEmitnpm test/npm run test:watch— Jestnpm run migrate/migrate:status/migrate:undo/migrate:undo:all— Sequelize migrationsnpm run seed/seed:undo— Sequelize seedersnpm run setup-db—migratethenseednpm run reset-db— undo all migrations, thensetup-dbnpm run dev:setup— start thedbcontainer, then migrate and seednpm run dev:reset— tear down containers/volumes, recreatedb, then migrate and seednpm run docker:dev/docker:dev:down/docker:dev:logs— full Docker Compose dev stacknpm ci— install dependencies exactly as locked (use this locally instead ofnpm install)
Windows / cross-platform lock file note
CI runs on ubuntu-latest. Some dependencies have platform-specific optional dependencies. npm install on Windows silently drops the Linux-only optional dependency entries from package-lock.json, which then breaks npm ci in CI with Missing: ... from lock file errors.
Rules to avoid this:
- Never run plain
npm installon Windows after the lock file is correct — it rewrites the lock and strips Linux entries. Usenpm cifor routine local installs instead; it only reads the lock, never rewrites it. - When adding/updating a dependency, regenerate the lock file in a Linux container so both platforms' optional deps are recorded:
Then rundocker run --rm -v "${PWD}:/app" -w /app node:22 sh -c "npm install --no-audit --no-fund"npm cilocally (Windows) to install from the corrected lock without touching it again. - Verify before pushing:
docker run --rm -v "${PWD}:/app" -w /app node:22 sh -c "rm -rf node_modules && npm ci"should succeed with no errors — this exactly mirrors CI.
Environment
.env.example is the single source of truth for env var documentation. Real secrets live in .env, .env.development, .env.development.local (all gitignored). Config is centralized in config.ts — read env vars through it, not process.env ad-hoc. Key vars:
PORT— server port (default3000)DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME/DB_SSL— MySQL connectionJWT_SECRET— JWT signing secretKICK_CLIENT_ID/KICK_CLIENT_SECRET/KICK_REDIRECT_URI— Kick OAuthKICK_BROADCASTER_ID— main streamer Kick IDKICK_OAUTH_*/KICK_API_BASE_URL— Kick API endpoints- Cloudinary, Discord, and Redis vars are documented in
.env.example/.env.cloudinary-example
On the production VPS, the CD workflow writes the production .env from GitHub secrets (see .github/workflows/prod-cd.yml).
Frontend dependency
This backend is consumed by the luisardito-shop-frontend API (read-only). API response-shape changes are consumer-visible: if you add, remove, or rename a response field, document it in the PR and flag any frontend impact. If a data-shape mismatch is found on the frontend, it is a backend bug and must be fixed here, not worked around silently in the frontend.
Docker Compose
The base docker-compose.yml defines three services:
- db — MySQL 8.0 with a persistent volume and a health check.
- redis — Redis 7-alpine with a persistent volume and a health check.
- api — The Node.js application built from the Dockerfile, depending on
dbandredisbeing healthy.
Development overrides live in docker-compose.override.yml (hot reload, published ports, development env) and production overrides in docker-compose.prod.yml (production env file, restart policy, host port mapping). Compose applies the override file automatically in development; production deploys pass both files explicitly.
CI/CD
- CI (
ci.yml) — Triggers on pushes todevand PRs todevormain. Runsnpm ci,npm test, and adocker build. It does not run ESLint or Prettier — runnpm run format:checkandnpm run lintlocally before pushing. - Production CD (
prod-cd.yml) — Triggers on pushes tomain. Writes the production.envon the VPS from GitHub secrets and deploys the stack withdocker compose.
Project Board
The backlog is tracked on the GitHub Projects board: https://github.com/users/NaferJ/projects/13
Fields
- Status — Todo / In Progress / In Review / Done
- Priority — High / Medium / Low
Sprint and category are tracked via labels (feature, tooling, etc.) instead of board fields.
Workflow
Cards move through the following statuses:
- Todo — Issue created and added to the board, not yet started.
- In Progress — Actively being coded (branch checked out, work underway).
- In Review — PR is open and awaiting review/merge.
- Done — PR merged. PRs that include
Closes #NNin their description auto-close the referenced issue and move the board card to Done.
gh CLI commands
Common operations for working with the board:
- View the board:
gh project item-list 13 --owner NaferJ - Create an issue:
gh issue create --repo NaferJ/luisardito-shop-backend --title "..." --body "..." - Add an issue to the board:
gh project item-add 13 --owner NaferJ --url <issue-url>
Labels
Apply labels to every issue to categorize work. The repo has 13 labels total:
Custom labels (apply to every issue):
feature— New feature or API endpointops— Operations, infra, CI/CD, deploymentcontent— Content, copy, or asset task (no code changes)tooling— Developer tooling, workflow, config, monitoring
GitHub default labels (use when applicable):
bug— Something isn't workingdocumentation— Improvements or additions to documentationenhancement— New feature or request (usefeatureinstead for API work)good first issue— Good for newcomershelp wanted— Extra attention is neededquestion— Further information is requestedduplicate— This issue or pull request already existsinvalid— This doesn't seem rightwontfix— This will not be worked on
Milestones
Milestones group issues and PRs toward a release version (e.g. "v1.1.0"). They are NOT the same as sprints:
- Sprint = time box ("what am I working on this cycle")
- Milestone = release target ("what version does this ship in")
Only create a milestone when shipping a version with consumer-visible changes. Tooling/ops/internal sprints get NO milestone. A milestone is created when you know which issues will ship in the next version bump; when all issues in the milestone are closed, the version is ready to release.
Card movement rule
When working on an issue, the AI must:
- Move the card to In Progress when starting work (and tell the user)
- Move the card to In Review when a PR is opened (and tell the user)
- The card moves to Done automatically when the PR with
Closes #NNmerges
Always tell the user when moving a card between statuses.
Assignment rule
Every issue must be assigned to NaferJ. When creating an issue, always pass --add-assignee NaferJ. The board is a solo project — there are no unassigned cards.
Status updates
Status updates are high-level project health reports (not task-level updates). Add one via the project board UI (side panel -> Add update).
When to add a status update:
- A sprint starts ("Sprint 1 started, target Sep 14")
- A sprint ends ("Sprint 1 complete, 5/6 items done")
- The project is at risk ("Blocked on Kick API change, sprint delayed")
- A major milestone ships ("v1.1.0 released with leaderboard subscription tiers + webhook hardening")
Cadence for solo work: one update at sprint start + one at sprint end. Not every session.
Each update has: Status (On track / At risk / Off track), start date, target date, and a brief Markdown message.
Issue templates
Issue templates exist in .github/ISSUE_TEMPLATE/:
feature.md— feature requests (endpoints, services, models, migrations)content.md— content, copy, or asset taskstooling.md— tooling and infrastructure tasks
Use these templates when creating new issues to keep descriptions consistent.