diff --git a/readme.md b/readme.md index 5eed7d1..84ae1ec 100644 --- a/readme.md +++ b/readme.md @@ -1 +1,53 @@ -## Start Api: node src/index.js +# YuGiOh Collection Manager — API + +Node.js/Express API for the YuGiOh collection manager. Handles card data, set browsing, image serving, and DB imports from YGOPRODeck. + +## Tech Stack + +- **Node.js** + **Express 5** +- **MySQL2** (connection pool) +- **Axios** — YGOPRODeck API requests + card image fetching + +## Endpoints + +| Method | Path | Description | +|---|---|---| +| GET | `/health` | Health check | +| GET | `/exportCards` | All cards with printings and owned counts | +| GET | `/cardImage/:cardId` | Card image (fetches + caches blob on first request) | +| GET | `/sets` | All sets with owned card counts | +| GET | `/sets/:setId/cards` | Cards in a specific set | +| PUT | `/collection/amount` | Update owned count for a printing | +| POST | `/import/full-import` | Full DB import from YGOPRODeck | +| POST | `/import/sets` | Import sets only | +| POST | `/import/cards` | Import cards only | +| GET | `/db-version` | Current local DB version | + +## Development + +```bash +npm install +cp .env.example .env # fill in DB credentials +node src/index.js +``` + +## Deployment + +Built as a Docker image. CI/CD via Woodpecker on push to `main`. + +```bash +docker build -t yugioh-api . +docker run -d --name yugioh-api --network yugioh --env-file .env yugioh-api +``` + +## Environment + +| Variable | Description | +|---|---| +| `DB_HOST` | MySQL host | +| `DB_PORT` | MySQL port (default 3306) | +| `DB_USER` | MySQL user | +| `DB_PASSWORD` | MySQL password | +| `DB_NAME` | Database name | +| `YGOPRO_API_BASE` | YGOPRODeck API base URL | +| `PORT` | Server port (default 3000) | diff --git a/src/controllers/setsController.js b/src/controllers/setsController.js new file mode 100644 index 0000000..19bcd77 --- /dev/null +++ b/src/controllers/setsController.js @@ -0,0 +1,44 @@ +const db = require('../config/db'); + +async function getSets(req, res) { + try { + const [rows] = await db.execute(` + SELECT + s.id, s.set_name, s.set_code, s.num_of_cards, s.tcg_date, + COUNT(DISTINCT csr.card_id) AS total_in_db, + COUNT(DISTINCT CASE WHEN csr.amount_owned > 0 THEN csr.card_id END) AS owned_count + FROM sets s + LEFT JOIN card_sets_rarity csr ON s.id = csr.set_id + GROUP BY s.id + ORDER BY s.tcg_date DESC, s.set_name ASC + `); + res.json(rows); + } catch (err) { + console.error('Error fetching sets:', err); + res.status(500).json({ error: 'Failed to fetch sets' }); + } +} + +async function getSetCards(req, res) { + const { setId } = req.params; + try { + const [rows] = await db.execute(` + SELECT + c.id, c.name, c.card_type AS type, c.frame_type, + csr.card_set_code AS set_code, + r.id AS rarity_id, r.rarity_name, r.rarity_code, + csr.amount_owned + FROM card_sets_rarity csr + JOIN cards c ON csr.card_id = c.id + JOIN rarities r ON csr.rarity_id = r.id + WHERE csr.set_id = ? + ORDER BY c.name ASC + `, [setId]); + res.json(rows); + } catch (err) { + console.error('Error fetching set cards:', err); + res.status(500).json({ error: 'Failed to fetch set cards' }); + } +} + +module.exports = { getSets, getSetCards }; diff --git a/src/index.js b/src/index.js index 378291a..ab4759f 100644 --- a/src/index.js +++ b/src/index.js @@ -7,6 +7,7 @@ const collectionRoutes = require('./routes/collectionRoutes'); const exportCardsRoutes = require('./routes/exportCardsRoutes'); const cardImageRoutes = require('./routes/cardImageRoutes'); const versionRoutes = require('./routes/versionRoutes'); +const setsRoutes = require('./routes/setsRoutes'); const app = express(); app.use(cors()); @@ -19,6 +20,7 @@ app.use('/collection', collectionRoutes); app.use('/exportCards', exportCardsRoutes); app.use('/cardImage', cardImageRoutes); app.use('/db-version', versionRoutes); +app.use('/sets', setsRoutes); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { diff --git a/src/routes/setsRoutes.js b/src/routes/setsRoutes.js new file mode 100644 index 0000000..7a84951 --- /dev/null +++ b/src/routes/setsRoutes.js @@ -0,0 +1,8 @@ +const express = require('express'); +const router = express.Router(); +const { getSets, getSetCards } = require('../controllers/setsController'); + +router.get('/', getSets); +router.get('/:setId/cards', getSetCards); + +module.exports = router;