Menyelesaikan object user dan init base

This commit is contained in:
Mr. Rayyan
2026-07-30 22:47:18 +07:00
parent 3efac50f39
commit fdbfb34842
128 changed files with 6785 additions and 3156 deletions
+10
View File
@@ -0,0 +1,10 @@
APP_ENV=development #development / test / prod
PORT=3069
DATABASE_URL=postgresql://USERNAME:PASSWORD@HOST:5432/DATABASE?schema=public
JWT_SECRET=GANTI_DENGAN_SECRET
JWT_REFRESH_SECRET=GANTI_DENGAN_REFRESH_SECRET
SWAGGER_ENABLED=true
LOG_LEVEL=debug
+3
View File
@@ -1 +1,4 @@
node_modules
RayLab-Core.zip
RayLab-Core.rar
.env
-208
View File
@@ -1,208 +0,0 @@
# RayLab Core Phase 1 --- Module Design
## Tujuan
Fase 1 mendefinisikan pembagian modul pada RayLab Core. Setiap modul
memiliki tanggung jawab yang jelas (Single Responsibility Principle),
mudah dikembangkan secara independen, dan berkomunikasi melalui service
atau interface yang telah ditentukan.
------------------------------------------------------------------------
# Prinsip Desain
- Modular dan mudah dikembangkan.
- Loose coupling, high cohesion.
- Setiap modul memiliki domain bisnis yang jelas.
- Antar modul tidak mengakses database modul lain secara langsung.
- Komunikasi dilakukan melalui service, interface, atau event jika
diperlukan.
------------------------------------------------------------------------
# Daftar Modul
## 1. Core System
Tanggung jawab:
- Bootstrap aplikasi
- Dependency Injection
- Configuration
- Logging
- Health Check
- Global Middleware
- Exception Filter
------------------------------------------------------------------------
## 2. Identity
Mengelola identitas pengguna.
Fitur:
- User
- Profile
- Session
- Authentication (implementasi pada fase berikutnya)
------------------------------------------------------------------------
## 3. Authorization
Mengelola hak akses.
Fitur:
- Group
- Role
- Permission
- Domain Access
- Resource Access
- Special Access
Hierarki:
``` text
User
Group
Role
Permission
Domain Access
Resource Access
Special Access
```
------------------------------------------------------------------------
## 4. Registry
Pusat registrasi aplikasi dan layanan.
Mengelola:
- Application
- Service
- Domain
- Adapter
------------------------------------------------------------------------
## 5. Configuration
Menyimpan konfigurasi yang dapat diubah saat runtime.
Contoh:
- Theme
- Timezone
- Upload Limit
- Default Language
------------------------------------------------------------------------
## 6. Dashboard
Menyediakan data untuk dashboard RayLab.
Dashboard tidak menyimpan business logic, hanya menggabungkan data dari
modul lain.
------------------------------------------------------------------------
## 7. Health
Monitoring internal.
Contoh:
- Database
- Redis
- Storage
- Adapter
- Service Status
------------------------------------------------------------------------
## 8. Adapter
Lapisan integrasi layanan eksternal.
Contoh adapter:
- Nextcloud
- Jellyfin
- Immich
- Minecraft
- Future integrations
Semua komunikasi eksternal harus melalui Adapter.
------------------------------------------------------------------------
## 9. Storage
Mengelola storage logis.
Contoh:
- Storage
- Volume
- Quota
- Path Mapping
------------------------------------------------------------------------
## 10. Media
Media Manager berada di RayLab Core.
Tanggung jawab:
- Membuat struktur folder otomatis
- Mengelola folder private/shared
- Memindahkan media saat perubahan visibilitas
- Mengubah permission
- Memicu refresh library Jellyfin
- Audit media
Jellyfin hanya membaca media, bukan mengelolanya.
------------------------------------------------------------------------
## 11. Audit
Mencatat seluruh aktivitas penting sistem.
Contoh:
- Login
- Perubahan permission
- Pembuatan user
- Penghapusan group
- Perubahan konfigurasi
- Aktivitas adapter
------------------------------------------------------------------------
# Aturan Antar Modul
- Tidak ada modul yang mengakses repository modul lain secara
langsung.
- Semua business logic berada pada modul pemilik domain.
- Integrasi dilakukan melalui service atau adapter.
- Setiap modul harus dapat diuji secara mandiri.
------------------------------------------------------------------------
# Hasil Akhir Fase 1
Setelah fase ini selesai, RayLab Core memiliki struktur modular yang
menjadi fondasi untuk seluruh pengembangan berikutnya.
-218
View File
@@ -1,218 +0,0 @@
# RayLab Core Phase 2 --- Domain Model
## Tujuan
Fase 2 mendefinisikan domain bisnis yang dimiliki RayLab Core beserta
hubungan antar domain. Domain model menjadi dasar implementasi entity,
service, API, dan database.
------------------------------------------------------------------------
# Prinsip Domain
- Domain mewakili konsep bisnis, bukan tabel database.
- Setiap domain memiliki tanggung jawab yang jelas.
- Domain saling berinteraksi melalui service, bukan akses langsung ke
data domain lain.
- Seluruh aturan bisnis berada pada domain terkait.
------------------------------------------------------------------------
# Domain Utama
## Identity
Mengelola identitas pengguna.
### Entity
- User
- Profile
- Session
### Tanggung Jawab
- Identitas pengguna
- Informasi profil
- Status sesi
------------------------------------------------------------------------
## Authorization
Mengelola hak akses sistem.
### Entity
- Group
- Role
- Permission
- Domain Access
- Resource Access
- Special Access
### Model IAM
``` text
User
Group
Role
Permission
Domain Access
Resource Access
Special Access
```
### Penjelasan
**Group** adalah identitas organisasi utama.
**Role** merupakan kumpulan tanggung jawab.
**Permission** mendefinisikan aksi yang diizinkan.
**Domain Access** menentukan aplikasi atau domain yang dapat diakses.
**Resource Access** menentukan objek di dalam aplikasi yang boleh
digunakan.
**Special Access** merupakan override khusus untuk user tertentu tanpa
mengubah group atau role.
------------------------------------------------------------------------
## Registry
Entity:
- Application
- Service
- Domain
- Adapter
Berfungsi sebagai katalog seluruh layanan RayLab.
------------------------------------------------------------------------
## Configuration
Entity:
- Setting
- Setting Category
Digunakan untuk konfigurasi yang dapat diubah saat runtime.
------------------------------------------------------------------------
## Storage
Entity:
- Storage
- Volume
- Quota
Mengelola penyimpanan logis dan alokasi kapasitas.
------------------------------------------------------------------------
## Media
Entity:
- Library
- Folder Template
- Folder Mapping
- Folder Permission
Media Manager mengendalikan struktur media, sedangkan Jellyfin hanya
membaca media yang telah disiapkan.
------------------------------------------------------------------------
## Audit
Entity:
- Audit Log
- Audit Category
- Audit Target
Mencatat seluruh aktivitas penting sistem.
------------------------------------------------------------------------
## Health
Entity:
- Health Check
- Service Status
Digunakan untuk memantau kesehatan layanan internal.
------------------------------------------------------------------------
## System
Entity:
- Job
- Notification
Digunakan untuk proses internal seperti background job dan notifikasi.
------------------------------------------------------------------------
# Relasi Antar Domain
``` text
Identity
└── Authorization
Authorization
├── Registry
├── Media
├── Storage
└── Dashboard
Registry
└── Adapter
Semua Domain
└── Audit
```
------------------------------------------------------------------------
# Aturan Domain
- Domain hanya memiliki satu tanggung jawab utama.
- Tidak ada duplikasi data antar domain.
- Setiap domain memiliki service sendiri.
- Entity hanya mewakili data dan aturan dasar domain.
- Komunikasi lintas domain dilakukan melalui service.
------------------------------------------------------------------------
# Hasil Akhir Fase 2
Pada akhir fase ini RayLab Core memiliki model domain yang menjadi acuan
untuk:
- Desain database
- Layered Architecture
- API
- Implementasi modul
- Pengembangan fitur di masa depan
-237
View File
@@ -1,237 +0,0 @@
# RayLab Core Phase 3 --- Layered Architecture
## Tujuan
Fase 3 menetapkan standar arsitektur kode RayLab Core agar seluruh modul
memiliki pola implementasi yang konsisten, mudah dipelihara, mudah
diuji, dan mudah dikembangkan.
------------------------------------------------------------------------
# Filosofi
Setiap request mengikuti alur yang sama:
``` text
HTTP Request
Controller
Application Service
Domain Service
Repository
Database
```
Setiap layer hanya boleh berinteraksi dengan layer yang berada tepat di
bawahnya.
------------------------------------------------------------------------
# Layer 1 --- Controller
Tanggung jawab:
- Menerima HTTP Request
- Validasi dasar
- Memanggil Application Service
- Mengembalikan HTTP Response
Tidak boleh:
- Mengakses database
- Menyimpan business logic
- Memanggil layanan eksternal secara langsung
------------------------------------------------------------------------
# Layer 2 --- Application Service
Application Service mengimplementasikan use case.
Contoh:
- Create User
- Update User
- Delete User
- Assign Group
- Grant Special Access
- Create Domain
Tanggung jawab:
- Mengatur alur bisnis
- Mengoordinasikan Domain Service, Repository, dan Adapter
- Menjalankan transaksi bila diperlukan
------------------------------------------------------------------------
# Layer 3 --- Domain Service
Seluruh aturan bisnis ditempatkan di layer ini.
Contoh:
- Owner tidak boleh dihapus
- Group default tidak boleh dihapus
- Validasi Domain Access
- Validasi Permission
- Validasi Resource Access
Business rule tidak boleh berada di Controller.
------------------------------------------------------------------------
# Layer 4 --- Repository
Repository bertanggung jawab terhadap akses data.
Fungsi utama:
- Save
- Find
- Update
- Delete
- Query
Repository tidak mengetahui HTTP maupun business logic.
------------------------------------------------------------------------
# Layer 5 --- Database
Menggunakan PostgreSQL dengan Prisma sebagai ORM.
Seluruh akses database dilakukan melalui Repository.
------------------------------------------------------------------------
# Adapter Layer
Integrasi dengan layanan eksternal dilakukan melalui Adapter.
Contoh:
- Nextcloud Adapter
- Jellyfin Adapter
- Immich Adapter
- Minecraft Adapter
Application Service tidak boleh memanggil API eksternal secara langsung.
------------------------------------------------------------------------
# Contoh Alur Create User
``` text
POST /users
UsersController
CreateUserService
├─────────────┐
▼ ▼
UserDomain GroupDomain
UserRepository
PostgreSQL
Media Adapter
Audit Service
HTTP Response
```
------------------------------------------------------------------------
# Dependency Rule
Layer Boleh Memanggil
--------------------- -------------------------------------
Controller Application Service
Application Service Domain Service, Repository, Adapter
Domain Service Entity
Repository Prisma
Adapter External API
Entity Tidak memanggil layer lain
Dependensi selalu mengarah ke bawah.
------------------------------------------------------------------------
# Struktur Folder
``` text
src/
├── modules/
│ ├── users/
│ │ ├── controllers/
│ │ ├── services/
│ │ ├── domain/
│ │ ├── repositories/
│ │ ├── dto/
│ │ ├── entities/
│ │ └── users.module.ts
│ │
│ ├── groups/
│ ├── authorization/
│ ├── registry/
│ ├── media/
│ ├── storage/
│ └── audit/
├── adapters/
│ ├── nextcloud/
│ ├── jellyfin/
│ ├── immich/
│ └── ...
├── common/
│ ├── auth/
│ ├── guards/
│ ├── filters/
│ ├── middleware/
│ ├── logger/
│ └── utils/
├── prisma/
└── main.ts
```
------------------------------------------------------------------------
# Aturan Implementasi
1. Business logic tidak boleh berada di Controller.
2. Frontend tidak boleh menyimpan business logic.
3. Integrasi eksternal wajib melalui Adapter.
4. Semua akses database melalui Repository.
5. Setiap modul harus dapat diuji secara mandiri.
6. Setiap layer memiliki satu tanggung jawab utama.
------------------------------------------------------------------------
# Hasil Akhir Fase 3
Setelah fase ini selesai, RayLab Core memiliki standar implementasi yang
konsisten untuk seluruh modul sehingga pengembangan jangka panjang
menjadi lebih mudah, terstruktur, dan mudah dipelihara.
-311
View File
@@ -1,311 +0,0 @@
# RayLab Core Phase 4 --- Technical Foundation
## Tujuan
Fase 4 menetapkan fondasi teknis RayLab Core. Dokumen ini mendefinisikan
teknologi, konvensi pengembangan, dan standar implementasi yang akan
digunakan secara konsisten pada seluruh modul.
------------------------------------------------------------------------
# Tujuan Akhir
Project dapat dijalankan dengan satu perintah:
``` bash
docker compose up -d
```
Kemudian endpoint health dapat diakses:
``` text
GET /health
```
Response:
``` json
{
"status": "ok"
}
```
------------------------------------------------------------------------
# Technology Stack
## Backend Framework
**NestJS**
Alasan:
- Modular architecture
- Dependency Injection
- Guard, Middleware, Interceptor
- Swagger integration
- Testing support
- Sangat cocok untuk aplikasi enterprise.
------------------------------------------------------------------------
## Programming Language
**TypeScript**
Keuntungan:
- Type safety
- Maintainability
- IDE support
- Konsisten dengan NestJS
------------------------------------------------------------------------
## Database
**PostgreSQL**
Digunakan sebagai database utama RayLab Core.
Semua data aplikasi disimpan di PostgreSQL.
------------------------------------------------------------------------
## ORM
**Prisma**
Keuntungan:
- Type-safe query
- Migration
- Schema management
- Autocomplete
- Maintainable
------------------------------------------------------------------------
## Cache
**Redis**
Digunakan untuk:
- Session
- Cache
- Rate limiting
- Queue (apabila diperlukan)
Redis bukan penyimpanan data utama.
------------------------------------------------------------------------
## API Documentation
**Swagger (OpenAPI)**
Seluruh endpoint wajib memiliki dokumentasi.
Minimal mencakup:
- Summary
- Description
- Request DTO
- Response DTO
- Error Response
------------------------------------------------------------------------
## Validation
Menggunakan:
- class-validator
- class-transformer
Seluruh request divalidasi sebelum masuk business logic.
------------------------------------------------------------------------
## Logging
Menggunakan:
**Pino**
Target:
- Structured Logging
- Performance
- Mudah diintegrasikan dengan monitoring.
------------------------------------------------------------------------
## Testing
Standar pengujian:
### Unit Test
- Jest
### Integration Test
- Jest
### End-to-End Test
- Playwright
Standar ini mengikuti roadmap pengujian RayLab.
------------------------------------------------------------------------
## Containerization
Seluruh aplikasi dijalankan menggunakan Docker.
Container utama:
- raylab-core
- postgres-raylab
- redis
------------------------------------------------------------------------
## Configuration
Konfigurasi menggunakan:
- .env
- NestJS Config Module
Business logic tidak boleh mengakses process.env secara langsung.
------------------------------------------------------------------------
# Coding Convention
## Dependency Injection
Semua dependency menggunakan Dependency Injection NestJS.
Tidak diperbolehkan:
``` typescript
new UserRepository();
```
------------------------------------------------------------------------
## Naming Convention
Folder:
``` text
users
groups
authorization
registry
```
Class:
``` text
UserService
UsersController
UserRepository
CreateUserDto
```
------------------------------------------------------------------------
## UUID
Seluruh entity menggunakan UUID v7 sebagai primary key.
Tidak menggunakan integer auto increment.
------------------------------------------------------------------------
## API Versioning
Semua endpoint menggunakan format:
``` text
/api/v1/
```
Perubahan besar menggunakan versi API baru.
------------------------------------------------------------------------
## Standard Response
### Success
``` json
{
"success": true,
"data": {},
"meta": {}
}
```
### Error
``` json
{
"success": false,
"error": {
"code": "USER_NOT_FOUND",
"message": "User not found"
}
}
```
------------------------------------------------------------------------
# Development Convention
Seluruh modul wajib mengikuti aturan berikut.
- Satu module mewakili satu domain bisnis.
- Tidak ada query database di Controller.
- Tidak ada business logic di Frontend.
- Integrasi eksternal hanya melalui Adapter.
- Seluruh endpoint memiliki DTO.
- Seluruh endpoint memiliki validasi.
- Seluruh endpoint memiliki dokumentasi Swagger.
- Seluruh perubahan penting menghasilkan Audit Log.
- Seluruh modul dapat diuji secara mandiri.
------------------------------------------------------------------------
# Struktur Project
``` text
raylab-core/
├── src/
├── prisma/
├── docs/
├── tests/
├── scripts/
├── docker/
├── package.json
├── docker-compose.yml
└── README.md
```
------------------------------------------------------------------------
# Hasil Akhir Fase 4
Setelah fase ini selesai, RayLab Core memiliki fondasi teknis yang
konsisten, modern, dan siap digunakan sebagai dasar implementasi seluruh
modul pada fase berikutnya.
Dokumen ini menjadi acuan resmi untuk pemilihan teknologi, standar
coding, struktur project, dan konvensi pengembangan RayLab Core.
-310
View File
@@ -1,310 +0,0 @@
# RayLab Core Phase 5 --- Data Architecture
## Tujuan
Fase 5 mendefinisikan arsitektur data RayLab Core. Fokus fase ini adalah
bagaimana seluruh domain saling berhubungan pada tingkat penyimpanan
data, sekaligus menetapkan standar desain database yang akan digunakan
oleh seluruh modul.
> Dokumen ini membahas arsitektur data, bukan implementasi tabel secara
> rinci.
------------------------------------------------------------------------
# Prinsip Data Architecture
RayLab Core menggunakan prinsip berikut:
- Database merepresentasikan domain bisnis.
- Tidak ada duplikasi data antar domain.
- Setiap domain memiliki kepemilikan data (data ownership).
- Seluruh perubahan struktur database dilakukan melalui migration.
- Integritas data lebih diutamakan daripada kemudahan implementasi.
------------------------------------------------------------------------
# Pembagian Database Schema
Agar database tetap terstruktur, PostgreSQL dibagi menjadi beberapa
schema.
## identity
Mengelola identitas pengguna.
Entity utama:
- users
- profiles
- sessions
- user_groups
------------------------------------------------------------------------
## authorization
Mengelola hak akses.
Entity utama:
- groups
- roles
- permissions
- role_permissions
- group_roles
- special_access
- domain_access
- resource_access
------------------------------------------------------------------------
## registry
Mengelola registrasi aplikasi dan layanan.
Entity utama:
- applications
- services
- domains
- adapters
------------------------------------------------------------------------
## configuration
Mengelola konfigurasi runtime.
Entity utama:
- settings
- setting_categories
------------------------------------------------------------------------
## storage
Mengelola penyimpanan logis.
Entity utama:
- storages
- volumes
- quotas
------------------------------------------------------------------------
## media
Digunakan oleh Media Manager.
Entity utama:
- libraries
- folder_templates
- folder_permissions
- folder_mappings
------------------------------------------------------------------------
## audit
Menyimpan riwayat aktivitas.
Entity utama:
- audit_logs
- audit_categories
- audit_targets
------------------------------------------------------------------------
## system
Digunakan oleh sistem internal.
Entity utama:
- jobs
- notifications
- health_checks
------------------------------------------------------------------------
# Hubungan Antar Domain
``` text
Identity
└──── Authorization
├──── Registry
├──── Storage
├──── Media
└──── Configuration
Semua Domain
Audit
```
Audit menerima aktivitas dari seluruh domain.
------------------------------------------------------------------------
# Standar Primary Key
Seluruh entity menggunakan:
- UUID v7
Keuntungan:
- Sulit ditebak
- Konsisten
- Cocok untuk sistem terdistribusi
- Performa indeks lebih baik dibanding UUID v4
------------------------------------------------------------------------
# Standar Timestamp
Seluruh entity memiliki minimal:
``` text
created_at
updated_at
deleted_at
```
Jika diperlukan juga memiliki:
``` text
created_by
updated_by
deleted_by
```
------------------------------------------------------------------------
# Soft Delete
Data penting tidak langsung dihapus.
Sebaliknya menggunakan:
``` text
deleted_at
```
Keuntungan:
- Audit lebih mudah
- Restore data memungkinkan
- Riwayat tetap terjaga
------------------------------------------------------------------------
# Metadata
Entity yang memerlukan fleksibilitas dapat memiliki kolom:
``` text
metadata (JSONB)
```
Contoh:
``` json
{
"theme": "dark",
"avatar": "/avatars/user.png"
}
```
JSONB digunakan hanya untuk data yang bersifat dinamis, bukan untuk
relasi utama.
------------------------------------------------------------------------
# Naming Convention
## Schema
Menggunakan huruf kecil.
Contoh:
``` text
identity
authorization
audit
```
## Table
Menggunakan bentuk jamak.
Contoh:
``` text
users
roles
permissions
```
## Column
Menggunakan snake_case.
Contoh:
``` text
created_at
updated_at
display_name
```
------------------------------------------------------------------------
# Migration Strategy
Seluruh perubahan struktur database wajib menggunakan Prisma Migration.
Tidak diperbolehkan:
- Mengubah tabel langsung di production.
- Mengedit struktur database secara manual.
- Menghapus migration yang sudah digunakan.
Migration menjadi sumber kebenaran (single source of truth) untuk
struktur database.
------------------------------------------------------------------------
# Integritas Data
Beberapa prinsip yang harus dijaga:
- Foreign key digunakan pada seluruh relasi penting.
- Constraint digunakan untuk menjaga validitas data.
- Unique index diterapkan pada data yang harus unik.
- Cascade delete hanya digunakan jika benar-benar diperlukan.
------------------------------------------------------------------------
# Hasil Akhir Fase 5
Pada akhir fase ini RayLab Core memiliki:
- Standar arsitektur database.
- Pembagian schema berdasarkan domain.
- Aturan relasi data.
- Standar UUID, timestamp, dan soft delete.
- Strategi migration.
- Konvensi penamaan database.
Dokumen ini menjadi acuan resmi ketika mulai membuat Prisma Schema dan
migration pada tahap implementasi.
-289
View File
@@ -1,289 +0,0 @@
# RayLab Core Phase 6 --- API Architecture
## Tujuan
Fase 6 mendefinisikan standar API RayLab Core sebagai kontrak komunikasi
untuk seluruh aplikasi dalam ekosistem RayLab.
API harus konsisten, mudah dipahami, terdokumentasi, dan stabil untuk
jangka panjang.
------------------------------------------------------------------------
# Prinsip API
Seluruh API RayLab Core mengikuti prinsip berikut:
- RESTful
- Stateless
- Versioned
- Consistent
- Predictable
- Self Documented
- API First
------------------------------------------------------------------------
# Base URL
Seluruh endpoint menggunakan format:
``` text
/api/v1/
```
Contoh:
``` text
/api/v1/users
/api/v1/groups
/api/v1/domains
/api/v1/applications
/api/v1/media
/api/v1/storage
```
------------------------------------------------------------------------
# HTTP Method
Method Fungsi
-------- ------------------------------------------
GET Membaca data
POST Membuat data
PATCH Memperbarui sebagian data
PUT Mengganti seluruh data (jika diperlukan)
DELETE Soft delete
------------------------------------------------------------------------
# Resource-Oriented API
Contoh endpoint User:
``` http
GET /api/v1/users
GET /api/v1/users/{id}
POST /api/v1/users
PATCH /api/v1/users/{id}
DELETE /api/v1/users/{id}
```
Nested resource:
``` text
/users/{id}/groups
/users/{id}/sessions
/groups/{id}/roles
/domains/{id}/resources
```
Action endpoint:
``` text
/users/{id}/reset-password
/users/{id}/special-access
/users/{id}/groups
```
------------------------------------------------------------------------
# Standard Response
## Success
``` json
{
"success": true,
"data": {},
"meta": {
"requestId": "...",
"timestamp": "..."
}
}
```
## Error
``` json
{
"success": false,
"error": {
"code": "USER_NOT_FOUND",
"message": "User not found"
}
}
```
Semua endpoint wajib menggunakan format yang sama.
------------------------------------------------------------------------
# Pagination
Request:
``` text
GET /users?page=1&limit=20
```
Response:
``` json
{
"success": true,
"data": [],
"pagination": {
"page": 1,
"limit": 20,
"total": 125,
"totalPages": 7
}
}
```
------------------------------------------------------------------------
# Filtering
Contoh:
``` text
/users?group=Owner
/applications?status=online
```
------------------------------------------------------------------------
# Sorting
``` text
/users?sort=name
/users?sort=-createdAt
```
Tanda minus (`-`) berarti urutan menurun (descending).
------------------------------------------------------------------------
# Search
``` text
/users?search=ray
```
Pencarian dilakukan melalui query parameter, bukan endpoint terpisah.
------------------------------------------------------------------------
# API Versioning
Versi API menjadi bagian dari URL.
Contoh:
``` text
/api/v1/
/api/v2/
```
Perubahan besar tidak boleh merusak kompatibilitas client lama.
------------------------------------------------------------------------
# Public API dan Internal API
## Public API
Digunakan oleh:
- Web Admin
- Android
- CLI
- Future Client
## Internal API
Digunakan oleh:
- Background Job
- Scheduler
- Adapter
- Internal Service
Contoh:
``` text
/internal/jobs
/internal/sync
```
Internal API tidak boleh diekspos ke publik.
------------------------------------------------------------------------
# Request ID
Setiap request memiliki Request ID unik.
Header:
``` text
X-Request-ID
```
Request ID digunakan untuk:
- Audit
- Logging
- Debugging
- Distributed tracing
------------------------------------------------------------------------
# Idempotency
Operasi tertentu mendukung:
``` text
Idempotency-Key
```
Hal ini mencegah duplikasi request akibat retry jaringan.
------------------------------------------------------------------------
# Dokumentasi API
Seluruh endpoint harus didokumentasikan menggunakan Swagger (OpenAPI).
Minimal mencakup:
- Summary
- Description
- Request DTO
- Response DTO
- Error Response
Tidak boleh ada endpoint tanpa dokumentasi.
------------------------------------------------------------------------
# Aturan API
- Tidak ada endpoint tanpa versioning.
- Tidak ada endpoint tanpa validasi DTO.
- Tidak ada endpoint tanpa dokumentasi.
- Seluruh endpoint menghasilkan response yang konsisten.
- Controller tidak berisi business logic.
- Error menggunakan kode yang konsisten.
------------------------------------------------------------------------
# Hasil Akhir Fase 6
Pada akhir fase ini RayLab Core memiliki standar API yang menjadi
kontrak komunikasi resmi untuk seluruh aplikasi dalam ekosistem RayLab.
Dokumen ini menjadi acuan implementasi Controller, DTO, Service,
dokumentasi Swagger, dan integrasi seluruh client dengan RayLab Core.
-249
View File
@@ -1,249 +0,0 @@
# RayLab Core Phase 7 --- Project Structure
## Tujuan
Fase 7 mendefinisikan struktur repository, organisasi source code, serta
standar penempatan file pada RayLab Core. Tujuannya adalah memastikan
seluruh kode memiliki pola yang konsisten sehingga mudah dipelihara,
dikembangkan, dan dipahami.
------------------------------------------------------------------------
# Prinsip
- Struktur mengikuti domain bisnis.
- Setiap module berdiri sendiri.
- Konfigurasi dipisahkan dari business logic.
- Dokumentasi menjadi bagian dari repository.
- Mudah diskalakan tanpa mengubah struktur dasar.
------------------------------------------------------------------------
# Struktur Repository
``` text
raylab-core/
├── docs/
├── docker/
├── prisma/
├── scripts/
├── tests/
├── src/
├── .env.example
├── .gitignore
├── docker-compose.yml
├── package.json
├── tsconfig.json
└── README.md
```
------------------------------------------------------------------------
# Struktur Source Code
``` text
src/
├── main.ts
├── app.module.ts
├── common/
├── config/
├── modules/
├── adapters/
└── shared/
```
------------------------------------------------------------------------
# Common
Berisi komponen yang digunakan lintas modul.
Contoh:
- Guards
- Filters
- Interceptors
- Middleware
- Logger
- Exceptions
- Decorators
- Pipes
- Utilities
------------------------------------------------------------------------
# Config
Berisi konfigurasi aplikasi.
Contoh:
- Database
- Redis
- JWT
- Environment
- Swagger
Seluruh konfigurasi diakses melalui ConfigService.
------------------------------------------------------------------------
# Modules
Setiap domain memiliki module sendiri.
``` text
modules/
├── identity/
├── authorization/
├── registry/
├── configuration/
├── storage/
├── media/
├── audit/
├── dashboard/
└── health/
```
------------------------------------------------------------------------
# Struktur Internal Module
``` text
identity/
├── controllers/
├── services/
├── domain/
├── repositories/
├── dto/
├── entities/
├── interfaces/
├── mappers/
├── events/
└── identity.module.ts
```
Seluruh file yang berkaitan dengan satu domain berada dalam module yang
sama.
------------------------------------------------------------------------
# Adapters
Seluruh integrasi eksternal ditempatkan pada folder adapters.
``` text
adapters/
├── nextcloud/
├── jellyfin/
├── immich/
├── minecraft/
└── ...
```
Adapter tidak menyimpan business logic.
------------------------------------------------------------------------
# Prisma
``` text
prisma/
├── schema.prisma
├── migrations/
└── seed.ts
```
Seluruh perubahan database dilakukan melalui migration.
------------------------------------------------------------------------
# Tests
``` text
tests/
├── unit/
├── integration/
└── e2e/
```
Pengujian dipisahkan berdasarkan jenisnya.
------------------------------------------------------------------------
# Dokumentasi
``` text
docs/
├── architecture/
├── adr/
├── api/
├── modules/
└── guides/
```
Dokumentasi menjadi bagian dari source repository dan diperbarui
bersamaan dengan perubahan kode.
------------------------------------------------------------------------
# Naming Convention
## Folder
Menggunakan huruf kecil.
Contoh:
``` text
identity
authorization
media
```
## File
Menggunakan nama yang deskriptif.
Contoh:
``` text
create-user.dto.ts
user.repository.ts
users.controller.ts
```
## Class
Menggunakan PascalCase.
Contoh:
``` text
UsersController
CreateUserDto
UserRepository
```
------------------------------------------------------------------------
# Aturan Penempatan Kode
- Controller hanya berada di folder controllers.
- DTO hanya berada di folder dto.
- Entity hanya berada di folder entities.
- Repository hanya berada di folder repositories.
- Business logic berada di services dan domain.
- Integrasi eksternal berada di adapters.
------------------------------------------------------------------------
# Hasil Akhir Fase 7
Pada akhir fase ini, RayLab Core memiliki struktur repository dan
organisasi kode yang baku. Setiap developer dapat mengetahui lokasi
suatu komponen tanpa perlu menebak, sehingga pengembangan jangka panjang
tetap konsisten dan mudah dipelihara.
-267
View File
@@ -1,267 +0,0 @@
# RayLab Core Phase 8 --- Development Workflow
## Tujuan
Fase 8 mendefinisikan alur kerja pengembangan (Development Workflow)
RayLab Core agar proses implementasi, pengujian, review, dan rilis
dilakukan secara konsisten.
Dokumen ini menjadi standar kerja untuk seluruh pengembangan RayLab
Core.
------------------------------------------------------------------------
# Prinsip
- Seluruh perubahan dapat dilacak.
- Setiap fitur dikembangkan secara terpisah.
- Kualitas kode lebih penting daripada kecepatan.
- Otomatisasi digunakan sebanyak mungkin.
- Dokumentasi diperbarui bersamaan dengan perubahan kode.
------------------------------------------------------------------------
# Development Lifecycle
``` text
Requirement
Architecture
Issue / Task
Implementation
Unit Test
Integration Test
End-to-End Test
Code Review
Merge
Release
```
------------------------------------------------------------------------
# Git Workflow
## Branch Utama
``` text
main
```
Selalu berisi kode yang stabil.
## Branch Pengembangan
Gunakan branch terpisah untuk setiap pekerjaan.
Contoh:
``` text
feature/identity
feature/media-manager
feature/api-users
fix/login-session
fix/storage-permission
refactor/authorization
docs/api-architecture
```
Satu branch hanya menangani satu tujuan.
------------------------------------------------------------------------
# Commit Convention
Format commit:
``` text
type(scope): description
```
Contoh:
``` text
feat(identity): add user service
fix(media): resolve folder permission bug
docs(api): update endpoint documentation
refactor(registry): simplify adapter registration
test(users): add integration test
```
Jenis commit:
- feat
- fix
- docs
- refactor
- test
- chore
- ci
------------------------------------------------------------------------
# Pull Request Checklist
Sebelum merge:
- Kode berhasil dikompilasi.
- Unit test lulus.
- Integration test lulus.
- E2E test lulus (jika relevan).
- Dokumentasi diperbarui.
- Migration ditinjau.
- Tidak ada perubahan yang tidak terkait.
------------------------------------------------------------------------
# Testing Strategy
## Unit Test
Menguji business logic secara terisolasi.
Tool:
- Jest
------------------------------------------------------------------------
## Integration Test
Menguji interaksi antar modul.
Tool:
- Jest
------------------------------------------------------------------------
## End-to-End Test
Menguji perilaku sistem dari sudut pandang pengguna.
Tool:
- Playwright
Standar ini mengikuti proses pengujian RayLab yang telah ditetapkan.
------------------------------------------------------------------------
# Code Review
Fokus review:
- Kesesuaian dengan arsitektur.
- Kualitas business logic.
- Keamanan.
- Konsistensi penamaan.
- Keterbacaan kode.
- Dampak terhadap modul lain.
Review tidak hanya memeriksa apakah kode berjalan, tetapi juga apakah
kode sesuai dengan standar RayLab Core.
------------------------------------------------------------------------
# Database Workflow
Perubahan database:
1. Ubah `schema.prisma`.
2. Buat migration.
3. Jalankan migration pada lingkungan pengembangan.
4. Perbarui dokumentasi jika diperlukan.
Perubahan langsung pada database produksi tidak diperbolehkan.
------------------------------------------------------------------------
# Documentation Workflow
Setiap perubahan yang memengaruhi arsitektur, API, atau modul harus
diikuti dengan pembaruan dokumentasi.
Area dokumentasi:
- Architecture
- API
- Module
- ADR
- Guide
Dokumentasi menjadi bagian dari proses pengembangan.
------------------------------------------------------------------------
# Release Workflow
``` text
Development
Testing
Review
Tag Release
Docker Build
Deployment
```
Setiap rilis menggunakan tag versi yang jelas.
Contoh:
``` text
v1.0.0
v1.1.0
v2.0.0
```
------------------------------------------------------------------------
# Definition of Done
Sebuah pekerjaan dianggap selesai apabila:
- Implementasi selesai.
- Seluruh test lulus.
- Tidak ada error linting.
- Dokumentasi diperbarui.
- Migration tersedia (jika diperlukan).
- Telah melalui code review.
------------------------------------------------------------------------
# Hasil Akhir Fase 8
Pada akhir fase ini RayLab Core memiliki standar workflow pengembangan
yang mencakup implementasi, pengujian, review, dokumentasi, dan proses
rilis. Workflow ini menjadi pedoman agar seluruh pengembangan tetap
konsisten, berkualitas, dan mudah dipelihara dalam jangka panjang.
-249
View File
@@ -1,249 +0,0 @@
# RayLab Core Phase 9 --- Implementation Roadmap
## Tujuan
Fase 9 mendefinisikan urutan implementasi RayLab Core berdasarkan
prioritas, dependensi, dan nilai bisnis. Roadmap ini menjadi acuan resmi
agar pengembangan dilakukan secara bertahap dan terstruktur.
> Fokus fase ini adalah **urutan implementasi**, bukan rincian kode.
------------------------------------------------------------------------
# Prinsip Roadmap
- Bangun fondasi sebelum fitur.
- Implementasikan modul berdasarkan dependensi.
- Setiap fase menghasilkan sistem yang dapat dijalankan dan diuji.
- Hindari membangun fitur yang belum memiliki fondasi.
------------------------------------------------------------------------
# Tahap 1 --- Core Foundation
Tujuan:
- Bootstrap NestJS
- Konfigurasi Docker
- PostgreSQL
- Prisma
- Redis
- Logging
- Config Module
- Health Check
- Swagger
Target:
- Project dapat dijalankan.
- Health endpoint tersedia.
- Database dan Redis terhubung.
------------------------------------------------------------------------
# Tahap 2 --- Identity
Implementasi:
- User
- Profile
- Session
- User Repository
- User Service
- CRUD User
Target:
- Pengguna dapat dikelola melalui API.
------------------------------------------------------------------------
# Tahap 3 --- Authorization
Implementasi:
- Group
- Role
- Permission
- Domain Access
- Resource Access
- Special Access
Target:
- Model IAM RayLab Core berfungsi.
------------------------------------------------------------------------
# Tahap 4 --- Registry
Implementasi:
- Application Registry
- Service Registry
- Domain Registry
- Adapter Registry
Target:
- Seluruh aplikasi dan layanan dapat didaftarkan dan ditemukan.
------------------------------------------------------------------------
# Tahap 5 --- Configuration
Implementasi:
- Runtime Settings
- Setting Categories
- Configuration API
Target:
- Konfigurasi dapat diubah tanpa mengubah kode aplikasi.
------------------------------------------------------------------------
# Tahap 6 --- Storage
Implementasi:
- Storage
- Volume
- Quota
- Path Mapping
Target:
- Penyimpanan logis dapat dikelola secara terpusat.
------------------------------------------------------------------------
# Tahap 7 --- Media Manager
Implementasi:
- Folder Template
- Folder Mapping
- Folder Permission
- Folder Provisioning
- Media Relocation
- Jellyfin Refresh Trigger
Target:
- Media Manager menjadi pengelola utama struktur media.
- Jellyfin hanya bertindak sebagai media server.
------------------------------------------------------------------------
# Tahap 8 --- Audit
Implementasi:
- Audit Log
- Audit Category
- Audit Target
Target:
- Seluruh aktivitas penting sistem tercatat.
------------------------------------------------------------------------
# Tahap 9 --- Dashboard
Implementasi:
- Dashboard API
- Statistik
- Ringkasan sistem
- Widget
Target:
- Dashboard dapat mengambil data dari seluruh modul.
------------------------------------------------------------------------
# Tahap 10 --- Health & Monitoring
Implementasi:
- Health Check
- Service Status
- Dependency Status
- Adapter Status
Target:
- Kondisi sistem dapat dipantau melalui API.
------------------------------------------------------------------------
# Tahap 11 --- External Adapter
Implementasi:
- Nextcloud Adapter
- Jellyfin Adapter
- Immich Adapter
- Adapter lain sesuai kebutuhan
Target:
- Integrasi eksternal menggunakan standar Adapter Layer.
------------------------------------------------------------------------
# Tahap 12 --- Optimization
Implementasi:
- Performance tuning
- Caching
- Query optimization
- Background job optimization
Target:
- Sistem siap untuk penggunaan jangka panjang.
------------------------------------------------------------------------
# Definition of Complete
Sebuah tahap dianggap selesai apabila:
- Seluruh fitur pada tahap tersebut selesai.
- Unit Test lulus.
- Integration Test lulus.
- Dokumentasi diperbarui.
- API terdokumentasi.
- Migration tersedia jika diperlukan.
------------------------------------------------------------------------
# Deliverable
Pada akhir roadmap, RayLab Core memiliki:
- Fondasi teknis yang stabil.
- Identity & Authorization terintegrasi.
- Registry dan Configuration.
- Storage dan Media Manager.
- Audit.
- Dashboard API.
- Health Monitoring.
- Adapter Framework.
- Dokumentasi lengkap.
- Standar pengembangan yang konsisten.
------------------------------------------------------------------------
# Hasil Akhir Fase 9
Dokumen ini menjadi acuan resmi urutan implementasi RayLab Core sehingga
setiap modul dibangun berdasarkan fondasi yang telah tersedia,
mengurangi risiko perubahan besar di kemudian hari dan menjaga
konsistensi arsitektur selama pengembangan.
-221
View File
@@ -1,221 +0,0 @@
# RayLab Core Phase 10 --- Deployment & Operations
## Tujuan
Fase 10 mendefinisikan standar deployment dan operasional RayLab Core
agar sistem dapat berjalan stabil, aman, mudah dipelihara, serta siap
digunakan sebagai layanan 24/7 pada infrastruktur RayLab.
Dokumen ini menjadi acuan implementasi lingkungan produksi maupun
pengembangan.
------------------------------------------------------------------------
# Prinsip Operasional
- Infrastructure as Code.
- Docker sebagai standar deployment.
- Zero manual configuration di production.
- Monitoring dan observability menjadi bagian dari sistem.
- Backup dan recovery harus dipersiapkan sejak awal.
- Deployment harus dapat diulang (repeatable).
------------------------------------------------------------------------
# Environment
RayLab Core memiliki beberapa lingkungan:
- Development
- Testing
- Staging (opsional)
- Production
Setiap environment memiliki konfigurasi yang terpisah.
------------------------------------------------------------------------
# Container Architecture
Komponen utama:
``` text
raylab-core
postgres-raylab
redis
```
Komponen pendukung:
``` text
nginx-proxy-manager
cloudflared / gateway
homepage
uptime-kuma
```
Semua service berada pada Docker Network yang telah ditentukan.
------------------------------------------------------------------------
# Deployment Workflow
``` text
Git
Build
Test
Docker Image
Deployment
Health Check
```
Deployment baru dianggap berhasil apabila health check lulus.
------------------------------------------------------------------------
# Configuration Management
- Gunakan `.env` untuk konfigurasi.
- Secret tidak boleh di-hardcode.
- Konfigurasi dibaca melalui Config Module.
- File `.env.example` disediakan untuk dokumentasi.
------------------------------------------------------------------------
# Logging
Semua log menggunakan format terstruktur.
Minimal mencatat:
- Timestamp
- Request ID
- Level
- Module
- Message
- Error (jika ada)
Log aplikasi dipisahkan dari log container.
------------------------------------------------------------------------
# Monitoring
Monitoring dilakukan menggunakan layanan RayLab:
- Uptime Kuma
- Grafana
- Prometheus
Metrik yang dipantau:
- CPU
- RAM
- Disk
- Response Time
- Error Rate
- Health Endpoint
------------------------------------------------------------------------
# Health Check
Setiap service menyediakan endpoint:
``` text
GET /health
```
Health check minimal memverifikasi:
- Database
- Redis
- Internal Service
- Adapter penting
------------------------------------------------------------------------
# Backup Strategy
Backup dilakukan secara berkala untuk:
- PostgreSQL
- Docker Volume
- Konfigurasi
- Dokumentasi
- Migration
Backup disimpan pada media penyimpanan terpisah sesuai strategi RayLab.
------------------------------------------------------------------------
# Disaster Recovery
Prosedur pemulihan minimal mencakup:
1. Restore database.
2. Restore konfigurasi.
3. Restore volume.
4. Jalankan container.
5. Verifikasi health check.
Targetnya adalah waktu pemulihan yang cepat dan terdokumentasi.
------------------------------------------------------------------------
# Security Baseline
Deployment harus memenuhi standar minimum:
- HTTPS
- Secret melalui environment
- Tidak mengekspos port yang tidak diperlukan
- Container berjalan dengan hak akses minimum jika memungkinkan
- Update dependency secara berkala
------------------------------------------------------------------------
# Maintenance
Aktivitas rutin:
- Update dependency
- Update Docker image
- Review log
- Review backup
- Verifikasi monitoring
- Verifikasi dokumentasi
------------------------------------------------------------------------
# Operational Checklist
Sebelum production:
- Docker berjalan normal.
- Health check lulus.
- Backup aktif.
- Monitoring aktif.
- Logging aktif.
- Dokumentasi diperbarui.
- Migration terbaru diterapkan.
------------------------------------------------------------------------
# Hasil Akhir Fase 10
Pada akhir fase ini RayLab Core memiliki standar deployment dan
operasional yang konsisten untuk lingkungan pengembangan maupun
produksi. Seluruh proses deployment, monitoring, backup, logging, dan
pemeliharaan terdokumentasi sehingga sistem siap dijalankan sebagai
layanan inti ekosistem RayLab.
-205
View File
@@ -1,205 +0,0 @@
# RayLab Core Phase 11 --- Scaling Strategy
## Tujuan
Fase 11 mendefinisikan strategi pengembangan jangka panjang RayLab Core
agar mampu berkembang dari sistem yang melayani kebutuhan pribadi
menjadi platform yang dapat menangani lebih banyak aplikasi, pengguna,
layanan, dan integrasi tanpa perlu mengubah arsitektur dasarnya.
Dokumen ini menjadi acuan untuk menjaga skalabilitas teknis maupun
organisasi proyek.
------------------------------------------------------------------------
# Prinsip Skalabilitas
- Bangun untuk kebutuhan saat ini, rancang untuk kebutuhan masa depan.
- Modular sebelum distributed.
- Scale up terlebih dahulu, scale out bila diperlukan.
- Hindari premature optimization.
- Pertahankan kompatibilitas ke belakang (backward compatibility) jika
memungkinkan.
------------------------------------------------------------------------
# Tahapan Skalabilitas
## Tahap 1 --- Single Server
Karakteristik:
- Satu instance RayLab Core.
- Satu PostgreSQL.
- Satu Redis.
- Docker Compose.
Cocok untuk homelab dan pengembangan awal.
------------------------------------------------------------------------
## Tahap 2 --- Multi Service
Mulai memisahkan layanan pendukung.
Contoh:
- Database terpisah.
- Monitoring terpisah.
- Backup terpisah.
- Worker background.
Tujuan:
Mengurangi coupling antar layanan.
------------------------------------------------------------------------
## Tahap 3 --- Horizontal Scaling
Jika beban meningkat:
- Menjalankan beberapa instance RayLab Core.
- Menggunakan reverse proxy atau load balancer.
- Session dipindahkan ke Redis.
- Stateless API menjadi syarat utama.
------------------------------------------------------------------------
# Modular Growth
Modul baru harus dapat ditambahkan tanpa mengubah modul yang sudah ada.
Contoh:
- AI
- Notification
- Billing
- Home Automation
- Marketplace Adapter
Integrasi dilakukan melalui service dan adapter yang sudah ada.
------------------------------------------------------------------------
# Adapter Expansion
Seluruh integrasi eksternal mengikuti pola Adapter.
Contoh:
- Nextcloud
- Jellyfin
- Immich
- Gitea
- Forgejo
- Home Assistant
- Ollama
- Future services
Tidak ada business logic di dalam adapter.
------------------------------------------------------------------------
# Database Scaling
Strategi bertahap:
1. Optimasi query.
2. Indexing.
3. Connection pooling.
4. Read replica (jika diperlukan).
5. Sharding hanya jika benar-benar dibutuhkan.
Perubahan dilakukan bertahap berdasarkan kebutuhan nyata.
------------------------------------------------------------------------
# Storage Scaling
Storage harus mendukung penambahan kapasitas tanpa mengubah business
logic.
Contoh:
- HDD tambahan.
- NAS.
- Object Storage (masa depan).
Storage Layer menjadi abstraksi terhadap media penyimpanan.
------------------------------------------------------------------------
# API Evolution
Strategi pengembangan API:
- Gunakan versioning.
- Hindari breaking changes.
- Tandai endpoint lama sebagai deprecated.
- Dokumentasikan seluruh perubahan.
------------------------------------------------------------------------
# Performance Strategy
Fokus optimasi:
- Query database.
- Caching Redis.
- Background Job.
- Lazy Loading.
- Pagination.
- Batch Processing.
Optimasi dilakukan berdasarkan hasil monitoring.
------------------------------------------------------------------------
# Observability
Seiring pertumbuhan sistem:
- Logging terstruktur.
- Metrics.
- Health Check.
- Audit.
- Distributed tracing (jika diperlukan).
------------------------------------------------------------------------
# Maintainability
Setiap modul harus:
- Memiliki dokumentasi.
- Memiliki test.
- Mengikuti coding convention.
- Mengikuti layered architecture.
Refactoring dilakukan secara bertahap tanpa mengubah kontrak publik.
------------------------------------------------------------------------
# Long-Term Vision
RayLab Core dirancang agar dapat berkembang menjadi platform yang
mendukung:
- Banyak aplikasi.
- Banyak pengguna.
- Banyak domain.
- Banyak adapter.
- Banyak layanan.
Dengan tetap mempertahankan satu pusat Identity & Access Management dan
satu standar arsitektur.
------------------------------------------------------------------------
# Hasil Akhir Fase 11
Pada akhir fase ini, RayLab Core memiliki strategi skalabilitas yang
jelas untuk pertumbuhan jangka panjang. Arsitektur yang telah dibangun
pada fase-fase sebelumnya dapat diperluas tanpa perubahan mendasar
sehingga sistem tetap modular, konsisten, dan mudah dipelihara.
-129
View File
@@ -1,129 +0,0 @@
# RayLab Core Phase 12 --- Future Vision & Evolution
## Tujuan
Fase 12 mendokumentasikan visi jangka panjang RayLab Core sebagai
platform inti ekosistem RayLab. Dokumen ini menjadi panduan arah
pengembangan di masa depan tanpa mengubah prinsip arsitektur yang telah
ditetapkan.
------------------------------------------------------------------------
# Visi
RayLab Core dirancang sebagai pusat pengelolaan identitas, otorisasi,
konfigurasi, penyimpanan, media, dan integrasi untuk seluruh layanan
dalam ekosistem RayLab.
Prinsip utamanya adalah membangun platform yang modular, dapat
diperluas, terdokumentasi, dan mudah dipelihara.
------------------------------------------------------------------------
# Sasaran Jangka Panjang
- Menjadi pusat Identity & Access Management (IAM).
- Menjadi registry seluruh aplikasi RayLab.
- Menjadi pusat konfigurasi layanan.
- Menjadi pengelola storage dan media.
- Menjadi fondasi integrasi seluruh aplikasi internal.
------------------------------------------------------------------------
# Evolusi Modul
Modul yang dapat ditambahkan di masa depan antara lain:
- Notification Center
- Workflow Engine
- Scheduler
- AI Integration
- Home Automation
- Billing
- Analytics
- Search Service
Modul baru harus mengikuti standar Layered Architecture dan tidak
mengubah kontrak modul yang sudah ada.
------------------------------------------------------------------------
# Evolusi Adapter
Adapter baru dapat ditambahkan untuk layanan seperti:
- Home Assistant
- Ollama
- Forgejo
- GitHub
- S3 Compatible Storage
- MQTT Broker
- Sistem pihak ketiga lainnya
Seluruh integrasi dilakukan melalui Adapter Layer agar business logic
tetap independen.
------------------------------------------------------------------------
# Ekosistem RayLab
RayLab Core diharapkan menjadi fondasi bagi berbagai aplikasi, seperti:
- Dashboard
- Warung Management
- File Management
- Media Management
- Monitoring
- Wiki
- Mobile Applications
- Future Services
Semua aplikasi menggunakan standar autentikasi dan otorisasi yang sama.
------------------------------------------------------------------------
# Standar Evolusi
Perubahan besar harus:
- Didokumentasikan melalui Architecture Decision Record (ADR).
- Menjaga kompatibilitas jika memungkinkan.
- Memiliki migration path yang jelas.
- Disertai pembaruan dokumentasi dan pengujian.
------------------------------------------------------------------------
# Continuous Improvement
Pengembangan dilakukan secara berkelanjutan melalui:
- Refactoring berkala.
- Peningkatan performa.
- Evaluasi keamanan.
- Penyempurnaan dokumentasi.
- Otomatisasi deployment dan pengujian.
------------------------------------------------------------------------
# Success Criteria
RayLab Core dianggap berhasil apabila:
- Mudah dikembangkan.
- Mudah diintegrasikan.
- Mudah dipelihara.
- Memiliki dokumentasi yang lengkap.
- Memiliki kualitas kode yang konsisten.
- Menjadi fondasi yang stabil bagi seluruh aplikasi RayLab.
------------------------------------------------------------------------
# Penutup
Fase ini tidak mendefinisikan fitur baru, melainkan arah pengembangan
jangka panjang. Setiap evolusi RayLab Core harus tetap berpegang pada
prinsip modularitas, konsistensi, keamanan, dokumentasi, dan
maintainability yang telah ditetapkan sejak fase awal.
Dengan demikian, RayLab Core dapat berkembang seiring kebutuhan tanpa
kehilangan stabilitas arsitekturnya.
-149
View File
@@ -1,149 +0,0 @@
Ringkasan
Dokumen ini menjelaskan struktur folder proyek, alur kerja (workflow) pengembangan, dan bagaimana data diproses dari UI sampai ke penyimpanan (data flow). Tujuan: memberi panduan onboarding cepat untuk developer agar konsisten dengan arsitektur RayLab Core.
1. Struktur Folder (penjelasan)
```text Docs/Structure-Workflow-DataFlow.md
raylab-core/
├── docker/ # Docker compose, konfigurasi container
├── prisma/ # Prisma schema, migrations, seed
├── docs/ # Dokumentasi proyek (arsitektur, ADR, panduan)
├── scripts/ # Script helper (migrate, seed, build)
├── src/ # Source code aplikasi
│ ├── main.ts # Bootstrap aplikasi
│ ├── app.module.ts # Root module (dependensi utama)
│ ├── common/ # Guards, filters, interceptors, middleware, logger, utils
│ ├── config/ # ConfigModule, ConfigService (env parsing)
│ ├── modules/ # Domain modules (identity, authorization, media, ...)
│ │ ├── identity/ # Example: controllers/, services/, repositories/, dto/, entities/
│ │ └── ...
│ ├── adapters/ # External integrations (Nextcloud, Jellyfin, Immich)
│ └── shared/ # Shared services (PrismaService, event bus, constants)
├── tests/ # Unit, integration, e2e
├── .env.example
├── docker-compose.yml
└── README.md
```
Penjelasan singkat folder penting:
- src/modules: setiap module merepresentasikan domain bisnis. Contoh: identity, authorization, registry. Module berisi subfolder terstruktur: controllers, services, domain, repositories, dto, entities, interfaces, events.
- src/common: komponen yang dipakai lintas module, seperti exception filters, authentication guards, middleware request-id, logging interceptor.
- src/adapters: semua integrasi eksternal hanya lewat adapter (no business logic). Adapter expose interface yang dipakai application service.
- src/shared: service bersama seperti PrismaService (DB client), event bus, constant classes.
- prisma/: schema prisma, migrations — migration menjadi sumber kebenaran struktur DB.
2. Development Workflow (Ringkas)
- Branching:
- main: selalu stabil dan dapat direlease
- feature/*, fix/*, refactor/* untuk pekerjaan terpisah
- Commit convention: type(scope): description (feat, fix, docs, test, refactor)
- PR checklist: build ok, unit tests ok, integration tests ok, dokumentasi diupdate, migration tersedia jika perlu
- CI Pipeline: lint → test → build → prisma migrate (dry-run) → docker build
- Release: tag versi (semver), build docker image, deploy via docker compose / orchestrator
3. Request & Data Flow — dari UI sampai Database
Langkah umum (singkat):
UI (web/mobile/cli)
↓ (HTTP request JSON + headers)
API Gateway / Reverse Proxy (optional)
NestJS Controller (src/modules/.../controllers)
- Validasi ringan (DTO + Pipes)
- Mapping request → DTO
- Menambahkan metadata (requestId, auth user)
Application Service (src/modules/.../services)
- Implementasi use-case / orchestration
- Koordinasi Domain Services, Repositories, Adapters
- Menjalankan transaksi jika perlu
- Men-trigger audit/event/background job
Domain Service / Domain Logic (src/modules/.../domain atau services)
- Semua aturan bisnis utama ditempatkan di sini
- Validasi domain, rules, invariants
Repository (src/modules/.../repositories)
- Akses database (Prisma client) — Save, Find, Update, Delete
- Tidak ada business logic berat di sini
Database (PostgreSQL)
Respon balik mengikuti format standar API (success/error)
Contoh alur lebih rinci (Create User):
1. UI POST /api/v1/users {email, displayName, password}
2. Controller menerima request, Pipe class-validator validasi DTO
3. Controller memanggil UserService.create(createUserDto, ctx)
4. UserService melakukan business logic: cek duplikasi email (via UserRepository), hash password (di service), mempersiapkan data user
5. UserService memanggil UserRepository.create(data)
6. Repository menggunakan PrismaClient untuk menyimpan ke tabel identity.users
7. Setelah sukses, UserService men-trigger AuditService.log(...) dan mengembalikan DTO respon
8. Controller membungkus respon ke format standar dan mengembalikan ke client
4. Non-blocking / Side Effects
- Audit: dipicu oleh Application Service setelah perubahan penting; bisa synchronous atau pushed ke queue
- Events: domain events dapat dipublish ke event bus (in-memory atau Redis) untuk worker/background processing
- Background Jobs: proses berat (email, refresh library, thumbnail generation) diproses oleh worker (BullMQ/Redis)
- Cache: gunakan Redis untuk session, rate-limiting, cache query hasil expensive
5. Error Handling & Observability
- Request ID: middleware menambahkan X-Request-ID jika belum ada; dipakai di log dan audit
- Structured logging: Pino dengan fields {timestamp, level, module, requestId, message}
- Error response standard:
```json Docs/Structure-Workflow-DataFlow.md
{
"success": false,
"error": { "code": "USER_NOT_FOUND", "message": "User not found" }
}
```
- Success response standard:
```json Docs/Structure-Workflow-DataFlow.md
{
"success": true,
"data": {},
"meta": { "requestId": "...", "timestamp": "..." }
}
```
- Monitoring: expose /health yang memeriksa koneksi DB, Redis, adapter penting. Integrasikan metrics untuk Prometheus/Grafana.
6. Best Practices & Rules
- Controller tipis: hanya validasi + mapping + panggil service
- Business logic hanya di Domain/Service
- Repository hanya query DB (Prisma)
- Adapter untuk komunikasi eksternal tanpa business logic
- Semua perubahan DB melalui migration (Prisma Migrate)
- Gunakan DTO + class-validator untuk input validation
- Gunakan UUID v7 untuk primary key, timestamps created_at/updated_at/deleted_at
- Soft delete: gunakan deleted_at
- Semua endpoint harus terdokumentasi di Swagger/OpenAPI
7. Contoh file lokasi logis untuk use-case "Create User"
- src/modules/identity/controllers/users.controller.ts (HTTP layer)
- src/modules/identity/dto/create-user.dto.ts (validation)
- src/modules/identity/services/user.service.ts (application service)
- src/modules/identity/domain/user.domain.ts (domain rules)
- src/modules/identity/repositories/user.repository.ts (prisma queries)
- src/shared/prisma.service.ts (prisma client)
- src/common/middleware/request-id.middleware.ts (request id)
- src/modules/audit/services/audit.service.ts (audit logging)
Penutup
Dokumen ini menjadi ringkasan teknis untuk struktur kode dan alur data. Jika Anda ingin, saya bisa:
- Menggenerate file contoh (controller/service/repository/dto) untuk use-case Create User sesuai struktur di atas.
- Membuat diagram sequence (plantuml) untuk alur request.
- Menambahkan template middleware, audit service, dan contoh Prisma model untuk User.
Pilih aksi selanjutnya jika ingin saya buatkan implementasi contoh secara otomatis.
-1
View File
@@ -1 +0,0 @@
// REMOVED: file content deleted per user request
-1
View File
@@ -1,4 +1,3 @@
# placeholder docker-compose (to be filled later)
version: '3.8'
services:
app:
+5432
View File
File diff suppressed because it is too large Load Diff
+43 -29
View File
@@ -2,55 +2,69 @@
"name": "raylab-core",
"version": "0.1.0",
"private": true,
"description": "RayLab Core - Identity & Platform services",
"description": "RayLab Core - Identity & Platform Services",
"author": "RayLab",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
},
"scripts": {
"start": "node dist/main.js",
"start:dev": "ts-node-dev --respawn --pretty --transpile-only src/main.ts",
"build": "tsc -p tsconfig.json",
"lint": "eslint . --ext .ts",
"lint": "eslint \"src/**/*.ts\"",
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
"test": "jest",
"test:watch": "jest --watch",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate dev",
"prisma:deploy": "prisma migrate deploy",
"prisma:reset": "prisma migrate reset",
"prisma:studio": "prisma studio",
"prisma:seed": "ts-node prisma/seed.ts"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/config": "^3.0.0",
"@nestjs/swagger": "^6.0.0",
"@nestjs/common": "^10.4.20",
"@nestjs/config": "^3.3.0",
"@nestjs/core": "^10.4.20",
"@nestjs/jwt": "^10.2.0",
"@nestjs/mapped-types": "^2.1.0",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.4.20",
"@nestjs/swagger": "^7.4.2",
"@prisma/client": "^5.22.0",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.0",
"swagger-ui-express": "^4.6.3",
"@prisma/client": "^5.0.0",
"pino": "^8.0.0",
"dotenv": "^16.0.0"
"class-validator": "^0.14.2",
"dotenv": "^16.6.1",
"jsonwebtoken": "^9.0.2",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"pino": "^9.7.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2",
"swagger-ui-express": "^5.0.1",
"uuid": "^11.1.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/swagger-ui-express": "^4.1.4",
"typescript": "^5.1.0",
"ts-node": "^10.9.1",
"@types/bcrypt": "^5.0.2",
"@types/jest": "^29.5.14",
"@types/node": "^22.13.10",
"@types/passport-jwt": "^4.0.1",
"@types/supertest": "^6.0.3",
"@types/swagger-ui-express": "^4.1.8",
"@typescript-eslint/eslint-plugin": "^8.25.0",
"@typescript-eslint/parser": "^8.25.0",
"eslint": "^9.21.0",
"@eslint/js": "^9.21.0",
"globals": "^16.0.0",
"jest": "^29.7.0",
"prettier": "^3.5.3",
"prisma": "^5.22.0",
"supertest": "^7.0.0",
"ts-jest": "^29.2.6",
"ts-node": "^10.9.2",
"ts-node-dev": "^2.0.0",
"prisma": "^5.0.0",
"eslint": "^8.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"prettier": "^2.8.0",
"jest": "^29.0.0",
"ts-jest": "^29.0.0",
"@types/jest": "^29.0.0",
"supertest": "^6.3.0",
"@types/supertest": "^2.0.12"
"typescript": "^5.8.2"
}
}
+15 -2
View File
@@ -1,5 +1,6 @@
// Prisma schema placeholder
// Define models in implementation phase
// Prisma schema
// Basic User model for RayLab Core
generator client {
provider = "prisma-client-js"
}
@@ -8,3 +9,15 @@ datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
name String
email String @unique
password String
status String @default("ACTIVE")
metadata Json?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
deleted_at DateTime?
}
+18
View File
@@ -0,0 +1,18 @@
src/ (overview)
Penjelasan singkat:
Folder src adalah root source code aplikasi. Berikut child-folder utama yang ada saat ini:
- core/: framework-level utilities (events, middleware, logger, exceptions, queue)
- shared/: shared utilities, types, decorators
- config/: configuration module dan service
- adapters/: external integrations
- modules/: domain modules (identity, authorization, media, storage, ...)
Contoh file entrypoint:
- src/main.ts: bootstrap aplikasi, register global middleware, setup swagger
- src/app.module.ts: root module yang mengimpor module lainnya
Panduan singkat:
- Ikuti struktur Clean Architecture untuk modul-modul dalam modules/.
- Jangan menaruh business logic di shared/ atau core/.
- Gunakan event-driven dan queue untuk proses lintas module.
+18
View File
@@ -0,0 +1,18 @@
adapters/
Penjelasan singkat:
Folder adapters berisi integrasi ke layanan eksternal. Adapter bertanggung jawab sebagai "translator" antara API eksternal dan interface aplikasi.
Struktur contoh:
- adapters/identity/
- adapters/media/ (jellyfin, immich)
- adapters/storage/ (filesystem, nextcloud, s3)
- adapters/notification/ (email, webhook)
- adapters/integration/ (3rd-party integrations)
Aturan:
- Adapter tidak mengandung business logic. Business logic tetap berada di Application/Domain layer.
- Adapter harus mengimplementasikan interface yang didefinisikan di module/domain yang memerlukannya.
Contoh file:
- src/adapters/media/jellyfin/jellyfin.adapter.ts
+11
View File
@@ -0,0 +1,11 @@
adapters/identity/
Penjelasan:
Adapter untuk layanan identity eksternal (jika ada). Implementasi translation antara eksternal API dan internal interface.
Contoh file:
- identity.adapter.ts
Aturan:
- Jangan letakkan business logic di adapter.
- Adapter harus mengimplementasikan interface yang dibutuhkan module.
+1
View File
@@ -0,0 +1 @@
+10
View File
@@ -0,0 +1,10 @@
adapters/immich/
Penjelasan:
Adapter spesifik untuk Immich integration.
Contoh file:
- immich.adapter.ts
Aturan:
- Adapter harus stateless dan dapat digunakan kembali.
+10
View File
@@ -0,0 +1,10 @@
adapters/integration/
Penjelasan:
Adapter untuk integrasi third-party yang lebih spesifik (mis. external API vendors).
Contoh file:
- vendor-a.adapter.ts
Aturan:
- Jangan masukkan business rules di sini; hanya mapping dan komunikasi.
+10
View File
@@ -0,0 +1,10 @@
adapters/jellyfin/
Penjelasan:
Adapter spesifik untuk Jellyfin (trigger library refresh, fetch metadata).
Contoh file:
- jellyfin.adapter.ts
Aturan:
- Jangan masukkan orchestration di adapter; gunakan service/module yang memanggil adapter.
+12
View File
@@ -0,0 +1,12 @@
adapters/media/
Penjelasan:
Adapters untuk media services seperti Jellyfin atau Immich.
Contoh file:
- jellyfin.adapter.ts
- immich.adapter.ts
Aturan:
- Adapter hanya wrap API calls dan mapping data.
- Integrasi heavy operations diserahkan ke queue/worker.
+10
View File
@@ -0,0 +1,10 @@
adapters/nextcloud/
Penjelasan:
Adapter untuk Nextcloud (file ops, permissions).
Contoh file:
- nextcloud.adapter.ts
Aturan:
- Pastikan error mapping agar client mendapatkan pesan yang konsisten.
+11
View File
@@ -0,0 +1,11 @@
adapters/notification/
Penjelasan:
Adapter untuk sistem notifikasi (email, webhook).
Contoh file:
- email.adapter.ts
- webhook.adapter.ts
Aturan:
- Notification adapter bersifat best-effort; retry dan persistence dikelola oleh queue/worker.
+13
View File
@@ -0,0 +1,13 @@
adapters/storage/
Penjelasan:
Adapters untuk storage backends: filesystem, nextcloud, s3, minio.
Contoh file:
- filesystem.adapter.ts
- nextcloud.adapter.ts
- s3.adapter.ts
Aturan:
- Adapter expose interface seperti readFile, writeFile, listFolder.
- Business logic integrasi tetap berada di module/storage.
+15 -1
View File
@@ -1 +1,15 @@
// placeholder app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { IdentityModule } from './modules/identity/identity.module';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
IdentityModule,
],
})
export class AppModule {}
+1
View File
@@ -0,0 +1 @@
// MOVED: see src/core and src/shared
+1
View File
@@ -0,0 +1 @@
// MOVED: see src/core/guards or module-specific guards
+1
View File
@@ -0,0 +1 @@
// MOVED: see src/core/exceptions
+1
View File
@@ -0,0 +1 @@
// MOVED: see src/core/guards or module-specific guards
+1
View File
@@ -0,0 +1 @@
// MOVED: see src/core/interceptors or module-specific interceptors
+1
View File
@@ -0,0 +1 @@
// MOVED: see src/core/logger
+1
View File
@@ -0,0 +1 @@
// MOVED: see src/core/middleware
+1
View File
@@ -0,0 +1 @@
// MOVED: see src/shared/utils
-1
View File
@@ -1 +0,0 @@
// placeholder config.module.ts
-1
View File
@@ -1 +0,0 @@
// placeholder config.service.ts
+23
View File
@@ -0,0 +1,23 @@
core/
Penjelasan singkat:
Folder core berisi fasilitas framework-level yang dipakai lintas modul. Jangan tempatkan business logic domain di sini. Core menyediakan building block seperti:
- Event bus / dispatcher
- Global middleware (request-id, correlation id)
- Global exception filters
- Logger (pino wrapper)
- Queue foundation (struktur jobs/workers/processors)
Contoh file yang ada di folder ini:
- src/core/events/event.interface.ts
- src/core/events/event-publisher.ts
- src/core/logger/logger.service.ts
- src/core/middleware/request-id.middleware.ts
- src/core/exceptions/http-exception.filter.ts
- src/core/queue/*
Panduan singkat:
- Semua event domain didefinisikan di core/events. Module boleh publish/subscribe.
- Logger tersedia sebagai utilitas global (injectable or exported instance).
- Queue hanya menyediakan pondasi; integrasi spesifik (BullMQ, Redis) dilakukan pada fase infrastructure atau worker.
+41
View File
@@ -0,0 +1,41 @@
import {
Injectable,
CanActivate,
ExecutionContext,
UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(
private readonly jwtService: JwtService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<Request>();
const authHeader = request.headers.authorization;
if (!authHeader) {
throw new UnauthorizedException('Authorization header is missing.');
}
const [type, token] = authHeader.split(' ');
if (type !== 'Bearer' || !token) {
throw new UnauthorizedException('Invalid authorization header.');
}
try {
const payload = await this.jwtService.verifyAsync(token);
request['user'] = payload;
return true;
} catch {
throw new UnauthorizedException('Invalid or expired token.');
}
}
}
@@ -0,0 +1,12 @@
import { Request } from 'express';
export interface JwtPayload {
sub: string;
email: string;
role: string;
permissions: string[];
}
export interface AuthenticatedRequest extends Request {
user: JwtPayload;
}
+11
View File
@@ -0,0 +1,11 @@
export default () => ({
database: {
url:
`postgresql://` +
`${process.env.DB_USER}:` +
`${process.env.DB_PASSWORD}@` +
`${process.env.SERVER_HOST}:` +
`${process.env.DB_PORT}/` +
`${process.env.DB_NAME}?schema=public`
}
});
+14
View File
@@ -0,0 +1,14 @@
core/events/
Penjelasan:
Folder ini berisi pondasi untuk domain events: definisi event, publisher, dispatcher, dan handler.
Isi yang direkomendasikan:
- event.interface.ts (DomainEvent)
- event-publisher.ts (interface dan implementasi sederhana)
- event-dispatcher.ts (dispatcher untuk publish/dispatch event)
- event-handler.ts (type alias untuk handler)
Aturan:
- Event hanya bermakna untuk komunikasi lintas module atau untuk memisahkan side-effect.
- Hindari business logic kompleks di handler; handler sebaiknya mendelegasikan ke application service atau job queue.
+13
View File
@@ -0,0 +1,13 @@
import { DomainEvent } from './event.interface';
export class EventDispatcher {
private publisher = new (require('./event-publisher').InMemoryEventPublisher)();
register(handler: (e: DomainEvent) => Promise<void>) {
this.publisher.register(handler);
}
async dispatch(event: DomainEvent) {
await this.publisher.publish(event);
}
}
+3
View File
@@ -0,0 +1,3 @@
import { DomainEvent } from './event.interface';
export type EventHandler = (event: DomainEvent) => Promise<void>;
+17
View File
@@ -0,0 +1,17 @@
import { DomainEvent } from './event.interface';
export interface EventPublisher {
publish(event: DomainEvent): Promise<void>;
}
export class InMemoryEventPublisher implements EventPublisher {
private handlers: Array<(e: DomainEvent) => Promise<void>> = [];
register(handler: (e: DomainEvent) => Promise<void>) {
this.handlers.push(handler);
}
async publish(event: DomainEvent) {
await Promise.all(this.handlers.map((h) => h(event)));
}
}
+5
View File
@@ -0,0 +1,5 @@
export interface DomainEvent {
readonly name: string;
readonly payload: any;
readonly occurredAt: Date;
}
+12
View File
@@ -0,0 +1,12 @@
core/exceptions/
Penjelasan:
Berisi global exception filters dan custom exception classes.
Isi yang direkomendasikan:
- http-exception.filter.ts
- domain-exception.ts (custom domain exception base)
Aturan:
- Exception filter mengubah exception menjadi response standar API.
- Gunakan kode error konsisten (error code constant) agar client dapat menangani error.
@@ -0,0 +1,18 @@
import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';
@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const status = exception.getStatus ? exception.getStatus() : 500;
response.status(status).json({
success: false,
error: {
code: exception.code || 'INTERNAL_ERROR',
message: exception.message || 'Internal server error',
},
});
}
}
+12
View File
@@ -0,0 +1,12 @@
core/logger/
Penjelasan:
Folder ini berisi wrapper logger (mis. pino) dan utilitas logging global.
Isi yang direkomendasikan:
- logger.service.ts / logger.instance.ts (exported pino instance or injectable wrapper)
- logger.interceptor.ts (optional HTTP logging interceptor)
Aturan:
- Gunakan structured logging (json) dengan field requestId, module, level.
- Jangan menambahkan business logic ke logger.
+5
View File
@@ -0,0 +1,5 @@
import pino from 'pino';
export const logger = pino({
level: process.env.LOG_LEVEL || 'info',
});
+14
View File
@@ -0,0 +1,14 @@
core/middleware/
Penjelasan:
Berisi middleware global seperti request-id, correlation id, timing, rate-limit glue (middleware only, implementasi rate-limit ada di infra).
Isi yang direkomendasikan:
- request-id.middleware.ts
- correlation-id.middleware.ts
- timing.middleware.ts
Aturan:
- Middleware harus ringan dan synchronous jika memungkinkan.
- Jangan letakkan business logic di middleware.
- Middleware global didaftarkan di main.ts atau CoreModule.
@@ -0,0 +1,11 @@
import { Injectable, NestMiddleware } from '@nestjs/common';
import { v4 as uuidv4 } from 'uuid';
@Injectable()
export class RequestIdMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
req.requestId = req.headers['x-request-id'] || uuidv4();
res.setHeader('X-Request-ID', req.requestId);
next();
}
}
+8
View File
@@ -0,0 +1,8 @@
Queue layer placeholder.
Structure:
- jobs/: job definitions
- workers/: worker implementations
- processors/: processors that execute jobs
Queue integration (e.g. BullMQ) should be added in infrastructure phase.
+11
View File
@@ -0,0 +1,11 @@
core/queue/jobs/
Penjelasan:
Tempat definisi job (job payload shape, job name constants). Job definitions hanya mendefinisikan contract untuk job.
Contoh:
- media-scan.job.ts
- thumbnail.job.ts
Aturan:
- Job definition tidak mengeksekusi logic; worker/processors yang mengeksekusi.
+12
View File
@@ -0,0 +1,12 @@
core/queue/processors/
Penjelasan:
Processor berisi fungsi yang mengeksekusi pekerjaan sebenarnya (CPU/IO heavy). Processor harus idempotent dan memiliki retry strategy.
Contoh:
- media-scan.processor.ts
- thumbnail.processor.ts
Aturan:
- Processor harus bisa dijalankan terpisah (CLI/worker process).
- Jangan panggil controller dari processor; gunakan service/infrastructure.
+12
View File
@@ -0,0 +1,12 @@
core/queue/workers/
Penjelasan:
Worker mengkonsumsi job dari queue dan memanggil processor yang sesuai.
Contoh:
- media-scan.worker.ts
- thumbnail.worker.ts
Aturan:
- Worker hanya fokus pada retry/failure handling dan delegasi ke processor.
- Implementasi queue (BullMQ, Bee-Queue) ditaruh di infra/worker deployment.
+48 -1
View File
@@ -1 +1,48 @@
// placeholder main.ts
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { ConfigService } from '@nestjs/config';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = app.get(ConfigService);
app.setGlobalPrefix('api');
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
forbidNonWhitelisted: true,
}),
);
app.enableCors();
const swaggerEnabled =
config.get<string>('SWAGGER_ENABLED') === 'true';
if (swaggerEnabled) {
const swaggerConfig = new DocumentBuilder()
.setTitle('RayLab Core API')
.setDescription('RayLab Core REST API')
.setVersion('1.0.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, swaggerConfig);
SwaggerModule.setup('docs', app, document);
}
const port = config.get<number>('PORT') || 3000;
await app.listen(port);
console.log(`Server running on http://localhost:${port}`);
}
bootstrap();
+20
View File
@@ -0,0 +1,20 @@
modules/
Penjelasan singkat:
Folder modules berisi domain modules. Setiap module merepresentasikan satu domain bisnis dan mengikuti prinsip Clean Architecture dengan folder:
- presentation/ # controllers, dto, response
- application/ # use-cases, commands, queries
- domain/ # entities, value objects, repository interfaces, domain services, events
- infrastructure/ # prisma repositories, adapter implementations
Contoh module: identity
- src/modules/identity/presentation/controllers/users.controller.ts
- src/modules/identity/application/services/get-user.service.ts
- src/modules/identity/domain/entities/user.entity.ts
- src/modules/identity/infrastructure/repositories/user.repository.ts
Panduan singkat:
- Controller tipis: lakukan validasi dan panggil application service.
- Business logic harus berada di application/domain.
- Infrastruktur mengimplementasikan interface domain (dependency inversion).
- Gunakan event untuk komunikasi lintas module bila memungkinkan.
@@ -0,0 +1,4 @@
import { SetMetadata } from '@nestjs/common';
export const Permissions = (...permissions: string[]) =>
SetMetadata('permissions', permissions);
@@ -0,0 +1,36 @@
import {
Injectable,
CanActivate,
ExecutionContext,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class PermissionGuard implements CanActivate {
constructor(
private readonly reflector: Reflector,
) {}
canActivate(context: ExecutionContext): boolean {
const permissions =
this.reflector.getAllAndOverride<string[]>(
'permissions',
[
context.getHandler(),
context.getClass(),
],
);
if (!permissions) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
return permissions.every(permission =>
user.permissions.includes(permission),
);
}
}
@@ -0,0 +1,12 @@
modules/identity/application/
Penjelasan:
Layer application berisi use-case (services/commands/queries) yang mengorkestrasi domain dan infrastruktur.
Contoh file:
- services/get-user.service.ts
- commands/create-user.command.ts
Aturan:
- Application service boleh memanggil repository interface, domain services, dan event publisher.
- Application menangani transaksi jika diperlukan.
@@ -0,0 +1,37 @@
import {
Injectable,
ConflictException,
} from '@nestjs/common';
import { CreateUserDto } from '../../presentation/dto/create-user.dto';
import { User } from '../../domain/entities/user.entity';
import { UserRepository } from '../../domain/repositories/user.repository.interface';
@Injectable()
export class CreateUserHandler {
constructor(
private readonly userRepository: UserRepository,
) {}
async execute(dto: CreateUserDto): Promise<User> {
const exists = await this.userRepository.existsByEmail(dto.email);
if (exists) {
throw new ConflictException('Email already exists.');
}
const user = User.create({
name: dto.name,
email: dto.email,
password: dto.password,
metadata: dto.metadata,
});
await this.userRepository.create(user);
// TODO:
// this.eventDispatcher.publish(new UserCreatedEvent(user));
return user;
}
}
@@ -0,0 +1,28 @@
import {
Injectable,
NotFoundException,
} from '@nestjs/common';
import { UserRepository } from '../../domain/repositories/user.repository.interface';
@Injectable()
export class DeleteUserHandler {
constructor(
private readonly userRepository: UserRepository,
) {}
async execute(id: string): Promise<void> {
const user = await this.userRepository.findById(id);
if (!user) {
throw new NotFoundException('User not found.');
}
user.delete();
await this.userRepository.update(user);
// TODO:
// Publish UserDeletedEvent
}
}
@@ -0,0 +1,24 @@
import {
Injectable,
NotFoundException,
} from '@nestjs/common';
import { UserRepository } from '../../domain/repositories/user.repository.interface';
import { User } from '../../domain/entities/user.entity';
@Injectable()
export class FindUserHandler {
constructor(
private readonly userRepository: UserRepository,
) {}
async execute(id: string): Promise<User> {
const user = await this.userRepository.findById(id);
if (!user) {
throw new NotFoundException('User not found.');
}
return user;
}
}
@@ -0,0 +1,15 @@
import { Injectable } from '@nestjs/common';
import { UserRepository } from '../../domain/repositories/user.repository.interface';
import { User } from '../../domain/entities/user.entity';
@Injectable()
export class FindUsersHandler {
constructor(
private readonly userRepository: UserRepository,
) {}
async execute(): Promise<User[]> {
return await this.userRepository.findAll();
}
}
@@ -0,0 +1,51 @@
import {
Injectable,
ConflictException,
NotFoundException,
} from '@nestjs/common';
import { UpdateUserDto } from '../../presentation/dto/update-user.dto';
import { UserRepository } from '../../domain/repositories/user.repository.interface';
import { User } from '../../domain/entities/user.entity';
@Injectable()
export class UpdateUserHandler {
constructor(
private readonly userRepository: UserRepository,
) {}
async execute(
id: string,
dto: UpdateUserDto,
): Promise<User> {
const user = await this.userRepository.findById(id);
if (!user) {
throw new NotFoundException('User not found.');
}
if (
dto.email &&
dto.email !== user.email
) {
const exists =
await this.userRepository.existsByEmail(dto.email);
if (exists) {
throw new ConflictException(
'Email already exists.',
);
}
user.changeEmail(dto.email);
}
if (dto.name) {
user.changeName(dto.name);
}
await this.userRepository.update(user);
return user;
}
}
@@ -0,0 +1,12 @@
services/
Penjelasan:
Application services (use-cases) untuk module identity.
Contoh file:
- get-user.service.ts
- create-user.service.ts
Aturan:
- Application service mengorkestrasi domain services dan repository.
- Menangani transaction boundary jika perlu.
@@ -1,20 +0,0 @@
import { Controller, Get, Param } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { UserService } from '../services/user.service';
@ApiTags('users')
@Controller('api/v1/users')
export class UsersController {
constructor(private readonly userService: UserService) {}
@Get(':id')
@ApiOperation({ summary: 'Get user by id' })
async findById(@Param('id') id: string) {
const data = await this.userService.findById(id);
return {
success: true,
data,
meta: {},
};
}
}
+13
View File
@@ -0,0 +1,13 @@
modules/identity/domain/
Penjelasan:
Layer domain berisi entity, value objects, repository interfaces, domain services, dan domain events.
Contoh file:
- entities/user.entity.ts
- events/user-created.event.ts
- repositories/user.repository.interface.ts
Aturan:
- Semua aturan bisnis inti berada di domain.
- Infrastruktur mengimplementasikan interface yang didefinisikan di domain.
@@ -0,0 +1,11 @@
entities/
Penjelasan:
Entity domain untuk identity, mis. User, Profile.
Contoh file:
- user.entity.ts
- profile.entity.ts
Aturan:
- Entity berisi atribut dan mungkin method domain kecil (invariants), bukan orchestration.
@@ -0,0 +1,52 @@
export class User {
private constructor(
public readonly id: string,
public name: string,
public email: string,
public password: string,
public metadata?: Record<string, any>,
) {}
static create(data: {
name: string;
email: string;
password: string;
metadata?: Record<string, any>;
}): User {
return new User(
crypto.randomUUID(),
data.name,
data.email,
data.password,
data.metadata,
);
}
delete() {
// Business Rule
}
changeEmail(email: string) {
this.email = email;
}
changeName(name: string) {
this.name = name;
}
static restore(data: {
id: string;
name: string;
email: string;
password: string;
metadata?: Record<string, any>;
}): User {
return new User(
data.id,
data.name,
data.email,
data.password,
data.metadata,
);
}
}
@@ -0,0 +1,6 @@
import { DomainEvent } from '../../../../core/events/event.interface';
export class UserCreatedEvent implements DomainEvent {
readonly name = 'UserCreated';
constructor(public readonly payload: any, public readonly occurredAt: Date = new Date()) {}
}
@@ -0,0 +1,6 @@
import { DomainEvent } from '../../../../core/events/event.interface';
export class UserDeletedEvent implements DomainEvent {
readonly name = 'UserDeleted';
constructor(public readonly payload: any, public readonly occurredAt: Date = new Date()) {}
}
@@ -0,0 +1,17 @@
import { User } from '../entities/user.entity';
export abstract class UserRepository {
abstract create(user: User): Promise<User>;
abstract update(user: User): Promise<User>;
abstract findById(
id: string,
): Promise<User | null>;
abstract findAll(): Promise<User[]>;
abstract existsByEmail(
email: string,
): Promise<boolean>;
}
@@ -1 +0,0 @@
// REMOVED: file content deleted per user request
@@ -1 +0,0 @@
// REMOVED: file content deleted per user request
@@ -1,9 +0,0 @@
export class UserEntity {
id: string;
email: string;
displayName: string;
metadata?: Record<string, any>;
createdAt: Date;
updatedAt: Date;
deletedAt?: Date | null;
}
+52 -1
View File
@@ -1 +1,52 @@
// REMOVED: file content deleted per user request
import { Module } from '@nestjs/common';
import { UsersController } from './presentation/controllers/users.controller';
import { PrismaService } from '../../shared/prisma.service';
import { PrismaUserRepository } from './infrastructure/repositories/prisma-user.repository';
import { UserRepository } from './domain/repositories/user.repository.interface';
import { EventDispatcher } from '../../core/events/event-dispatcher';
import { JwtAuthGuard } from '../../core/auth/guards/jwt-auth.guard';
import { JwtModule } from '@nestjs/jwt';
import { CreateUserHandler } from './application/handlers/create-user.handler';
import { FindUserHandler } from './application/handlers/find-user.handler';
import { DeleteUserHandler } from './application/handlers/delete-user.handler';
import { FindUsersHandler } from './application/handlers/find-users.handler';
import { UpdateUserHandler } from './application/handlers/update-user.handler';
import { PermissionGuard } from '../authorization/presentation/guards/permission.guard';
import { Reflector } from '@nestjs/core';
@Module({
imports: [
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: {
expiresIn: '1d',
},
}),
],
controllers: [UsersController],
providers: [
//#region User
CreateUserHandler,
FindUserHandler,
FindUsersHandler,
UpdateUserHandler,
DeleteUserHandler,
//#endregion
JwtAuthGuard,
PermissionGuard,
Reflector,
PrismaService,
PrismaUserRepository,
{
provide: UserRepository,
useClass: PrismaUserRepository,
},
{
provide: 'EVENT_DISPATCHER',
useValue: new EventDispatcher(),
},
],
})
export class IdentityModule {}
@@ -0,0 +1,12 @@
modules/identity/infrastructure/
Penjelasan:
Implementasi teknis untuk module identity, seperti Prisma repository, adapter implementations, dan data mappers.
Contoh file:
- prisma/user.repository.ts (mengimplementasikan domain repository interface)
- adapter/identity-adapter.ts
Aturan:
- Infrastruktur hanya mengimplementasikan interface domain; jangan memuat business rules.
- Import dari infrastructure ke domain harus satu arah: infrastructure -> domain (implementasi).
@@ -0,0 +1,27 @@
import { User } from '../../domain/entities/user.entity';
export class PrismaUserMapper {
static toDomain(model: any): User | null {
if (!model) {
return null;
}
return User.restore({
id: model.id,
name: model.name,
email: model.email,
password: model.password,
metadata: model.metadata,
});
}
static toPersistence(user: User) {
return {
id: user.id,
name: user.name,
email: user.email,
password: user.password,
metadata: user.metadata ?? {},
};
}
}
@@ -0,0 +1,11 @@
repositories/
Penjelasan:
Implementasi repository di layer infrastructure. Biasanya berisi Prisma queries dan mapping antara DB model dan domain entity.
Contoh file:
- prisma/user.repository.ts
Aturan:
- Repository mengimplementasikan interface di domain layer.
- Hindari business logic di repository.
@@ -0,0 +1,64 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../../../shared/prisma.service';
import { UserRepository } from '../../domain/repositories/user.repository.interface';
import { User } from '../../domain/entities/user.entity';
import { PrismaUserMapper } from '../mappers/prisma-user.mapper';
@Injectable()
export class PrismaUserRepository implements UserRepository {
constructor(private readonly prisma: PrismaService) {}
async findById(id: string) {
const user = await this.prisma.user.findUnique({
where: { id },
});
return PrismaUserMapper.toDomain(user);
}
async findAll(): Promise<User[]> {
const users = await this.prisma.user.findMany({
where: { deleted_at: null },
orderBy: { created_at: 'desc' },
});
return users.map(PrismaUserMapper.toDomain);
}
async create(user: User): Promise<User> {
const created = await this.prisma.user.create({
data: PrismaUserMapper.toPersistence(user),
});
return PrismaUserMapper.toDomain(created)!;
}
async update(user: User): Promise<User> {
const updated = await this.prisma.user.update({
where: {
id: user.id,
},
data: PrismaUserMapper.toPersistence(user),
});
return PrismaUserMapper.toDomain(updated)!;
}
async delete(id: string) {
const user = await this.prisma.user.update({
where: { id },
data: { deleted_at: new Date() },
});
return PrismaUserMapper.toDomain(user);
}
async existsByEmail(email: string, excludeId?: string | null) {
const where: any = { email };
if (excludeId) {
where.id = { not: excludeId };
}
const user = await this.prisma.user.findFirst({ where });
return !!user;
}
}
@@ -1,3 +0,0 @@
export interface IUserService {
findById(id: string): Promise<any | null>;
}
@@ -0,0 +1,13 @@
modules/identity/presentation/
Penjelasan:
Layer presentation untuk module identity. Berisi controller, request/response DTO, dan mapping ke HTTP.
Contoh file:
- controllers/users.controller.ts
- dto/create-user.dto.ts
- dto/update-user.dto.ts
Aturan:
- Controller tipis: lakukan validasi DTO dan panggil application service.
- Jangan menaruh business logic di controller.
@@ -0,0 +1,10 @@
controllers/
Penjelasan:
Folder untuk controller HTTP endpoint module identity.
Contoh file:
- users.controller.ts
Aturan:
- Controller hanya menerima request, validasi DTO, panggil application service, kembalikan response.

Some files were not shown because too many files have changed in this diff Show More