# AvtoAmbor — Auto Parts Inventory System (v1 scaffold) ## Context Build a simple, single-user inventory system named "AvtoAmbor" for an auto parts store in Tajikistan. Development is on Linux inside Docker; the production target is a Windows machine where the owner will access it via browser on localhost. v1 is PARTS ONLY — no service jobs, customers, or invoicing. Do not write tests, lint config, or CI in this pass. Keep the code idiomatic, lightly commented, and not over-engineered. ## Tech stack (strict) - Node.js 20 LTS, run via Docker - SQLite via `better-sqlite3` - SvelteKit 2.x pinned to **Svelte 4** — `"svelte": "^4.2.0"` in package.json. Use Svelte 4 syntax only: no runes, no `$state`/`$derived`/`$effect`. - `@sveltejs/adapter-node` for production (so deployment to Windows is just `node build/index.js`) - Plain CSS. No Tailwind, no component library. ## Repo layout avtoambor/ Makefile Dockerfile docker-compose.yml .dockerignore .gitignore README.md package.json svelte.config.js vite.config.js src/ app.html hooks.server.js # opens db on startup lib/ server/ db.js # better-sqlite3, WAL mode, foreign keys on schema.sql seed.sql parts.js # CRUD helpers movements.js suppliers.js i18n/ en.json tg.json store.js # locale store + t(key) helper components/ Header.svelte # "AvtoAmbor" wordmark + EN/Тоҷ toggle routes/ +layout.svelte # renders
+page.svelte # dashboard parts/ +page.svelte # list, search, sort +page.server.js new/ +page.svelte +page.server.js [id]/ +page.svelte # edit + recent movements +page.server.js movements/ new/ +page.svelte +page.server.js suppliers/ +page.svelte +page.server.js data/ # gitignored; holds avtoambor.db scripts/ init-db.js # reads schema.sql + seed.sql, writes data/avtoambor.db ## Database schema (initial guess — we will iterate) - All translated fields use `_en` and `_tg` suffixes. - Money stored as INTEGER dirams (1 TJS = 100 dirams). - Timestamps as ISO 8601 TEXT (`datetime('now')`). Tables: - categories(id PK, name_en, name_tg, sort_order) - suppliers(id PK, name, phone, address, notes, created_at) - parts(id PK, sku UNIQUE NOT NULL, name_en, name_tg, description_en, description_tg, category_id FK, unit TEXT, cost_price INT, sale_price INT, quantity_on_hand INT DEFAULT 0, reorder_level INT DEFAULT 0, location TEXT, barcode TEXT, active INT DEFAULT 1, created_at, updated_at) - stock_movements(id PK, part_id FK, movement_type CHECK(movement_type IN ('in','out','adjust')), quantity INT, unit_price INT, supplier_id FK NULL, reference TEXT, notes TEXT, created_at) Indexes on parts.sku, parts.barcode, parts.category_id, stock_movements.part_id. Update `parts.quantity_on_hand` in application code (in a transaction with the movement insert), not via trigger — clearer for future-me. ## Seed data - 5–6 categories: Filters, Brakes, Engine, Electrical, Fluids, Belts & Hoses - 3–4 suppliers with realistic names - 25–30 realistic auto parts with EN and Tajik (Cyrillic) names. Bias toward parts common for Lada, Daewoo Nexia, Opel, and Toyota, which are common in Tajikistan. Use realistic somoni prices. ## UI - `Header.svelte` (in `+layout.svelte`, every page): - Left: "AvtoAmbor" wordmark - Right: language toggle showing the *other* language (click EN → switches to Tajik). Persist choice to `localStorage` under key `avtoambor.locale`. - Pages for v1: - `/` dashboard: total SKUs, count of parts at/below reorder level, total inventory value at cost - `/parts` searchable + sortable list - `/parts/new` create - `/parts/[id]` edit, with recent movements panel - `/movements/new` record in/out/adjust - `/suppliers` list + add inline - Every visible string goes through the i18n helper. Missing keys fall back to English and log a `console.warn` once per missing key. GIve it a Tajik look & feel, if that's even possible for such a simple app ## i18n - `en.json` and `tg.json` with nested keys (e.g. `nav.parts`, `parts.sku`) - `store.js` exports a writable `locale` store and a derived `t` function: `$t('parts.sku')` in templates - Default locale is `'tg'`. On mount in the layout, read `localStorage` and hydrate if present. ## Makefile Targets (use `docker compose`). First target = `help`. - `help` — print a friendly banner + list of targets with descriptions - `install` — `docker compose run --rm app npm install` - `run` — `docker compose up` (dev server on 5173) - `build` — production build via adapter-node into `build/` - `db-init` — run `scripts/init-db.js`, skip if `data/avtoambor.db` exists - `db-reset` — confirm prompt, then delete and recreate the db - `docker-build` — build the image - `docker-shell` — interactive bash in the container - `clean` — remove `node_modules`, `build/`, but keep `data/` - `clean-all` — also wipe `data/` Use `@` to suppress command echo where it would be noise. ## Dockerfile - `node:20-bookworm-slim` - Install `python3 make g++` for the `better-sqlite3` native build - Non-root user - WORKDIR `/app` - EXPOSE 5173 and 3000 ## docker-compose.yml - One service `app` - Bind-mount the repo to `/app` - Named volume for `node_modules` so it doesn't shadow the host - Bind-mount `./data` so the SQLite file persists on the host - Map 5173:5173 and 3000:3000 ## README.md Short: what it is, prerequisites (Docker), quickstart (`make install && make db-init && make run`), and a one-liner on production: `make build` then `node build/index.js` on the Windows host. ## Deliverables for this pass 1. Generate every file above, working out of the box. 2. Print the resulting file tree. 3. Print the exact command sequence to bring it up from a fresh clone. 4. Call out anything you guessed at that I should review before we move on.