Skip to content

enesyaks/ITACM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ–₯️ ITACM β€” IT Asset Control Pro

Self-hosted IT asset management, batteries included.

Hardware & network inventory Β· employee handovers with printable PDF receipts Β· software licenses Β· mobile lines Β· vendors & contracts Β· repairs Β· physical stock counts Β· a full audit trail β€” all behind a built-in, mobile-ready web UI running entirely on your own infrastructure.


License: MIT Node PostgreSQL Docker Self-hosted No build step Mobile ready i18n


πŸ‡¬πŸ‡§ English Β· πŸ‡ΉπŸ‡· TΓΌrkΓ§e β†’


Dashboard


πŸ“‘ Table of contents


πŸ’‘ Why ITACM?

Most asset trackers are either a spreadsheet that rots or a heavyweight SaaS you can't self-host. ITACM sits in the middle:

  • One command to run. docker compose up -d gives you the database, schema, first admin and a full web UI β€” no build step, no separate frontend to deploy.
  • Handovers that hold up. Every asset assignment is an atomic, row-locked transaction that produces a printable Zimmet Tutanağı (handover receipt) with your company branding.
  • The whole company, one dump. Assets, employees, receipts, contracts, audit history and uploaded documents all live in PostgreSQL, so a single backup captures everything.
  • Works from the warehouse floor. The UI is fully responsive with a mobile bottom-nav and a camera QR/barcode scanner β€” count stock or hand over a laptop from your phone.
  • Yours to keep. No telemetry, no vendor lock-in, MIT licensed.

πŸ“Έ Screenshots

Network & Server topology Providers & Contracts
Network topology Providers
Mobile Lines Physical Stock Count
Mobile Lines Stock Count
Employee detail β€” assets, licenses, lines System Audit Log
Employee detail Audit log
Printable handover receipt Reports & builder
Print preview Reports

Mobile dashboard Β Β  Mobile lines on phone

Responsive layout with bottom navigation and a center QR-scan button.

More screens (hardware inventory, product catalog, handover basket, login) live in docs/screenshots/.


✨ Feature highlights

πŸ–₯ Built-in, mobile-ready web UI

Served by the backend itself β€” no build step, strict same-origin CSP. 15 modules, global search (Cmd/Ctrl+K), QR codes, dark-mode aware, and a responsive shell with mobile bottom-nav + camera scanner. Just open http://localhost:8000.

🀝 Atomic handover basket

Assign multiple assets to an employee in one all-or-nothing transaction, producing a printable handover receipt (Zimmet Tutanağı). Row locks make double-assignment impossible; reprints preserve the original issuer's name.

🎨 Customizable handover designs

Live-preview editor to pick which sections, columns, titles and labels appear on the printed/PDF form, plus multiple visual themes (terminal, classic, corporate, slate).

🌐 Network & Server inventory

Infrastructure gear (switches, firewalls, routers, servers, storage) kept out of personal zimmet β€” assigned to a site + responsible person instead. Interactive dependency topology (per-site graphs, uplinks, cross-site parents) and rack-cabinet U-maps.

🏒 Providers & Contracts

Vendors / ISPs / MSPs as first-class records with contacts, account numbers and support lines. Attach contracts with renewal dates, cost, billing cycle and internal owner; 60-day renewal alerts and per-provider document storage.

πŸ“± Mobile lines

Company SIM cards & phone numbers as first-class inventory: operator, plan, ICCID, monthly cost. Assign / take back with full history β€” lines show up on the employee profile and on handover forms.

πŸ§‘β€πŸ’Ό Guided onboarding & offboarding

Schedule a new hire's kit (reserve assets + lines), then complete it into a single handover. Offboarding is a transactional checklist that returns, reassigns, scraps or sells every asset, seat, line and infra responsibility before deactivating the employee.

πŸ” Role-based access control

Owner, Admin, Helpdesk, Viewer roles enforced on every endpoint, re-checked on each request so changes apply instantly. Owners can disable or delete accounts β€” every disable/enable/delete/role change is recorded. Sign-in is local email/password with optional TOTP MFA, password change, and server-side logout (JWT revoke). There is no SSO / Entra login.

🧾 System-wide audit log

A unified, filterable timeline of all instance activity β€” assets, users, documents, handovers, logins, settings and more β€” merging the append-only audit table with legacy domain history. Search by source, actor and date; secrets are redacted before storage.

⏳ Product lifecycle (EOL)

Lifecycle duration per category plus per-asset overrides (e.g. MacBooks at 5 years) β€” or untick EOL for a category (accessories) to exclude it entirely. Every asset shows its EOL date and "EOL soon" / overdue flags.

πŸ“¦ Physical stock counts

