Appearance
Naluri Internal Admin Ecosystem
Dokumentasi untuk tiga project yang membentuk admin panel Naluri.
Source Code References
Untuk Claude: Gunakan path ini untuk akses langsung ke source code.
| Project | Repository Path |
|---|---|
| naluri-admin | /Users/joko/Documents/projects/naluri-admin |
| admin-api | /Users/joko/Documents/projects/admin-api |
| entitlement-service | /Users/joko/Documents/projects/entitlement-service |
Key entry points:
naluri-admin/src/modules/coupon/- Coupon module frontendadmin-api/src/coupons/- Coupon module backendadmin-api/src/focus-dashboard/- Focus Dashboard proxyentitlement-service/src/analytics/- Analytics & Focus Dashboard service
Table of Contents
Architecture Overview
┌──────────────────────────────────────────────────────────────────────┐
│ FRONTEND │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ naluri-admin │ │
│ │ React 18 + TypeScript + Vite + TailwindCSS │ │
│ │ React Query + React Router + React Hook Form │ │
│ └────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
│
│ HTTP REST API
▼
┌──────────────────────────────────────────────────────────────────────┐
│ BACKEND │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ admin-api │ │
│ │ NestJS 9 + TypeORM + PostgreSQL │ │
│ │ JWT Auth + RBAC + Audit Logging │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │ │ │
│ Direct DB │ │ HTTP Proxy │
│ Access │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────┐ ┌─────────────────────────────────┐ │
│ │ Naluri Core DB │ │ entitlement-service │ │
│ │ (PostgreSQL) │ │ NestJS 11 + Prisma + PostgreSQL│ │
│ │ - coupons │ │ - subscriptions │ │
│ │ - coupon_codes │ │ - features │ │
│ │ - users │ │ - permissions │ │
│ │ - plans │ │ - analytics │ │
│ └─────────────────────────┘ └─────────────────────────────────┘ │
│ │ │
│ │ Read-only │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ Naluri Core DB (read) │ │
│ │ - users (for validation) │ │
│ └─────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘Projects
| Project | Tech Stack | Port | Purpose |
|---|---|---|---|
| naluri-admin | React, TypeScript, Vite | 5173 | Admin panel frontend |
| admin-api | NestJS, TypeORM | 3000 | Backend API gateway |
| entitlement-service | NestJS, Prisma | 3001 | Feature access & subscriptions |
Data Flow
Coupon Management Flow
User clicks coupon in naluri-admin
│
▼
GET /coupon/show/{couponId} ───▶ admin-api
│ │
│ │ TypeORM query
│ ▼
│ Naluri Core DB
│ (coupons table)
│ │
◀──────────────────────────────┘Focus Dashboard Flow
User opens Focus Dashboard tab
│
▼
GET /focus-dashboard/details/{sponsorCodeId}
│
▼
admin-api (proxy)
│
▼
GET /analytics/focus-dashboard/{sponsorCodeId}
│
▼
entitlement-service
│
├───▶ Local DB (access records)
│
└───▶ Naluri Core DB (coupon & user data)Database Connections
admin-api
| Connection | Database | Purpose |
|---|---|---|
NALURI_DB | Naluri Core | Coupons, plans, users, subscriptions |
entitlement-service
| Connection | Database | Purpose |
|---|---|---|
DATABASE_URL | Internal Entitlement | Subscriptions, features, permissions, analytics |
CORE_DATABASE_URL | Naluri Core (read-only) | User validation, coupon lookup |
Key Concepts
Coupon vs Coupon Code
┌─────────────────────────────────────────────────────────────┐
│ COUPON (coupons table) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ id: "uuid-123" ◀── sponsorCodeId │ │
│ │ code: "ACME2024" ◀── sponsorCode (string) │ │
│ │ sponsor: "ACME Corp" │ │
│ │ plan_id: "uuid-plan" │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ │ has many │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ COUPON CODES (coupon_codes table) │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ id: "uuid-cc1" │ │ id: "uuid-cc2" │ ◀── couponCodeId │
│ │ │ name: "acme-1" │ │ name: "acme-2" │ │ │
│ │ └─────────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘Environment Variables
| Service | Variable | Purpose |
|---|---|---|
| admin-api | INTERNAL_ENTITLEMENT_HOST | URL to entitlement-service |
| admin-api | ENTITLEMENT_HOST | Alternative entitlement URL |
| entitlement-service | DATABASE_URL | Internal database |
| entitlement-service | CORE_DATABASE_URL | Naluri Core database |
Common Patterns
API Pattern (admin-api)
typescript
// admin-api acts as proxy to entitlement-service
@Injectable()
export class FocusDashboardService {
constructor(private readonly httpService: HttpService) {}
async getDetails(sponsorCodeId: string) {
// Forward request to entitlement-service
return this.httpService.get(`/analytics/focus-dashboard/${sponsorCodeId}`);
}
}Query Pattern (naluri-admin)
typescript
// React Query for data fetching
export const useFocusDashboardDetails = (sponsorCodeId: string) => {
return useQuery({
queryKey: ['focus-dashboard', sponsorCodeId],
queryFn: () => api.get(`/focus-dashboard/details/${sponsorCodeId}`),
});
};Dual Database Pattern (entitlement-service)
typescript
// Two separate Prisma clients
@Injectable()
export class AnalyticsService {
constructor(
private readonly db: DatabaseService, // Internal DB
private readonly naluriDb: NaluriDatabaseService, // Naluri Core DB
) {}
async getDetails(couponId: string) {
// Read from internal DB
const access = await this.db.focusDashboardAccess.findMany({ ... });
// Enrich with Naluri Core data
const coupon = await this.naluriDb.coupons.findUnique({ ... });
return { ...access, coupon };
}
}Project Documentation
Last updated: March 2026