A complete POS (Point of Sale) and Inventory Management system built with Next.js 16, TypeScript, and PostgreSQL.
- Authentication System: Login, register, forgot password, account activation with JWT
- User Management: RBAC with 5 roles (Super Admin, Admin, Warehouse Manager, Cashier, Finance)
- Customer Management: Full CRUD for customer data
- Product Management: Products with types (Raw Material, Finished Goods, Service), units, and inventory tracking
- Unit Quantity Management: Configurable units of measurement
- Inventory Management: Real-time stock tracking, manipulation (add/remove), and detailed summaries
- Transaction Management: Buy/Sell transactions with multiple items, discounts, and taxes
- Payment Management: Multiple payment types (Cash, Card, QRIS, Transfer) with status tracking
- Tax Management: Configurable tax rates
- Analytics & Reports: Transaction summaries, product-specific reports, inventory summaries
- Role-Based Access Control: Granular permissions across all features
- Frontend: Next.js 16.0.3, React 19.2.0, TypeScript 5
- UI Library: Radix UI primitives, Tailwind CSS v4, shadcn/ui components, lucide-react icons
- Charts: Recharts for data visualization
- Backend: Next.js API Routes with 3-layer architecture (Handler → Service → Repository)
- Database: PostgreSQL with pg driver, raw SQL queries
- Authentication: JWT tokens (jsonwebtoken), bcryptjs for password hashing
- Email: nodemailer for account activation and password reset
src/
├── app/ # Next.js App Router
│ ├── (public)/ # Public route group (no authentication)
│ │ ├── api/ # Public API routes
│ │ │ └── auth/ # Auth endpoints (login, register, forgot password)
│ │ ├── login/ # Login page
│ │ ├── register/ # Register page
│ │ └── layout.tsx # Public layout wrapper
│ ├── (private)/ # Private route group (requires JWT authentication)
│ │ ├── api/ # Protected API routes (all require Bearer token)
│ │ │ ├── users/ # User CRUD
│ │ │ ├── customers/ # Customer CRUD
│ │ │ ├── products/ # Product CRUD
│ │ │ ├── taxes/ # Tax CRUD
│ │ │ ├── unit-quantities/ # Unit quantity CRUD
│ │ │ ├── inventory-histories/ # Inventory operations
│ │ │ ├── transactions/ # Transaction management
│ │ │ ├── payments/ # Payment processing
│ │ │ ├── finance/ # Finance dashboard data
│ │ │ └── me/ # Current user info
│ │ ├── customers/ # Customer pages
│ │ ├── dashboard/ # Dashboard
│ │ ├── inventory-histories/ # Inventory pages
│ │ ├── payments/ # Payment pages
│ │ ├── products/ # Product pages
│ │ ├── taxes/ # Tax pages
│ │ ├── transactions/ # Transaction pages
│ │ ├── unit-quantities/ # Unit quantity pages
│ │ ├── users/ # User pages
│ │ └── layout.tsx # Protected layout wrapper
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
├── client/ # Client-side code
│ ├── components/ # Reusable UI components
│ ├── helpers/ # Utility functions
│ ├── hooks/ # Custom React hooks
│ ├── layouts/ # Layout components
│ └── pages/ # Page components
├── server/ # Server-side code
│ ├── db/ # Database connection pool
│ ├── handlers/ # HTTP request handlers
│ ├── services/ # Business logic + transactions
│ ├── repositories/ # Data access layer (SQL)
│ └── utils/ # Utilities (auth, error, email)
└── shared/ # Shared types
├── entities/ # Database entity interfaces
├── enums/ # Application enums
├── request/ # API request types
├── response/ # API response types
└── rbac/ # RBAC configuration
migrations/ # SQL migration files (11 migrations)
docs/ # Documentation
- Node.js 18+ and pnpm
- PostgreSQL 14+
- sql-migrate (for running migrations)
- Clone the repository
git clone <repository-url>
cd kamil-boilerplate- Install dependencies
pnpm install- Setup environment variables
cp .env.example .envEdit .env and configure:
- Database credentials (DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD)
- JWT_SECRET (use a strong random string)
- Email configuration (if using email features)
- Setup database
Create the PostgreSQL database:
createdb kamil_boilerplateInstall sql-migrate:
go install github.com/rubenv/sql-migrate/...@latest
# or
brew install sql-migrateCreate dbconfig.yml in project root:
development:
dialect: postgres
datasource: postgres://DB_USER:DB_PASSWORD@DB_HOST:DB_PORT/DB_NAME?sslmode=disable
dir: migrations
table: migrationsRun migrations:
sql-migrate up- Run the development server
pnpm devOpen http://localhost:3000 with your browser.
These routes are accessible without authentication:
POST /api/auth/login- Login with email/passwordPOST /api/auth/register- Register new userPOST /api/auth/forgot-password- Request password resetPOST /api/auth/reset-password- Reset password with tokenPOST /api/auth/activate- Activate account with token
All endpoints below require Authorization: Bearer <token> header or auth_token cookie.
Users
GET /api/users- List users (paginated, searchable, filterable by role)GET /api/users/{id}- Get user by IDPOST /api/users- Create userPUT /api/users/{id}- Update userDELETE /api/users/{id}- Soft delete user
Customers
GET /api/customers- List customers (paginated, searchable)GET /api/customers/{id}- Get customer by IDPOST /api/customers- Create customerPUT /api/customers/{id}- Update customerDELETE /api/customers/{id}- Soft delete customer
Products
GET /api/products- List products (paginated, searchable, filterable by type)GET /api/products/{id}- Get product by IDPOST /api/products- Create productPUT /api/products/{id}- Update productDELETE /api/products/{id}- Soft delete product
Taxes
GET /api/taxes- List taxes (paginated, searchable)GET /api/taxes/{id}- Get tax by IDPOST /api/taxes- Create taxPUT /api/taxes/{id}- Update taxDELETE /api/taxes/{id}- Soft delete tax
Unit Quantities
GET /api/unit-quantities- List unit quantities (paginated, searchable)GET /api/unit-quantities/{id}- Get unit quantity by IDPOST /api/unit-quantities- Create unit quantityPUT /api/unit-quantities/{id}- Update unit quantityDELETE /api/unit-quantities/{id}- Soft delete unit quantity
Inventory
GET /api/inventory-histories- List inventory history (filterable by product, date)GET /api/inventory-histories/{id}- Get inventory history by IDPOST /api/inventory-histories- Manipulate inventory (add/remove stock)GET /api/inventory-histories/summary- Get inventory summary
Transactions
GET /api/transactions- List transactions (filterable by type, status, customer, date)GET /api/transactions/{id}- Get transaction by IDPOST /api/transactions- Create transaction (with items, discounts, taxes)GET /api/transactions/summary- Get transaction summary with analyticsGET /api/transactions/product-summary- Get product-specific transaction analytics
Payments
GET /api/payments- List payments (filterable by type, transaction, date)GET /api/payments/{id}- Get payment by IDPOST /api/payments- Create payment (auto-updates transaction status)
Full access to all features
All permissions except user management
- Products: Full CRUD
- Inventory: Full CRUD + summary
- Transactions: Read only
- Unit Quantities: Full CRUD
- Customers: Full CRUD
- Transactions: Create + Read
- Payments: Create + Read
- Products: Read only
- Taxes: Read only
- Transactions: Read + summary
- Payments: Full CRUD
- Taxes: Full CRUD
- Customers: Read only
- Inventory: Read + summary
-
Handlers (
src/server/handlers/)- Parse HTTP requests
- Call service methods
- Format responses
- NO business logic
-
Services (
src/server/services/)- Business logic
- Transaction management (BEGIN/COMMIT/ROLLBACK)
- Validation
- Call repository methods
-
Repositories (
src/server/repositories/)- SQL queries only
- Accept PoolClient for transactions
- Return raw data
Every service method follows:
const client = await getDbClient();
try {
await client.query('BEGIN');
// Business logic + repository calls
await client.query('COMMIT');
return result;
} catch (error) {
await client.query('ROLLBACK');
throw error;
} finally {
client.release();
}Run development server:
pnpm devBuild for production:
pnpm buildStart production server:
pnpm startLint code:
pnpm lintCreate new migration:
sql-migrate new <migration_name>Run migrations:
sql-migrate upRollback migration:
sql-migrate downCheck migration status:
sql-migrate statusSee .env.example for all required variables:
DB_*: Database connection settingsJWT_SECRET: Secret key for JWT tokensJWT_EXPIRES_IN: Token expiration timeFRONTEND_URL: Frontend URL for email linksEMAIL_*: Email server configuration
See docs/ folder for detailed documentation:
CLIENT.md- Client-side implementation guide (components, pages, hooks, helpers)SERVER.md- Server-side architecture (3-layer pattern, handlers, services, repositories)SHARED.md- Shared types and interfaces (entities, enums, request/response types)RBAC.md- Role-based access control (permissions, roles, Protected component)TECH.md- Technical specifications (architecture rules, patterns, conventions)STEP-BY-STEP-GUIDE.md- Development guide (step-by-step instructions)SMTP_CONFIGURATION.md- Email configuration guide
MIT