Open a count session and scan from any signed-in device β€” start on the PC, keep scanning barcodes/QRs from your phone camera. Closing the session reconciles against live inventory: found / missing / unknown, with CSV export.

πŸ“₯ Excel / CSV migration

Download the template, fill it with your existing zimmet spreadsheet, upload β€” a dry-run preview shows exactly what will be created, then one transaction auto-creates employees, catalog entries, assets (sequential tags) and one handover per employee with full history.

πŸ“„ Licenses Β· 🏷 labels Β· πŸ’± currency

Seat pools with atomic claim/release and 30-day expiry alerts. Print scannable Code 128 labels (size/fields/copies configurable). Pick your display currency for costs across the app.

🌍 Multi-language UI

12 languages (EN, TR, DE, FR, ES, IT, PT, NL, PL, RU, AR, JA). Pick one on the onboarding screen, change it any time in Settings; untranslated strings fall back to English.

πŸš€ First-run onboarding sets your company name, logo and Owner account; branding flows into the UI and every printed receipt. πŸ§ͺ Demo dataset β€” npm run seed:demo fills Postgres with a realistic company; scale it with SEED_EMPLOYEES=2000 npm run seed:demo -- --reset, and add npm run seed:infra / npm run seed:providers for network gear and vendors.


🧩 Modules

The sidebar maps 1:1 to the feature set:

Module What it does
Dashboard KPIs, attention-required alerts (licenses, low stock, EOL), asset distribution, recent activity
Hardware Full device inventory β€” QR codes, bulk actions, cost/warranty, lifecycle, global search
Network & Server Infra inventory + dependency topology + rack cabinets (site/owner, not personal zimmet)
Product Catalog Approved brands/models, categories, locations, departments, lifecycle & spec options
Software & Licenses Seat pools, atomic claim/release, expiry alerts, per-license holder export
Mobile Lines SIM/phone-number inventory with assignment history
Providers & Contracts Vendor directory + commercial agreements with renewal tracking and documents
Consumables Stock movements with low-stock alerts
Employees Directory, per-person detail (assets/licenses/lines/infra), onboarding & offboarding
Handover Ops Atomic handover basket + printable/PDF receipts
Maintenance & Repair Send to repair / return / scrap, with document attachments
Stock Count Physical count sessions with camera scanning and reconciliation
Reports 19 preset reports + a builder (data sources Γ— columns Γ— filters), CSV / letterhead print
Audit Log Unified, filterable activity timeline (Owner/Admin)
IT Users RBAC user management β€” create, role, disable/enable, delete (audited)

πŸ“± Mobile ready

The entire app is responsive β€” no separate mobile build:

  • Collapsible sidebar with a bottom navigation bar and a center QR-scan button.
  • Camera barcode/QR scanning (via a vendored ZXing build) for stock counts and quick asset lookup.
  • Start on PC, continue on phone: open a stock-count session on your desktop and keep scanning from any signed-in device.
  • Viewport-fit, theme-color and web-app meta so it behaves well when added to a home screen.

🧰 Tech stack

Layer Technology
Runtime Node.js β‰₯ 20, Express 4
Database PostgreSQL 16 β€” idempotent schema.sql + tracked versioned migrations, applied on startup
Auth JWT (HS256, pinned alg) + bcrypt (cost 12), role-based middleware re-checked per request
Frontend Vanilla JS SPA served by the backend β€” no build step, split into per-view modules
PDF / labels PDFKit + QR codes, custom handover templates, Code 128 barcodes
Scanning Vendored ZXing browser build (camera QR/barcode)
Packaging Docker + Docker Compose

πŸš€ Quick start β€” Docker Compose

Everything is automatic: the database container is created, the schema + migrations are applied, and the first Admin (Owner) account is seeded.

git clone https://github.com/<you>/itacm.git
cd itacm

npm install
npm run setup          # generates .env with strong secrets (or copy .env.example)

docker compose up -d
docker compose logs api   # first-run Owner credentials are printed here

Then open http://localhost:8000 β€” the first visit shows the onboarding wizard to set your company name/logo, pick a zimmet design and language, and create the Owner account.

Tip

If you leave ADMIN_PASSWORD empty, a strong random password is generated and printed once in the API logs. Change it after first login.

Prefer to configure by hand? Copy .env.example to .env, set at least JWT_SECRET (openssl rand -hex 32), then docker compose up -d.


🌍 Deploying to a server

The compose file works unchanged on any host with Docker. Put a reverse proxy (Caddy / Nginx / Traefik) with TLS in front of port 8000 and set CORS_ORIGINS to your frontend's origin if it differs.

