Full-stack ERP web application for internal manufacturing operations.
- Next.js 14 App Router + TypeScript
- Tailwind CSS (industrial dark blue theme)
- Prisma ORM + PostgreSQL
- NextAuth Credentials (email/password)
- UploadThing for tender PDF uploads
- Role-based dashboards + route protection
- Activity logging for create/update/delete actions
abiding-erp/
├── app/
│ ├── (auth)/login/page.tsx
│ ├── activity-logs/page.tsx
│ ├── api/
│ │ ├── auth/[...nextauth]/route.ts
│ │ ├── logs/route.ts
│ │ ├── orders/route.ts
│ │ ├── payments/route.ts
│ │ ├── products/route.ts
│ │ ├── tenders/[id]/status/route.ts
│ │ ├── tenders/route.ts
│ │ ├── uploadthing/{core.ts,route.ts}
│ │ └── users/{route.ts,[id]/reset-password/route.ts}
│ ├── dashboard/page.tsx
│ ├── products/page.tsx
│ ├── tenders/page.tsx
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
├── components/sidebar.tsx
├── lib/
│ ├── activity-logger.ts
│ ├── auth.ts
│ ├── prisma.ts
│ ├── rbac.ts
│ └── route-auth.ts
├── prisma/{schema.prisma,seed.ts}
├── middleware.ts
└── .env.example
- Owner
- Sales
- Manufacturing
- TenderExecutive
- Logistics
- Quality
- Accounts
- Install dependencies:
npm install
- Copy env:
cp .env.example .env
- Run PostgreSQL and update
DATABASE_URL. - Generate Prisma client and migrate:
npm run prisma:generate npm run prisma:migrate -- --name init
- Seed Owner user:
npm run prisma:seed
- Start dev server:
npm run dev
Default owner login after seed:
- Email:
owner@abiding.local - Password:
owner1234
- Push repository to Git provider.
- Import project into Vercel.
- Set environment variables:
DATABASE_URLNEXTAUTH_SECRETNEXTAUTH_URLUPLOADTHING_SECRETUPLOADTHING_APP_ID
- Add a managed PostgreSQL (Vercel Postgres/Neon/Supabase).
- Set build command:
npm run prisma:generate && npm run build - Run migrations from CI/CD or one-off release phase:
npx prisma migrate deploy
- API routes enforce role checks server-side.
- Activity logs are owner-only in both middleware and API.
- Product total cost is calculated server-side from subparts.
- Tender status transitions are role-restricted.