{"id":51781884,"url":"https://github.com/andrijzyn/handmade-wms","last_synced_at":"2026-07-20T13:04:04.550Z","repository":{"id":344256110,"uuid":"1180900698","full_name":"andrijzyn/handmade-wms","owner":"andrijzyn","description":"Stock Pulse - Diploma project for Jr. Bachelor of Software Engeneering","archived":false,"fork":false,"pushed_at":"2026-06-30T21:04:33.000Z","size":6727,"stargazers_count":0,"open_issues_count":6,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-30T21:22:01.536Z","etag":null,"topics":["ai-agent","audit-logging","crud","iron-session","netlify","nextjs","restful-api","sql","supabase-db","typescript","wms"],"latest_commit_sha":null,"homepage":"https://timely-croissant-26e162.netlify.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrijzyn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-13T14:32:08.000Z","updated_at":"2026-06-30T21:01:11.000Z","dependencies_parsed_at":"2026-03-27T03:01:59.826Z","dependency_job_id":null,"html_url":"https://github.com/andrijzyn/handmade-wms","commit_stats":null,"previous_names":["andrijzyn/next-platform-starter","andrijzyn/military-inventory-management-system","andrijzyn/military-warehouse-management-system","andrijzyn/handmade-wms"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/andrijzyn/handmade-wms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrijzyn%2Fhandmade-wms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrijzyn%2Fhandmade-wms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrijzyn%2Fhandmade-wms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrijzyn%2Fhandmade-wms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrijzyn","download_url":"https://codeload.github.com/andrijzyn/handmade-wms/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrijzyn%2Fhandmade-wms/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35686949,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"ssl_error","status_checked_at":"2026-07-20T02:08:09.736Z","response_time":111,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agent","audit-logging","crud","iron-session","netlify","nextjs","restful-api","sql","supabase-db","typescript","wms"],"created_at":"2026-07-20T13:04:03.830Z","updated_at":"2026-07-20T13:04:04.544Z","avatar_url":"https://github.com/andrijzyn.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# StockPulse — Military Inventory Management System \n\n\u003cimg width=\"1870\" height=\"1025\" alt=\"image\" src=\"https://github.com/user-attachments/assets/15329784-8fab-4f1b-9221-1c31c0337969\" /\u003e\n\nA logistics and inventory management system for military warehouses. Built with **Next.js 16** (App Router), **Supabase** (PostgreSQL), and deployed on **Netlify**.\n\n\u003e (RN only for one division as the basis of the system)\n\nAuthentication is implemented with a custom session layer (iron-session + bcrypt) to minimise dependency on external providers and simplify future migrations to on-premise deployments.\n\n---\n\n[![Netlify Status](https://api.netlify.com/api/v1/badges/bdf2edfe-59ca-4dc1-a32a-fd8d85621657/deploy-status)](https://app.netlify.com/projects/timely-croissant-26e162/deploys)\n\n[Docs](https://documenter.getpostman.com/view/40522977/2sBXwjvtDk)\n\n---\n\n## Features\n\n- **Product management** — create, edit, and delete inventory items with SKU, category, price, stock thresholds, categories, filters, and classifications\n- **Location tracking** — assign products to warehouse locations (row / column / level), view product info by ID and location, and track allocated vs. unallocated quantities with per-product location breakdown\n- **Allocation indicator** — visual balance status per product: Balanced, Unallocated, or Exceeded\n- **User management** — permissions-based access to functions with dedicated permission assignment module for administration\n- **Authentication** — cookie-based sessions via iron-session with bcrypt password hashing\n- **Search \u0026 sort** — filter products and locations by name, SKU, and category\n- **Low stock alerts** — configurable per-product threshold with dashboard indicators\n- **Database integration** — Supabase (PostgreSQL) used for persistent product, location, and access data storage\n\n---\n\n## Technology Stack\n\n| Layer      | Technology                                          |\n| ---------- | --------------------------------------------------- |\n| Framework  | Next.js 15 (App Router), React 19, TypeScript       |\n| Styling    | Tailwind CSS v3, shadcn/ui (Radix UI), Lucide icons |\n| State      | TanStack Query v5                                   |\n| Forms      | React Hook Form + Zod                               |\n| Auth       | iron-session (cookie-based), bcrypt                 |\n| Database   | Supabase (PostgreSQL) via `@supabase/supabase-js`   |\n| Deployment | Netlify + `@netlify/plugin-nextjs`                  |\n\n---\n\n## Done\n\n- [x] Build Supabase (PostgreSQL) integration\n- [x] Authentication via iron-session + bcrypt\n- [x] Add Product table with - Categories, Filters, and Classifications\n- [x] View product info by ID and location\n- [x] Per-product location breakdown with quantity tracking\n- [x] Separate functions by permissions\n- [x] Create module for permission assignment\n- [x] Create module for logging changes with displaying differences\n- [x] Mobile-optimised layout\n\n***\n\n## Security and accesible\n\n- [ ] Set different SKUs filtering by UAL — юзер бачить тільки те, до чого має допуск\n- [ ] Limit to one login connection per user — активна сесія одна, нова заходить і скидає стару\n\n***\n\n## Security Findings\n\n### Vuln 1: Hardcoded Fallback Session Secret — `src/lib/auth.ts:19`\n\n* **Severity:** High\n* **Category:** `weak_cryptography` / `authentication_bypass`\n* **Confidence:** 9/10\n* **Description:** The `iron-session` password (used as the HMAC key to sign and encrypt all session cookies) falls back to the hardcoded literal `\"stockpulse-dev-secret-must-be-at-least-32-chars\"` when `SESSION_SECRET` is not set in the environment. This string is publicly visible in the repository.\n* **Exploit Scenario:** An attacker who has read the repository clones it, reads the fallback string, and uses the `iron-session` library to seal a crafted session object `{ user_id: \"\u003ctarget-id\u003e\" }` with the known key. If any deployment (staging, CI, a rushed production push) is missing `SESSION_SECRET`, the server accepts the forged cookie as a fully authenticated session, granting access to any user account without knowing the password.\n* **Fix:** Removed fallback — `SESSION_SECRET` is now required at startup; the server throws if it is absent. ✅\n\n---\n\n### Vuln 2: Debug Endpoint Left in Production Code — `src/app/api/debug/route.ts`\n\n* **Severity:** Medium\n* **Category:** `information_disclosure`\n* **Confidence:** 9/10\n* **Description:** A `/api/debug` endpoint exists in the production source tree. The endpoint is gated by `read_debug` permission and returns up to 10 user records with full permission sets, product count, and whether `SUPABASE_SERVICE_ROLE_KEY` and `SESSION_SECRET` are configured.\n* **Exploit Scenario:** An attacker who obtains a `read_debug`-granted account calls `GET /api/debug` to receive a complete map of all user accounts and their exact permission sets, identifying high-value targets.\n* **Status:** Accepted — endpoint is protected by a dedicated `read_debug` permission that must be explicitly assigned.\n\n---\n\n### Vuln 3: Default `admin/admin123` Credential in Seed File — `supabase/seed.sql:6`\n\n* **Severity:** Medium\n* **Category:** `default_credentials`\n* **Confidence:** 8/10\n* **Description:** The seed file previously documented the default admin password in a plaintext comment. Any deployment that ran the seed without rotating the password is directly vulnerable.\n* **Exploit Scenario:** `POST /api/auth/login` with `{\"username\":\"admin\",\"password\":\"admin123\"}` yields an admin session on any instance where the password was not changed after seeding.\n* **Fix:** Removed the plaintext password comment from the seed file. ✅ Change the admin password immediately after first login on any new deployment.\n\n***\n\n## Operational management (InBound / OutBound)\n\n- [ ] Create InBound / OutBound module — форми надходження і видачі з часом, відповідальним і підписом\n- [ ] Automatic/manual loading into field stores — автоматична/ручна алокація по складах при InBound\n- [ ] Set enclosure for adding/editing products without OrderID — додати продукти безпосередньо через продуктовий модуль\n- [ ] Build Order Management module (Creating, Picking, Checking, Dispatching), which should connect warehouse workers with (products \u0026 locations)\n- [ ] System for Disposing of Damaged Products\n\n***\n\n## Logging\n\n- [ ] Export audit log to CSV / PDF for reporting\n- [ ] Add stock movement dashboard with time-based charts\n\n***\n\n## UX\n\n- [ ] PWA support — встановити як застосунок на телефон без апстору\n- [ ] Barcode / QR scan — замість ручного вводу SKU на складі\n- [ ] Unify Windows by example of \"User-form\"\n\n***\n\n## Ideas for to do\n\n| Функція | Чому важливо |\n|---|---|\n| Звіт по залишках (PDF/XLSX) | Офіцер звітує документом, не скріншотом |\n| Threshold alerts у реальному часі | Email або браузерне сповіщення при low stock |\n| Bulk import через CSV | Завести великий каталог без ручного введення |\n| Історія руху по продукту | Скільки і коли прийшло/пішло по конкретній позиції |\n| Multi-warehouse | Один інстанс для кількох об'єктів зі зведеним дашбордом |\n| Друк документів | Накладна, акт списання, картка продукту для підпису |\n\n***\n\n## Prioritate\n\n1. **Permissions module** — без цього все інше небезпечно\n2. **InBound/OutBound module** — без цього система не ведеться як облік\n3. **User action logging** — без цього немає підзвітності\n4. **Mobile layout** — без цього система не використовується на складі\n5. **Export документів** — без цього адміністративна робота ведеться в іншому місці\n\n---\n\n## Database Setup (Supabase)\n\n### 1. Create a project\n\n1. Go to [supabase.com](https://supabase.com) and create a new project.\n2. Choose a name, password, and region (EU-Central recommended).\n3. Wait for provisioning to complete.\n\n### 2. Run migrations\n\nOpen **SQL Editor** in the Supabase dashboard and execute in order:\n\n1. `supabase/schema.sql` — creates `products`, `users`, `locations`, and `product_locations` tables with foreign key constraints\n2. `supabase/seed.sql` — inserts default admin user and sample products\n\n### 3. Get your API keys\n\nGo to **Supabase Dashboard → Settings → API** and copy:\n\n- **Project URL** → `NEXT_PUBLIC_SUPABASE_URL`\n- **service_role key** → `SUPABASE_SERVICE_ROLE_KEY`\n\n---\n\n## Local Development\n\n```bash\n# 1. Install dependencies\nnpm install\n\n# 2. Configure environment\ncp .env.local.example .env.local\n# Fill in your Supabase URL, keys, and session secret\n\n# 3. Start dev server\nnpm run dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000).\n\n**Demo credentials**\n| Field | Value |\n|---|---|\n| Username | `admin` |\n| Password | `admin123` |\n\n---\n\n## Environment Variables\n\n| Variable                    | Source                                   | Description                         |\n| --------------------------- | ---------------------------------------- | ----------------------------------- |\n| `NEXT_PUBLIC_SUPABASE_URL`  | Supabase → Settings → API → Project URL  | Public Supabase project URL         |\n| `SUPABASE_SERVICE_ROLE_KEY` | Supabase → Settings → API → service_role | Secret key — never expose to client |\n| `SESSION_SECRET`            | Generate manually (32+ chars)            | Cookie encryption secret            |\n\nGenerate a session secret:\n\n```bash\nopenssl rand -base64 32\n```\n\n---\n\n## Build\n\n```bash\nnpm run build\n```\n\n---\n\n## Contributing\n\n1. Fork the repository and clone your fork\n2. Create a branch: `feature/\u003cname\u003e` or `bugfix/\u003cname\u003e`\n3. Install dependencies and verify the build passes locally\n4. Run lint and type check:\n   ```bash\n   npm run lint\n   npx tsc --noEmit\n   ```\n5. Commit with a clear message and push to your fork\n6. Open a Pull Request against the `dev` branch — include a short description of the change and any related issue numbers\n\n**Code style**\n\n- Follow existing ESLint and Prettier config — `npm run lint` fixes most issues automatically\n- Keep TypeScript types accurate; avoid `any` unless absolutely necessary\n- Write small, focused commits — one logical change per commit\n\n---\n\n## API Endpoints\n\n| Method           | Endpoint                       | Description                            |\n| ---------------- | ------------------------------ | -------------------------------------- |\n| GET/POST         | `/api/products`                | List and create products               |\n| GET/PATCH/DELETE | `/api/products/[id]`           | Get, update, or delete a product       |\n| GET/POST         | `/api/products/[id]/locations` | List and assign locations to a product |\n| PATCH/DELETE     | `/api/product-locations/[id]`  | Update or remove a location assignment |\n| GET              | `/api/locations`               | Search available warehouse locations   |\n| GET/POST         | `/api/users`                   | List and create users                  |\n| PATCH/DELETE     | `/api/users/[id]`              | Update or delete a user                |\n| POST             | `/api/auth/login`              | Authenticate and create session        |\n| POST             | `/api/auth/logout`             | Destroy session                        |\n| GET              | `/api/auth/me`                 | Get current session user               |\n| GET              | `/api/stats`                   | Dashboard KPI summary                  |\n\nAll endpoints require authentication. Unauthenticated requests return `401 Unauthorized`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrijzyn%2Fhandmade-wms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrijzyn%2Fhandmade-wms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrijzyn%2Fhandmade-wms/lists"}