For managed platforms (Railway, Render, Fly.io, Cloud Run…), deploy the Dockerfile, attach a Postgres add-on, and set the same environment variables (DATABASE_URL, PGSSL=true, JWT_SECRET, ADMIN_*). The schema and migrations are applied automatically on startup.


πŸ’Ύ Backup & recovery

Your entire system β€” assets, employees, handover receipts, contracts, audit history and the document archive (scanned/generated PDFs) β€” lives in PostgreSQL. Back it up regularly.

npm run backup                 # β†’ backups/itacm-YYYYMMDD-HHMMSS.sql.gz
npm run restore backups/itacm-20260707-120000.sql.gz   # replaces current data (asks to confirm)

A single dump captures everything (the document archive is stored inside the database). Copy the backups/ folder somewhere safe, or schedule the command with cron, e.g. daily at 02:00:

0 2 * * *  cd /path/to/ITACM && npm run backup

Changing the database password

POSTGRES_PASSWORD is fixed when the database volume is first created. Editing it in .env and restarting will not work β€” the API will fail to authenticate. To rotate it safely, without losing any data:

npm run change-db-password

Warning

Never run docker compose down -v. The -v flag deletes the database volume and permanently destroys all your data. If the API ever reports password authentication failed, run npm run change-db-password (or restore the previous password in .env) β€” do not wipe the volume.


βš™οΈ Configuration reference

Variable Required Description
PORT / API_PORT – HTTP port (default 8000)
CORS_ORIGINS – Comma-separated allowed origins (blank = same-origin)
DATABASE_URL βœ… postgres://user:pass@host:5432/db (or POSTGRES_URL)
PGSSL – true for managed Postgres over TLS
JWT_SECRET βœ… Min 32 chars β€” openssl rand -hex 32
JWT_EXPIRES_IN – Token lifetime (default 12h)
ADMIN_EMAIL / ADMIN_USERNAME / ADMIN_PASSWORD – First-run Owner seed (password auto-generated if empty)

With docker compose, POSTGRES_DB / POSTGRES_USER / POSTGRES_PASSWORD feed both the database container and the API's DATABASE_URL.


πŸ”Œ API reference

All responses are { success, data } or { success: false, error, details? }. All endpoints (except login / health) require Authorization: Bearer <TOKEN>. Every router applies authenticate; writes/deletes additionally require a role.

