Technical Architecture
Technical documentation covering the monorepo structure, packages, and deployment.
Technical Architecture
The Greenacres Coffee Platform is built as a modern TypeScript monorepo using TurboRepo and pnpm.
Monorepo Structure
coffee/
├── apps/
│ ├── web/ # Public site + Buyer Portal (Next.js)
│ ├── admin/ # Admin Dashboard (Next.js)
│ └── docs/ # Documentation (Fumadocs)
├── packages/
│ ├── ui/ # Shared UI components (Tailwind + Shadcn)
│ ├── auth/ # Authentication logic (Firebase)
│ ├── db/ # Database schemas and utilities
│ ├── types/ # Shared TypeScript types
│ └── config/ # Shared ESLint/TS configs
└── turbo.json # TurboRepo configurationApps
Web (apps/web)
The public-facing Next.js application containing:
- Marketing Pages: Homepage, About, Contact
- Buyer Portal: Catalog, Coffee Details, Inquiries, Profile
Port: 3000
Admin (apps/admin)
Internal administration dashboard:
- Dashboard: Metrics and overview
- Products: Coffee CRUD operations
- Inquiries: Request management
- Users: Role and access management
Port: 3001
Packages
UI (packages/ui)
Shared component library built with:
- Tailwind CSS: Utility-first styling
- Shadcn/ui: Accessible component primitives
- Lucide Icons: Icon library
Key components: Button, Card, Input, Modal, Table
Auth (packages/auth)
Firebase Authentication wrapper providing:
useAuth()hook for client componentssignIn(),signUp(),signOut()methods- Role-based access control
- Session persistence
DB (packages/db)
Firestore data access layer:
- Collections: users, coffees, inquiries, locations
- Functions: getCoffees, createInquiry, updateUserRole
- Email: Mailtrap integration for transactional emails
Types (packages/types)
Shared TypeScript interfaces:
interface CoffeePricing {
pricePerLb: number;
quantity?: number;
availability: 'in_stock' | 'pre_shipment' | 'out_of_stock';
availabilityPeriod?: string;
terms: string; // e.g., 'FOB' or 'EXW'
incoterm?: string; // e.g., 'FOB', 'EXW', 'CIF', 'DAP'
logisticsLocation?: string; // e.g., 'Djibouti', 'Genoa'
paymentTerms?: string;
updatedAt: Date;
}
interface Coffee {
id: string;
name: string;
region: string;
grade: number;
// ...
referenceCode?: string;
isTopLot?: boolean;
images?: string[];
videos?: string[];
pricing?: Record<'addisAbaba' | 'trieste' | 'genoa', CoffeePricing>;
}
interface Inquiry {
id: string;
userId: string;
coffeeId: string;
status: 'pending' | 'reviewed' | 'quoted' | 'completed';
// ...
}Data Mapping Strategy (Offer List)
The platform bridges the gap between conventional offline PDF offer lists and a digital catalog. Based on the client's PDF format, data maps to the Coffee model as follows:
| Offer List Field | Firestore Field | Notes |
|---|---|---|
| Coffee Name / Description | name, region, grade, preparation | Parsed to create a standardized name. |
| Ref No. | referenceCode | Internal tracking ID (e.g., ET-YG-W1-24). |
| Bag Size & Quantity | pricing.*.quantity (in bags) | Total bags available at a specific location. |
| Availability (Date/Status) | pricing.*.availabilityPeriod & availability | e.g., "Jan/Feb 2026" or "In Stock". |
| Incoterm & Location | pricing.*.incoterm & logisticsLocation | Defines the specific delivery terms per location (e.g., FOB & Djibouti). |
| Payment Terms | pricing.*.paymentTerms | Typically LC/CAD or similar. |
| Price / kg (or lb) | pricing.*.pricePerLb | Base unit price for calculations. |
Note: The isTopLot boolean is generally derived manually or based on specific grade/SCA score thresholds.
Database
Firebase Firestore is used as the primary database.
Collections
| Collection | Description |
|---|---|
users | User profiles and roles |
coffees | Coffee product catalog |
inquiries | Sample requests from buyers |
locations | Delivery location pricing |
emailQueue | Outbound email queue |
Security Rules
Located in firestore.rules:
- Users can only read/write their own data
- Admins have full access
- Public read access for coffee catalog
Deployment
Vercel
The platform is designed for Vercel deployment:
# Deploy all apps
vercel deploy
# Deploy specific app
vercel deploy --cwd apps/webEnvironment Variables
Required environment variables (see .env.production.example):
NEXT_PUBLIC_FIREBASE_API_KEY=...
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=...
NEXT_PUBLIC_FIREBASE_PROJECT_ID=...
FIREBASE_ADMIN_CLIENT_EMAIL=...
FIREBASE_ADMIN_PRIVATE_KEY=...
MAILTRAP_TOKEN=...Testing
Vitest
Unit and integration tests using Vitest:
# Run all tests
pnpm test
# Run tests for specific package
pnpm --filter @greenacres/db testLinting
ESLint configuration shared via packages/config:
# Lint all packages
pnpm lint
# Type check
pnpm typecheck