# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Filamenteka is a 3D printing filament inventory management system for tracking Bambu Lab filaments. It consists of: - **Frontend**: Next.js app with React, TypeScript, and Tailwind CSS (static export to `/out`) - **Backend**: Node.js Express API server (`/api/server.js`) with PostgreSQL database - **Infrastructure**: AWS (CloudFront + S3 for frontend, EC2 for API, RDS for database) - **Repository**: `git.demirix.dev/dax/Filamenteka` ## Critical Rules - NEVER mention ANY author in commits. No author tags or attribution of any kind - Build for AMD64 Linux when deploying (development is on ARM macOS) - Always run security checks before commits (Husky pre-commit hook does this automatically) ## Common Commands ```bash # Development npm run dev # Start Next.js dev server (port 3000) npm run build # Build static export to /out npm run lint # ESLint npm test # Jest tests npm run test:watch # Jest watch mode npm test -- --testPathPattern=__tests__/components/ColorCell # Run single test file # API Development cd api && npm run dev # Start API with nodemon (port 4000) # Quality Gates npm run security:check # Credential leak detection npm run test:build # Verify build succeeds without deploying npx tsc --noEmit # TypeScript type checking # Database npm run migrate # Run pending migrations locally scripts/update-db-via-aws.sh # Run migrations on production RDS via EC2 # Deployment (auto via CI/CD on push to main, or manual) scripts/deploy-api-update.sh # Deploy API to EC2 via AWS SSM scripts/deploy-frontend.sh # Manual frontend deploy to S3/CloudFront ``` ## Architecture ### Frontend (Next.js App Router) - `/app/page.tsx` — Public filament inventory table (home page) - `/app/upadaj/` — Admin panel: login, `/dashboard` (filament CRUD), `/colors` (color management), `/customers` (customer management), `/sales` (sales recording), `/requests` (customer color requests), `/analytics` (revenue/inventory dashboards) - `/src/services/api.ts` — Axios instance with auth interceptors (auto token injection, 401/403 redirect) - `/src/data/bambuLabColors.ts` — Primary color-to-hex mapping with gradient support (used by `ColorCell` component) - `/src/data/bambuLabColorsComplete.ts` — Extended color database grouped by finish type (used by filters) ### API (`/api/server.js`) Single-file Express server running on EC2 (port 80). All routes inline. - Endpoints: `/api/login`, `/api/filaments`, `/api/colors`, `/api/customers`, `/api/sales`, `/api/color-requests`, `/api/analytics/*` - Auth: JWT tokens with 24h expiry, single admin user (password from `ADMIN_PASSWORD` env var) ### Database (PostgreSQL on RDS) Key schemas and constraints: ``` filaments: id, tip (material), finish, boja (color), refill, spulna, kolicina, cena, sale_* colors: id, name, hex, cena_refill (default 3499), cena_spulna (default 3999) customers: id, name, phone (unique), city, notes, created_at sales: id, customer_id (FK→customers), total_amount, notes, created_at + sale_items join table color_requests: id, color_name, message, contact_name, contact_phone, status ``` **Critical constraints:** - `filaments.boja` → FK to `colors.name` (ON UPDATE CASCADE) — colors must exist before filaments reference them - `kolicina = refill + spulna` — enforced by check constraint - Migrations in `/database/migrations/` with sequential numbering (currently up to `023_`) ## Key Patterns ### Color Management (two-layer system) 1. **Database `colors` table**: Defines valid color names + pricing. Must be populated first due to FK constraint. 2. **Frontend `bambuLabColors.ts`**: Maps color names → hex codes for UI display. Supports solid (`hex: '#FF0000'`) and gradient (`hex: ['#HEX1', '#HEX2'], isGradient: true`). 3. Color names must match exactly between `colors.name`, `filaments.boja`, and `bambuLabColors.ts` keys. 4. The `ColorCell` component renders table row backgrounds from these mappings. ### Adding New Colors 1. Add to database `colors` table (via admin panel at `/upadaj/colors` or migration) 2. Add hex mapping to `src/data/bambuLabColors.ts` 3. Optionally add to `src/data/bambuLabColorsComplete.ts` finish groups ### API Communication - Service modules in `src/services/api.ts`: `authService`, `colorService`, `filamentService`, `colorRequestService`, `customerService`, `saleService`, `analyticsService` - Auth token stored in localStorage with 24h expiry - Cache busting on filament fetches via timestamp query param ## CI/CD (Gitea Actions) `.gitea/workflows/deploy.yml` triggers on push to `main`. Auto-detects changes via `git diff HEAD~1`: - **Frontend changes** (anything outside `api/`): security check → tests → build → S3 deploy (3-tier cache: HTML no-cache, `_next/` immutable, rest 24h) → CloudFront invalidation - **API changes** (`api/` files): SSM command to EC2 to pull `server.js` from Gitea and restart `node-api` service - Both run if both changed in a single push ## Deployment Details | Component | Target | Method | |-----------|--------|--------| | Frontend | S3 `filamenteka-frontend` → CloudFront | Static export, OAC-protected | | API | EC2 `i-03956ecf32292d7d9` | SSM, systemd `node-api` service | | Database | RDS `filamenteka.ci7fsdlbzmag.eu-central-1.rds.amazonaws.com` | Migrations via `scripts/update-db-via-aws.sh` | | DNS | Cloudflare | `api.filamenteka.rs` → EC2 | | IaC | `/terraform/` | VPC, EC2, RDS, ALB, CloudFront, Cloudflare | ## Environment Variables ```bash # Frontend (.env.local) NEXT_PUBLIC_API_URL=https://api.filamenteka.rs/api NEXT_PUBLIC_MATOMO_URL=https://analytics.demirix.dev NEXT_PUBLIC_MATOMO_SITE_ID=7 # API Server (.env in /api) DATABASE_URL=postgresql://filamenteka_admin:PASSWORD@filamenteka.ci7fsdlbzmag.eu-central-1.rds.amazonaws.com:5432/filamenteka JWT_SECRET=... ADMIN_PASSWORD=... NODE_ENV=production PORT=80 ``` ## Pre-commit Hooks (Husky) `scripts/pre-commit.sh` runs automatically and blocks commits that fail: 1. Author mention check (blocks attribution) 2. Security check (credential leaks) 3. Build test (ensures compilation) 4. Unit tests (`jest --passWithNoTests`)