Method Endpoint Roles Description
POST /api/auth/login public Email/password β†’ JWT
POST /api/auth/verify-token any Validate token, return profile + permissions
GET/POST /api/auth/users Admin List / create IT users
PATCH /api/auth/users/:uid/role Β· /status Admin/Owner Change role Β· disable/enable (audited)
DELETE /api/auth/users/:uid Owner Delete an IT user (audited)
GET /api/dashboard/stats all KPIs, alerts, recent activity
GET /api/assets Β· /:id all Inventory list (?status=&category=&search=) Β· detail + history
POST/PUT /api/assets Β· /:id Admin, Helpdesk Create / update hardware & infra
POST /api/assets/:id/return Admin, Helpdesk Return an assigned asset to stock
POST /api/handovers Admin, Helpdesk Atomic handover basket (below)
GET /api/handovers Β· /:id all Receipts (feed the printable form)
GET/POST /api/onboardings … /:id/complete Β· /cancel Admin, Helpdesk Schedule / complete / cancel onboarding
POST /api/employees/:id/offboard Admin, Helpdesk Transactional offboarding disposition
GET/POST /api/maintenance Β· /:id/close Admin, Helpdesk Repair logs / send / close ({scrap:true})
GET /api/employees all Directory + handover selector
POST/PUT /api/employees Β· /:id Admin, Helpdesk Create / update
GET/POST /api/licenses Β· /:id/assign Β· /revoke Admin, Helpdesk Seat pools + atomic claim/release
GET/POST /api/lines Β· /:id/assign Β· /unassign Admin, Helpdesk Mobile lines + history
GET/POST /api/providers Β· /contracts Admin, Helpdesk Vendors & contracts (+ document upload/download)
GET/POST /api/consumables Β· /:id/adjust Admin, Helpdesk Stock + atomic movements
GET/POST /api/counts Β· /:id/scan Β· /close Admin, Helpdesk Physical stock-count sessions
GET/PUT /api/catalog/* Admin, Helpdesk Catalog, locations, departments, settings
POST /api/import/inventory Owner, Admin Excel/CSV migration (dry-run + commit)
GET /api/documents/:id/download Owner, Admin, Helpdesk Stream a stored handover document (auth required)
GET /api/audit Β· /:bucket/:id Owner, Admin Unified audit timeline + event detail
The atomic handover basket β€” how it works
POST /api/handovers
{
  "employeeId": "…",
  "documentType": "single",
  "items": [
    { "assetId": "…", "conditionNote": "New, sealed box" },
    { "assetId": "…", "conditionNote": "Used, good condition" }
  ]
}

In one transaction (Postgres BEGIN … FOR UPDATE): every asset is validated as In Stock β†’ the receipt document is created β†’ each asset flips to Assigned bound to the employee β†’ the employee's activeAssetCount is incremented β†’ one audit row is written per asset.

If any asset is locked, the API returns 409 with a per-asset conflict list and nothing is written. Row locks / transaction retries make it impossible for two operators to hand over the same laptop concurrently.


πŸ”’ Security notes

  • Secrets never live in the repo. .env is git-ignored; the setup wizard writes it with 0600 permissions and generates a strong JWT_SECRET and DB password for you. Database backups (backups/) are git-ignored too.
  • Auth: passwords are bcrypt-hashed (cost 12); JWTs are signed HS256 with the algorithm pinned on verify; login uses a single error message and a constant-time compare (dummy hash for unknown emails) so it can't be used to enumerate accounts; every request re-checks the user row so role changes / disables / deletes apply instantly.
  • Access control: every API router mounts authenticate, and mutating routes add requireRole(...). The audit log redacts sensitive keys (passwords, tokens, keys) before persisting.
  • Uploads: document routes validate the real file type by magic bytes (not the client's claim) and cap the body at 12 MB; downloads set a sanitized Content-Disposition. All SQL is parameterized; all rendered values are HTML-escaped.
  • Hardening: strict Content-Security-Policy (no inline scripts, self-only), HSTS, nosniff / frame-deny / referrer / permissions-policy headers, login rate-limiting (20 / 15 min / IP), global API rate limit (1000 / 5 min / IP), same-origin-only CORS by default, 1 MB default body limit, x-powered-by disabled, a one-shot onboarding endpoint that locks itself after first use, and an npm audit-clean dependency tree.
  • Transport: front the API with HTTPS (Caddy / Nginx / Traefik). Set CORS_ORIGINS to your exact frontend origin if it differs.

πŸ—‚ Project structure

β”œβ”€β”€ server.js                  Node/Docker entry (auto-migrates on startup)
β”œβ”€β”€ public/                    Built-in web UI (vanilla JS SPA, no build step)
β”‚   β”œβ”€β”€ index.html             App shell + onboarding/login
β”‚   β”œβ”€β”€ css/app.css
β”‚   └── js/
β”‚       β”œβ”€β”€ api.js  i18n.js  ui.js  money.js  barcode.js  mobile-shell.js
β”‚       └── views/             One module per screen (dashboard, assets, network,
β”‚                              providers, audit, onboarding, stockcount, …)
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app.js                 Express app, body limits, audit middleware, route mounting
β”‚   β”œβ”€β”€ config/                Env parsing
β”‚   β”œβ”€β”€ middleware/            Bearer auth + role gate, error handling
β”‚   β”œβ”€β”€ routes/                Thin controllers (assets, providers, contracts, audit, …)
β”‚   β”œβ”€β”€ utils/                 PDF, uploadGuard, contentDisposition, permissions, defaults
β”‚   β”œβ”€β”€ services/              Backend-agnostic service facade
β”‚   └── providers/postgres/    JWT auth + PostgreSQL
β”‚       β”œβ”€β”€ schema.sql         Idempotent base schema
β”‚       β”œβ”€β”€ migrations/        Tracked versioned migrations (schema_migrations)
β”‚       β”œβ”€β”€ migrate.js         Applies schema.sql + pending migrations
β”‚       └── *Service.js        assets, employees, providers, audit, offboard, onboarding, …
β”œβ”€β”€ scripts/                   setup Β· seed-demo Β· seed-infra Β· seed-providers Β· backup Β· restore
β”œβ”€β”€ docker-compose.yml         Self-hosted stack (API + Postgres)
β”œβ”€β”€ Dockerfile Β· docker-entrypoint.sh
└── .env.example               Fully documented configuration template

πŸ§‘β€πŸ’» Development

npm install
npm run setup      # or hand-write .env
npm run dev        # auto-restarting local server
npm run lint       # syntax check (server + all src/scripts)
npm run migrate    # apply schema + pending migrations manually (optional)

# Demo data
npm run seed:demo                                  # ~500 employees
SEED_EMPLOYEES=2000 npm run seed:demo -- --reset   # larger, historical dataset
npm run seed:infra                                 # network/server gear + topology
npm run seed:providers                             # vendors + contracts

πŸ“œ License

Released under the MIT license.


Built with ❀️ by Enes Yakışık · If ITACM helps you, consider giving it a ⭐

About

No description, website, or topics provided.

Resources

License

Stars

1 star

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages