{"id":19056323,"url":"https://github.com/chanmeng666/agrihire-solutions","last_synced_at":"2026-05-09T06:03:08.828Z","repository":{"id":260836183,"uuid":"814965614","full_name":"ChanMeng666/agrihire-solutions","owner":"ChanMeng666","description":"Modern agricultural equipment hire management system built with Next.js 16, Neon PostgreSQL, Drizzle ORM, Better Auth, and shadcn/ui. Features multi-store operations, tiered pricing, role-based dashboards, and real-time analytics.","archived":false,"fork":false,"pushed_at":"2026-03-21T12:25:52.000Z","size":10341,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-22T02:57:59.751Z","etag":null,"topics":["agriculture","better-auth","drizzle-orm","equipment-rental","fullstack","heroku","neon-database","nextjs","postgresql","react","recharts","server-components","shadcn-ui","tailwindcss","typescript"],"latest_commit_sha":null,"homepage":"https://agrihireaq.pythonanywhere.com/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChanMeng666.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"chanmeng66u","thanks_dev":null,"custom":null}},"created_at":"2024-06-14T04:28:52.000Z","updated_at":"2026-03-21T12:25:55.000Z","dependencies_parsed_at":"2025-06-28T03:33:55.327Z","dependency_job_id":null,"html_url":"https://github.com/ChanMeng666/agrihire-solutions","commit_stats":null,"previous_names":["chanmeng666/agrihire-solutions"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ChanMeng666/agrihire-solutions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMeng666%2Fagrihire-solutions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMeng666%2Fagrihire-solutions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMeng666%2Fagrihire-solutions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMeng666%2Fagrihire-solutions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChanMeng666","download_url":"https://codeload.github.com/ChanMeng666/agrihire-solutions/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMeng666%2Fagrihire-solutions/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32809147,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"online","status_checked_at":"2026-05-09T02:00:06.633Z","response_time":123,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["agriculture","better-auth","drizzle-orm","equipment-rental","fullstack","heroku","neon-database","nextjs","postgresql","react","recharts","server-components","shadcn-ui","tailwindcss","typescript"],"created_at":"2024-11-08T23:49:05.129Z","updated_at":"2026-05-09T06:03:08.821Z","avatar_url":"https://github.com/ChanMeng666.png","language":"TypeScript","funding_links":["https://buymeacoffee.com/chanmeng66u"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# AgriHire Solutions\n\n### Modern Agricultural Equipment Hire Management System\n\nA full-stack equipment rental platform for New Zealand agricultural businesses, built with Next.js 16, Neon PostgreSQL, Better Auth, and shadcn/ui. Features multi-store operations, tiered pricing, role-based access control, and real-time analytics dashboards.\n\nDeployed on Cloudflare Workers via the [OpenNext](https://opennext.js.org/) adapter.\n\n[![Live Demo](https://img.shields.io/badge/Live_Demo-agrihire.chanmeng.org-F38020?style=for-the-badge\u0026logo=cloudflare\u0026logoColor=white)](https://agrihire.chanmeng.org)\n\n![Next.js](https://img.shields.io/badge/Next.js-16-black?style=flat-square\u0026logo=next.js)\n![React](https://img.shields.io/badge/React-19-61DAFB?style=flat-square\u0026logo=react)\n![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?style=flat-square\u0026logo=typescript)\n![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-4-06B6D4?style=flat-square\u0026logo=tailwindcss)\n![PostgreSQL](https://img.shields.io/badge/Neon_PostgreSQL-17-4169E1?style=flat-square\u0026logo=postgresql)\n![Drizzle](https://img.shields.io/badge/Drizzle_ORM-0.45-C5F74F?style=flat-square)\n![Better Auth](https://img.shields.io/badge/Better_Auth-1.5-000?style=flat-square)\n![Cloudflare Workers](https://img.shields.io/badge/Cloudflare_Workers-F38020?style=flat-square\u0026logo=cloudflare\u0026logoColor=white)\n\n\u003c/div\u003e\n\n---\n\n## Architecture\n\n```mermaid\ngraph TB\n    subgraph \"Client\"\n        Browser[\"Browser\"]\n    end\n\n    subgraph \"Cloudflare Edge Network\"\n        CDN[\"Cloudflare CDN\u003cbr/\u003e(Static Assets)\"]\n        Worker[\"Cloudflare Worker\u003cbr/\u003e(Next.js via OpenNext)\"]\n        Middleware[\"Edge Middleware\u003cbr/\u003e(Auth \u0026 Route Protection)\"]\n    end\n\n    subgraph \"External Services\"\n        Neon[\"Neon PostgreSQL\u003cbr/\u003e(Serverless Database)\"]\n        Resend[\"Resend\u003cbr/\u003e(Transactional Email)\"]\n        UT[\"Uploadthing\u003cbr/\u003e(File Storage)\"]\n    end\n\n    Browser --\u003e|\"HTTPS\"| CDN\n    CDN --\u003e|\"Static files\u003cbr/\u003e(_next/static, images)\"| Browser\n    CDN --\u003e|\"Dynamic requests\"| Middleware\n    Middleware --\u003e|\"Authenticated\"| Worker\n    Middleware --\u003e|\"Unauthenticated\u003cbr/\u003e(protected routes)\"| Browser\n    Worker --\u003e|\"SQL over HTTP\"| Neon\n    Worker --\u003e|\"API calls\"| Resend\n    Worker --\u003e|\"API calls\"| UT\n```\n\n## Request Flow\n\n```mermaid\nsequenceDiagram\n    participant U as User Browser\n    participant CF as Cloudflare Edge\n    participant MW as Middleware\n    participant W as Worker (Next.js)\n    participant DB as Neon PostgreSQL\n\n    U-\u003e\u003eCF: GET /for-hire/tractors\n    CF-\u003e\u003eCF: Check static asset cache\n    alt Static asset (CSS, JS, images)\n        CF--\u003e\u003eU: Return cached asset\n    else Dynamic route\n        CF-\u003e\u003eMW: Forward to middleware\n        MW-\u003e\u003eMW: Check session cookie\n        alt Public route\n            MW-\u003e\u003eW: Pass through\n        else Protected route, no session\n            MW--\u003e\u003eU: 307 Redirect to /login\n        end\n        W-\u003e\u003eDB: Query via Neon HTTP\n        DB--\u003e\u003eW: Result rows\n        W-\u003e\u003eW: Server-render React (RSC)\n        W--\u003e\u003eU: HTML + RSC payload\n    end\n```\n\n---\n\n## Features\n\n### Public Storefront\n- **Equipment Browsing** — Browse by category, search, view detailed specs and tiered pricing\n- **Store Locator** — Find nearest stores with addresses and contact info\n- **Promotions** — Active discount codes with linked products\n- **News** — Store announcements and articles\n- **Contact** — Message submission to specific stores\n\n### Customer Portal\n- **Shopping Cart** — Add equipment with hire dates, apply promo codes, quantity management\n- **Booking System** — Review and submit bookings with store selection (transactional processing)\n- **My Bookings** — View booking history, item details, hire status, payment receipts\n- **Messages** — Two-way messaging with store staff\n- **Profile** — Update personal info, address, and change password\n\n### Staff Dashboard\n- **Analytics** — Revenue charts, category distribution, stats cards (Recharts)\n- **Booking Management** — View all bookings with customer details and hire records\n- **Checkout/Return** — Equipment check-out and return workflow with staff tracking\n- **Equipment Management** — Machine inventory with serial numbers, service records\n- **Product Management** — CRUD for products with 3-tier pricing\n- **Category Management** — Inline add/edit with status toggle\n- **Inventory Overview** — Stock summary by product (available/hired/inactive counts)\n- **Promotions** — Create and manage discount promotions with linked products\n- **News** — Publish and edit store articles\n- **Messages** — Reply to customer messages with notification tracking\n\n### Admin Panel\n- **Store Management** — Create stores with auto-generated operating hours\n- **Staff Management** — Create staff accounts with role assignment\n- **Customer Management** — View all customers with booking counts and status\n\n### Infrastructure\n- **Authentication** — Email/password with 5-role RBAC (customer, staff, lmgr, nmgr, admin)\n- **Dark Mode** — System-aware theme with manual toggle\n- **Responsive** — Mobile sidebar navigation for dashboard\n- **Loading States** — Skeleton UIs for all route groups\n- **Error Handling** — Custom 404, 500, and 403 pages\n- **Email** — Password reset and booking confirmation emails via Resend\n- **File Uploads** — Uploadthing integration for product/machine images\n\n---\n\n## Tech Stack\n\n| Layer | Technology |\n|-------|-----------|\n| **Framework** | [Next.js 16](https://nextjs.org/) (App Router, Server Components, Server Actions) |\n| **Language** | [TypeScript 5](https://www.typescriptlang.org/) |\n| **UI** | [shadcn/ui](https://ui.shadcn.com/) + [Tailwind CSS 4](https://tailwindcss.com/) |\n| **Database** | [Neon](https://neon.tech/) (Serverless PostgreSQL) |\n| **ORM** | [Drizzle ORM](https://orm.drizzle.team/) |\n| **Auth** | [Better Auth](https://better-auth.com/) |\n| **Charts** | [Recharts](https://recharts.org/) |\n| **Email** | [Resend](https://resend.com/) |\n| **Uploads** | [Uploadthing](https://uploadthing.com/) |\n| **Icons** | [Lucide React](https://lucide.dev/) |\n| **Deployment** | [Cloudflare Workers](https://workers.cloudflare.com/) via [@opennextjs/cloudflare](https://opennext.js.org/cloudflare) |\n\n---\n\n## Project Structure\n\n```\nsrc/\n├── app/\n│   ├── (auth)/              # Login, Register, Reset Password (4 pages)\n│   ├── (public)/            # Equipment, Stores, News, Promotions, Contact (9 pages)\n│   ├── (customer)/          # Cart, Bookings, Messages, Profile (6 pages)\n│   ├── (dashboard)/         # Staff dashboard \u0026 admin panel (26 pages)\n│   ├── api/                 # Auth, Cart count, Uploadthing routes\n│   ├── page.tsx             # Data-driven homepage\n│   ├── not-found.tsx        # 404 page\n│   └── error.tsx            # Error boundary\n├── components/\n│   ├── ui/                  # shadcn/ui components\n│   ├── layout/              # Header, Footer\n│   ├── dashboard/           # Sidebar, Mobile nav, Charts, Stats\n│   └── equipment/           # Hire form\n├── lib/                     # DB, Auth, Email, User context utilities\n├── middleware.ts             # Route protection \u0026 auth redirection\n└── server/\n    ├── actions/             # 8 server action modules\n    └── queries/             # 9 data query modules\n\ndrizzle/\n├── schema.ts               # 20 PostgreSQL table definitions\n├── relations.ts             # Entity relationships\n└── seed.ts                  # Sample data seeding script\n\n# Cloudflare Workers config\nwrangler.jsonc               # Worker name, compatibility flags, env vars\nopen-next.config.ts          # OpenNext adapter configuration\n```\n\n---\n\n## Database Schema\n\n```mermaid\nerDiagram\n    USER ||--o| CUSTOMER : \"has profile\"\n    USER ||--o| STAFF : \"has profile\"\n    STORE ||--|{ STORE_HOUR : \"has hours\"\n    STORE ||--|{ STAFF : \"employs\"\n    STORE ||--|{ BOOKING : \"receives\"\n    CUSTOMER ||--|{ BOOKING : \"makes\"\n    CUSTOMER ||--o| CART : \"owns\"\n    CART ||--|{ CART_ITEM : \"contains\"\n    BOOKING ||--|{ BOOKING_ITEM : \"includes\"\n    BOOKING ||--o| PAYMENT : \"has\"\n    BOOKING_ITEM ||--o| HIRE_RECORD : \"tracked by\"\n    CATEGORY ||--|{ PRODUCT : \"categorizes\"\n    PRODUCT ||--|{ MACHINE : \"has units\"\n    PRODUCT ||--|{ CART_ITEM : \"added to\"\n    PRODUCT ||--|{ BOOKING_ITEM : \"booked as\"\n    PROMOTION ||--|{ PROMO_PRODUCT : \"links\"\n    PRODUCT ||--|{ PROMO_PRODUCT : \"discounted by\"\n    STORE ||--|{ MESSAGE : \"receives\"\n    CUSTOMER ||--|{ MESSAGE : \"sends\"\n```\n\n20 tables organized into domains:\n\n| Domain | Tables |\n|--------|--------|\n| **Auth \u0026 Users** | `user`, `customer`, `staff`, `reset_tokens` |\n| **Stores** | `store`, `store_hour` |\n| **Catalog** | `category`, `product`, `machine`, `service` |\n| **Bookings** | `booking`, `booking_item`, `hire_record`, `payment` |\n| **Cart** | `cart`, `cart_item` |\n| **Promotions** | `promotion`, `promo_product` |\n| **Communication** | `message`, `notifications`, `news` |\n| **System** | `setting` |\n\n---\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js \u003e= 18\n- A [Neon](https://neon.tech/) database\n- (Optional) [Resend](https://resend.com/) API key for emails\n- (Optional) [Uploadthing](https://uploadthing.com/) token for file uploads\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/ChanMeng666/agrihire-solutions.git\ncd agrihire-solutions\n\n# Install dependencies\nnpm install\n\n# Copy environment variables\ncp .env.example .env.local\n# Edit .env.local with your Neon DATABASE_URL and other values\n\n# Push database schema to Neon\nnpm run db:push\n\n# Seed sample data\nnpm run db:seed\n\n# Start development server\nnpm run dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000) to view the app.\n\n### Available Scripts\n\n| Command | Description |\n|---------|-------------|\n| `npm run dev` | Start Next.js development server |\n| `npm run build` | Build Next.js for production (webpack) |\n| `npm run build:worker` | Build Cloudflare Worker via OpenNext |\n| `npm run start` | Start local production server |\n| `npm run preview` | Preview Worker build locally (Wrangler dev) |\n| `npm run deploy` | Deploy to Cloudflare Workers |\n| `npm run lint` | Run ESLint |\n| `npm run db:push` | Push Drizzle schema to database |\n| `npm run db:generate` | Generate migration files |\n| `npm run db:seed` | Seed database with sample data |\n| `npm run db:studio` | Open Drizzle Studio |\n\n---\n\n## Deployment\n\nThe application is deployed on **Cloudflare Workers** using the `@opennextjs/cloudflare` adapter, which converts the Next.js output into a Worker-compatible bundle.\n\n```mermaid\ngraph LR\n    A[\"next build\u003cbr/\u003e(webpack)\"] --\u003e B[\"opennextjs-cloudflare\u003cbr/\u003ebuild\"]\n    B --\u003e C[\".open-next/\u003cbr/\u003eworker.js + assets/\"]\n    C --\u003e D[\"wrangler deploy\"]\n    D --\u003e E[\"Cloudflare Workers\u003cbr/\u003eEdge Network\"]\n\n    style A fill:#000,color:#fff\n    style B fill:#F38020,color:#fff\n    style E fill:#F38020,color:#fff\n```\n\n### Deploy to Cloudflare Workers\n\n```bash\n# 1. Install dependencies\nnpm install\n\n# 2. Set secrets (one-time)\nnpx wrangler secret put DATABASE_URL\nnpx wrangler secret put BETTER_AUTH_SECRET\nnpx wrangler secret put RESEND_API_KEY\nnpx wrangler secret put UPLOADTHING_TOKEN\n\n# 3. Update wrangler.jsonc with your account_id and domain URLs\n\n# 4. Build \u0026 deploy\nNEXT_PUBLIC_APP_URL=https://your-domain.com npm run build:worker\nnpm run deploy\n```\n\n### Key Configuration Files\n\n| File | Purpose |\n|------|---------|\n| `wrangler.jsonc` | Cloudflare Worker config (name, account, compatibility flags, env vars) |\n| `open-next.config.ts` | OpenNext adapter configuration |\n| `next.config.ts` | Next.js framework configuration |\n| `drizzle.config.ts` | Drizzle ORM database configuration |\n\n### Environment Variables\n\n| Variable | Type | Description |\n|----------|------|-------------|\n| `DATABASE_URL` | Secret | Neon PostgreSQL connection string |\n| `BETTER_AUTH_SECRET` | Secret | Auth encryption key (min 32 chars) |\n| `RESEND_API_KEY` | Secret | Resend email service API key |\n| `UPLOADTHING_TOKEN` | Secret | Uploadthing file upload token |\n| `BETTER_AUTH_URL` | Var | Production URL (e.g. `https://agrihire.chanmeng.org`) |\n| `NEXT_PUBLIC_APP_URL` | Var | Public app URL (baked at build time) |\n\n### Important Notes\n\n- The build uses `--webpack` flag (not Turbopack) for Cloudflare Workers compatibility\n- `nodejs_compat` compatibility flag is enabled in `wrangler.jsonc` for Node.js `crypto` module support\n- `NEXT_PUBLIC_APP_URL` must be set as an environment variable during `npm run build:worker` since Next.js inlines it at build time\n\n---\n\n## Sample Accounts\n\nAfter running `npm run db:seed`, these accounts are available:\n\n| Role | Email | Notes |\n|------|-------|-------|\n| Customer | cust1@email.com | Auckland store |\n| Customer | cust2@email.com | Christchurch store |\n| Staff | staff1@agrihire.nz | Auckland store |\n| Local Manager | lmanager1@agrihire.nz | Auckland store |\n| Network Manager | nmanager1@agrihire.nz | All stores |\n| Admin | admin1@agrihire.nz | Full access |\n\n\u003e **Note:** These seed accounts use bcrypt-hashed passwords from the original system. For new accounts, use the registration form.\n\n---\n\n## License\n\nThis project is for educational and demonstration purposes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanmeng666%2Fagrihire-solutions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchanmeng666%2Fagrihire-solutions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanmeng666%2Fagrihire-solutions/lists"}