7.3 KiB
AGENTS.md
Guide for coding agents working in this repository.
Repo reality
This repo is an ESM TypeScript scraper focused on Magnit supermarket data.
The active stack is Playwright, Axios, PostgreSQL, and Drizzle ORM.
Use package.json and src/ as source of truth.
Treat README.md carefully.
It still documents useful local setup like docker-compose up -d, but it also contains stale Prisma-era commands and descriptions that no longer match the code.
Do not treat README Prisma commands as the current workflow.
Package manager and commands
Use pnpm.
pnpm install
pnpm exec playwright install chromium
pnpm type-check
pnpm build
pnpm dev
pnpm enrich
pnpm test-db
pnpm db:generate
pnpm db:migrate
pnpm db:push
pnpm db:studio
Command mapping:
pnpm type-check,tsc --noEmitpnpm build, compile TypeScript todist/pnpm dev, runsrc/scripts/scrape-magnit-products.tspnpm enrich, runsrc/scripts/enrich-product-details.tspnpm test-db, runsrc/scripts/test-db-connection.tspnpm db:*, Drizzle migration and studio commands
There is no lint command, no automated test framework, and no single-test execution command today.
Local DB setup and verification reality
The README still documents docker-compose up -d for local PostgreSQL, and that is still the documented bootstrap step.
Current source uses Drizzle, not Prisma, so do not describe pnpm prisma:* commands as current.
Use the commands that actually exist for validation:
pnpm type-checkpnpm buildpnpm test-db, when DB setup or connectivity is involvedpnpm dev, when scraper behavior is involvedpnpm enrich, when enrichment flow is involved
There is no Jest, Vitest, Mocha, or similar runner configured, no per-file test command, and no single-test pattern to follow.
Direct script entry points
Main scripts are src/scripts/scrape-magnit-products.ts, src/scripts/enrich-product-details.ts, and src/scripts/test-db-connection.ts.
Direct execution example:
tsx src/scripts/scrape-magnit-products.ts
MAGNIT_STORE_CODE=992301 tsx src/scripts/scrape-magnit-products.ts
TypeScript and module conventions
The project is ESM TypeScript. package.json sets "type": "module". tsconfig.json uses strict: true, module: "ESNext", and moduleResolution: "bundler".
Observed conventions:
- Local imports use the
.jsextension - External imports are usually first, then local imports, but the repo is mixed
- Match nearby file style instead of rewriting unrelated imports
- Public APIs and service methods often have explicit types
- Pragmatic
anyand casts are present around ORM and script boundaries - Do not invent a fake rule that every type must be explicit everywhere
Naming and file naming
Follow the naming already in the repo.
- Classes, interfaces, and major service types use PascalCase
- Functions, variables, and object properties use camelCase
- Constants often use UPPER_SNAKE_CASE
- Class and service files are usually PascalCase, for example
MagnitApiScraper.ts - Utility, config, database, and schema files are usually lowercase, for example
logger.ts,errors.ts,client.ts,schema.ts - Script files are kebab-case, for example
scrape-magnit-products.ts
Logging, comments, and errors
Prefer Logger from src/utils/logger.ts for application code.
It provides info, error, warn, and debug, with debug gated by DEBUG === 'true'.
Loggeris preferred in scraper and service code- Plain
console.logandconsole.errorstill appear in infra and test-style scripts src/config/database.tsandsrc/scripts/test-db-connection.tsare current examples- Comments and log messages are often Russian, so keep language and tone consistent with nearby code
Active error classes live in src/utils/errors.ts.
DatabaseErroris actively used inProductServiceAPIErroris actively used inMagnitApiScraperScraperErrorexists, but it is not a common active pattern today
Common style is to catch low-level failures, log the original error, and re-throw a domain-specific error when that pattern already exists nearby.
Database and schema patterns
The active DB layer is Drizzle.
Source-backed facts:
- DB client is
src/database/client.ts - It exports
db = drizzle(pool, { schema }) src/config/database.tsre-exportsdband provides connect and disconnect helpers- Schema lives in
src/db/schema.ts - Products have a composite unique constraint on
(externalId, storeId) - Product price columns are decimal values
- Parser code converts inbound kopecks to rubles before persistence
Common query style uses Drizzle builders such as:
.select().from(...).where(...).insert().values(...).returning().update().set(...).where(...).returning()
Batch size 50 is a common working number in product saving and scraper pagination defaults.
Service and scraper flow
Keep the existing responsibilities intact.
MagnitApiScraperowns Playwright session setup, cookie and device-id capture, API requests, retries, reinit behavior, pagination, and streaming batchesProductParsertransforms API payloads intoCreateProductDataand enrichment fieldsProductServiceowns store, category, and product persistence
Main persistence flow:
MagnitApiScraperfetches product batchesProductParsermaps API items into DB-ready structuresProductServicecreates or updates stores, categories, and products
Prefer extending that flow over bypassing it.
Avoid dropping raw Drizzle writes into scraper fetch logic when ProductService already owns the path.
Scripts and direct DB access
Production-style scraper flow leans on services. Some debug and utility scripts are more direct.
src/scripts/scrape-magnit-products.tsusesconnectDatabase,disconnectDatabase, and passesdbinto scraper save methodssrc/scripts/enrich-product-details.tsinstantiatesProductServicedirectly and coordinates enrichment batches- Debug or infra-style code may query
dbdirectly when narrowly focused on setup or inspection
Match the local pattern instead of forcing extra abstraction into one-off scripts.
Environment variables
Common variables confirmed by source and docs:
DATABASE_URL=postgresql://user:password@localhost:5432/supermarket
MAGNIT_STORE_CODE=992301
DEBUG=true
Other runtime variables used by scripts include MAGNIT_USE_STREAMING, MAGNIT_MAX_PRODUCTS, MAGNIT_STORE_TYPE, MAGNIT_CATALOG_TYPE, MAGNIT_HEADLESS, MAGNIT_PAGE_SIZE, MAGNIT_RATE_LIMIT_DELAY, MAGNIT_MAX_ITERATIONS, MAGNIT_RETRY_ATTEMPTS, and FETCH_OBJECT_INFO.
Cursor Requestly rule
The repo includes a Cursor rule at .cursor/rules/requestly-test-rules.mdc for .requestly-supermarket/**/*.json.
Preserve these points:
- Use
rq.test()for tests - Use
rq.expect()for assertions - Read response data from
rq.response.bodyand parse it as JSON before working with fields - Prices in these Requestly payloads are in kopecks, for example
24999means249.99rubles
Practical guidance
Read nearby files before standardizing style.
Prefer source over README when they disagree, document Drizzle not Prisma, and do not claim linting, automated tests, or single-test support that does not exist.
When changing scraper persistence, check MagnitApiScraper, ProductParser, and ProductService together.