@ojokesusu/lintasai 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish-npm.yml +40 -0
- package/.github/workflows/validate.yml +93 -0
- package/AUDIT_POST_SETUP_PROMPT_v1.md +280 -0
- package/BOOTSTRAP_PROJECT_DOCS_PROMPT_v1.md +3 -0
- package/CHANGELOG.md +313 -0
- package/CLAUDE_universal_v1.md +1021 -0
- package/CONTRIBUTING.md +101 -0
- package/FIRST_SESSION_PROMPT_v1.md +7 -0
- package/JALANKAN_KIT.md +188 -0
- package/LICENSE +21 -0
- package/MULAI_DI_SINI.md +145 -0
- package/PROJECT_KICKOFF_PROMPT_v1.md +3 -0
- package/PROJECT_LIFECYCLE_PROMPT_v1.md +536 -0
- package/PROJECT_MIGRATION_PROMPT_v1.md +3 -0
- package/README.md +505 -0
- package/SETUP_POLA_B_PROMPT_v1.md +5 -0
- package/SPLIT_REPO_MIGRATION_PROMPT_v1.md +485 -0
- package/TEAM_ROLLOUT_GUIDE_v1.md +172 -0
- package/UPDATE_DOCS_PROMPT_v1.md +3 -0
- package/UPDATE_KIT_PROMPT_v1.md +213 -0
- package/bin/lintasai.js +81 -0
- package/docs/SIGNED_RELEASE.md +162 -0
- package/install-windows.ps1 +225 -0
- package/kit.ps1 +508 -0
- package/lib/agents-md.ps1 +174 -0
- package/lib/git-helpers.ps1 +104 -0
- package/lib/kit-files.psd1 +133 -0
- package/lib/manifest-signing.ps1 +65 -0
- package/lib/manifest.ps1 +267 -0
- package/lib/rollback.ps1 +241 -0
- package/lib/safety.ps1 +193 -0
- package/lib/template-deploy.ps1 +242 -0
- package/lib/version-detect.ps1 +161 -0
- package/package.json +36 -0
- package/setup-pola-b.ps1 +687 -0
- package/templates/ANALOGI_LIBRARY.md +7 -0
- package/templates/CLAUDE_TEAM_GUIDE.md +505 -0
- package/templates/CROSS_REPO_TYPES_PIPELINE.md +473 -0
- package/templates/DB_SCHEMA_SCAN_PROMPT.md +194 -0
- package/templates/DISCORD_BOT_INTEGRATION.md +187 -0
- package/templates/GLOSSARY_NON_PROGRAMMER.md +361 -0
- package/templates/INDEX.md +157 -0
- package/templates/MCP_SETUP.md +1145 -0
- package/templates/MIGRATE_TO_SUBFOLDER_PROMPT_v1.md +220 -0
- package/templates/ONBOARDING.md +172 -0
- package/templates/PROJECT_STARTER_TEMPLATES.md +264 -0
- package/templates/PROMPT_LIBRARY.md +790 -0
- package/templates/RLS_SETUP_PROMPT.md +167 -0
- package/templates/SECURITY_INCIDENT_PLAYBOOK.md +191 -0
- package/templates/SPLIT_REPO_AGENTS_TEMPLATES.md +32 -0
- package/templates/SPLIT_REPO_NON_PROGRAMMER_PROMPTS.md +604 -0
- package/templates/SPLIT_REPO_TOOLS_SETUP.md +388 -0
- package/templates/STACK_DETECTION_PATTERN.md +261 -0
- package/templates/STACK_GUIDE.md +564 -0
- package/templates/STACK_MIGRATION_GUIDE.md +154 -0
- package/templates/STACK_VERSIONS.md +31 -0
- package/templates/UPDATE_GUIDE.md +246 -0
- package/templates/_EXAMPLE.md +110 -0
- package/templates/_PATTERNS.md +173 -0
- package/templates/architecture.md +180 -0
- package/templates/architecture_auto.md +61 -0
- package/templates/decisions/README.md +108 -0
- package/templates/decisions/_TEMPLATE.md +84 -0
- package/templates/feature-flags-advanced.md +171 -0
- package/templates/github/CODEOWNERS.template +61 -0
- package/templates/github/GENERATE_TYPES_SCRIPT.md +77 -0
- package/templates/github/PUBLISH_SHARED_WORKFLOW.yml +52 -0
- package/templates/github/RECEIVE_BACKEND_UPDATE.yml +106 -0
- package/templates/github/RENOVATE_FRONTEND.json +28 -0
- package/templates/github/TRIGGER_FRONTEND_UPDATE.yml +29 -0
- package/templates/github/pull_request_template.md +44 -0
- package/templates/github/scripts/ai-review.js +153 -0
- package/templates/github/workflows/ai-review.yml +61 -0
- package/templates/github/workflows/backup-schemas.yml +169 -0
- package/templates/glossary.md +110 -0
- package/templates/split-agents/BACKEND.md +149 -0
- package/templates/split-agents/FRONTEND.md +141 -0
- package/templates/split-agents/SHARED.md +82 -0
- package/templates/split-agents/TOOLS.md +77 -0
- package/tests/Run-Tests.ps1 +19 -0
- package/tests/lib-safety.Tests.ps1 +66 -0
- package/tests/rollback.Tests.ps1 +66 -0
- package/tests/uninstall.Tests.ps1 +265 -0
- package/tests/update-kit.Tests.ps1 +78 -0
- package/uninstall.ps1 +794 -0
- package/update-kit.ps1 +907 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Feature Flag Pattern (ADVANCED — Post-Launch Only)
|
|
2
|
+
|
|
3
|
+
> ⚠️ **JANGAN PAKAI FILE INI DI EARLY-STAGE PROJECT (progress <50% / belum launch ke user nyata).**
|
|
4
|
+
>
|
|
5
|
+
> Default workflow tim = **staging-only** (Vercel Preview per PR). Lihat `CLAUDE_TEAM_GUIDE.md` section 7b (Risk Level Decision Tree).
|
|
6
|
+
>
|
|
7
|
+
> File ini cuma dipakai **post-launch** kalau project sudah punya user aktif dan butuh:
|
|
8
|
+
> - Kill switch instant untuk fitur kritis (mis. payment toggle saat Black Friday)
|
|
9
|
+
> - A/B test gradual rollout (10% → 50% → 100%)
|
|
10
|
+
> - Per-user targeting (beta tester subset)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Filosofi: Kapan UPGRADE dari Staging-Only ke Feature Flag?
|
|
15
|
+
|
|
16
|
+
Project pertama kali = simpler is better. Tambah complexity HANYA kalau ada **pain point konkret**, bukan karena "best practice di tutorial".
|
|
17
|
+
|
|
18
|
+
### Sinyal kamu butuh feature flag (post-launch):
|
|
19
|
+
|
|
20
|
+
| Sinyal | Contoh |
|
|
21
|
+
|---|---|
|
|
22
|
+
| Rollback `git revert` sudah TIDAK cukup cepat | Bug payment terdeteksi jam 11 malam, butuh kill switch <30 detik (bukan 5 menit redeploy) |
|
|
23
|
+
| Butuh test fitur ke subset user dulu | Beta launch ke 100 user terpilih sebelum public |
|
|
24
|
+
| Butuh A/B test resmi | "Versi A vs Versi B landing page, monitor conversion 2 minggu" |
|
|
25
|
+
| Butuh deploy kode tapi launch terpisah | Code deploy sekarang, launch announcement minggu depan |
|
|
26
|
+
|
|
27
|
+
Kalau **tidak ada** sinyal di atas → **STAY di staging-only**. Feature flag tanpa pain point = premature optimization.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Implementasi: Env Var Vercel
|
|
32
|
+
|
|
33
|
+
Simple feature flag pakai env var Vercel (no library tambahan):
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// lib/flags.ts
|
|
37
|
+
export const flags = {
|
|
38
|
+
newDashboard: process.env.NEXT_PUBLIC_FF_NEW_DASHBOARD === 'true',
|
|
39
|
+
betaPayment: process.env.FF_BETA_PAYMENT === 'true', // server-only
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Pakai di Server Component
|
|
43
|
+
import { flags } from '@/lib/flags'
|
|
44
|
+
|
|
45
|
+
export default function Page() {
|
|
46
|
+
if (flags.newDashboard) return <NewDashboard />
|
|
47
|
+
return <OldDashboard />
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Naming Convention
|
|
52
|
+
|
|
53
|
+
Semua flag wajib pakai prefix `NEXT_PUBLIC_FF_<AREA>_<NAMA>`:
|
|
54
|
+
- `FF` = Feature Flag
|
|
55
|
+
- `<AREA>` = domain (mis. `BILLING`, `INBOX`, `AUTH`)
|
|
56
|
+
- `<NAMA>` = nama fitur snake-uppercase
|
|
57
|
+
|
|
58
|
+
Contoh: `NEXT_PUBLIC_FF_BILLING_NEW_PRICING`, `NEXT_PUBLIC_FF_INBOX_V2_FILTER`.
|
|
59
|
+
|
|
60
|
+
**Wajib di-comment di kode** dengan tanggal lahir + target hapus:
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
// FLAG: NEXT_PUBLIC_FF_INBOX_V2_FILTER
|
|
64
|
+
// Created: 2026-06-15
|
|
65
|
+
// Target removal: 2026-07-15 (setelah 100% rollout 2 minggu stabil)
|
|
66
|
+
const showNewFilter = process.env.NEXT_PUBLIC_FF_INBOX_V2_FILTER === 'true';
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Gradual Rollout
|
|
72
|
+
|
|
73
|
+
1. Set `NEXT_PUBLIC_FF_NEW_DASHBOARD=false` di Production → fitur tersembunyi.
|
|
74
|
+
2. Set `NEXT_PUBLIC_FF_NEW_DASHBOARD=true` di Preview → tim QA test.
|
|
75
|
+
3. Saat siap launch → ubah Production env var ke `true` → redeploy 2-5 menit.
|
|
76
|
+
4. Setelah 1-2 minggu stabil → hapus flag, code path lama dihapus (lihat **Cleanup Ritual**).
|
|
77
|
+
|
|
78
|
+
> Prefix `NEXT_PUBLIC_` = ter-expose ke browser. Untuk flag rahasia (mis. feature internal), pakai env var tanpa prefix → cek di Server Component/Action only.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Per-User Flag (Canary Rollout)
|
|
83
|
+
|
|
84
|
+
Kalau butuh rollout ke 10% user random (bukan all-or-nothing), pakai hash deterministik dari userId. Jangan pakai `Math.random()` (user bakal kelap-kelip).
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { cookies } from 'next/headers'
|
|
88
|
+
import { createHash } from 'crypto'
|
|
89
|
+
|
|
90
|
+
export function isNewDashboardEnabled() {
|
|
91
|
+
const userId = cookies().get('userId')?.value ?? ''
|
|
92
|
+
if (!userId) return false
|
|
93
|
+
|
|
94
|
+
// sha256 = distribusi merata + stabil per userId
|
|
95
|
+
const hash = createHash('sha256').update(userId).digest('hex')
|
|
96
|
+
const bucket = parseInt(hash.slice(0, 4), 16) % 100
|
|
97
|
+
return bucket < 10 // 10% user
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> **Kenapa sha256?** Charcode sum (`'abc'` → 97+98+99 = 294) gampang collision. Sha256 merata & tahan collision.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Cleanup Ritual (Cegah Flag Debt)
|
|
106
|
+
|
|
107
|
+
Flag yang sudah "selesai" tapi dibiarkan = **flag debt** (kode penuh `if (flag) {}` zombie).
|
|
108
|
+
|
|
109
|
+
Aturan:
|
|
110
|
+
1. **1-2 minggu setelah flag = `true` stabil di prod tanpa bug**:
|
|
111
|
+
- Bikin PR baru: hapus pemanggilan env var dari kode (else branch lama dihapus).
|
|
112
|
+
- Hapus env var dari Vercel dashboard (Settings → Environment Variables → Delete) di semua environment.
|
|
113
|
+
2. **Quarterly ritual**: review flag yang `Target removal`-nya lewat. Grep `NEXT_PUBLIC_FF_` di kode + cocokkan dengan Vercel dashboard.
|
|
114
|
+
|
|
115
|
+
> Rule of thumb: **kalau flag sudah lebih lama dari fitur yang dilindunginya, itu flag debt.**
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Testing Flag
|
|
120
|
+
|
|
121
|
+
Tiap flag wajib minimal 2 unit test (case ON + case OFF):
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { vi, describe, it, expect, afterEach } from 'vitest'
|
|
125
|
+
import { isNewDashboardEnabled } from '@/lib/flags'
|
|
126
|
+
|
|
127
|
+
describe('flag NEXT_PUBLIC_FF_NEW_DASHBOARD', () => {
|
|
128
|
+
afterEach(() => vi.unstubAllEnvs())
|
|
129
|
+
|
|
130
|
+
it('flag ON → render path baru', () => {
|
|
131
|
+
vi.stubEnv('NEXT_PUBLIC_FF_NEW_DASHBOARD', 'true')
|
|
132
|
+
expect(isNewDashboardEnabled()).toBe(true)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('flag OFF → render path lama', () => {
|
|
136
|
+
vi.stubEnv('NEXT_PUBLIC_FF_NEW_DASHBOARD', 'false')
|
|
137
|
+
expect(isNewDashboardEnabled()).toBe(false)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('flag undefined → default OFF (fail-safe)', () => {
|
|
141
|
+
vi.stubEnv('NEXT_PUBLIC_FF_NEW_DASHBOARD', '')
|
|
142
|
+
expect(isNewDashboardEnabled()).toBe(false)
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Trade-off Penting (Sebelum Pakai Flag)
|
|
150
|
+
|
|
151
|
+
| Aspek | Implikasi |
|
|
152
|
+
|---|---|
|
|
153
|
+
| **NEXT_PUBLIC_ vs server-only** | Keduanya butuh redeploy Vercel saat flip (~2-5 menit). Tidak instant. |
|
|
154
|
+
| **Staff access** | Staff tanpa akses Vercel TIDAK bisa toggle flag. Flag = owner-only operation. |
|
|
155
|
+
| **Code complexity** | Kode jadi bercabang (`if/else`). Susah review, susah test full coverage. |
|
|
156
|
+
| **Maintenance** | Wajib cleanup flag yang sudah stabil (else jadi flag debt). |
|
|
157
|
+
|
|
158
|
+
Kalau butuh **instant toggle (sub-detik) tanpa redeploy** → migrasi ke **DB-backed flag** (Prisma `FeatureFlag` table + Server Action dengan cache TTL pendek). Tapi itu kompleksitas extra lagi — pertimbangkan dengan matang.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Aktivasi Workflow Feature Flag (Saat Siap Post-Launch)
|
|
163
|
+
|
|
164
|
+
Saat project sudah launch dan kamu mau pakai feature flag default:
|
|
165
|
+
|
|
166
|
+
1. Update `CLAUDE_TEAM_GUIDE.md` section 7b: tambah sub-section "Decision Tree Branch + Flag" (lihat git history kit, sebelum stripped).
|
|
167
|
+
2. Update `PROMPT_LIBRARY.md` Prompt 11: tambah field `[Flag?]` di template task.
|
|
168
|
+
3. Update `AGENTS.md` proyek: tambah link ke file ini di section "Workflow & Komunikasi Task".
|
|
169
|
+
4. Setup channel Slack/Discord untuk announce tiap flag flip (transparency).
|
|
170
|
+
|
|
171
|
+
Atau: PR ke kit `lintasAI` untuk re-enable flag workflow di default kit (kalau team udah scale 20+).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# .github/CODEOWNERS.template
|
|
2
|
+
# Template GitHub CODEOWNERS
|
|
3
|
+
#
|
|
4
|
+
# Cara pakai:
|
|
5
|
+
# 1. Copy file ini jadi `.github/CODEOWNERS` (tanpa `.template`).
|
|
6
|
+
# 2. Ganti SEMUA placeholder `<...>` dengan GitHub username aktual (huruf kecil, prefix `@`).
|
|
7
|
+
# 3. Commit. GitHub otomatis request review ke owner saat ada PR yang sentuh file terkait.
|
|
8
|
+
#
|
|
9
|
+
# Sintaks: <pola-path> @user1 @user2
|
|
10
|
+
# Pola lebih spesifik (di bawah) menang dari pola umum (di atas).
|
|
11
|
+
# Dokumentasi resmi: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
|
12
|
+
|
|
13
|
+
# ── Default owner (fallback untuk semua file yang tidak match rule lain) ──
|
|
14
|
+
* @<owner-username>
|
|
15
|
+
|
|
16
|
+
# ── Area sensitif: auth & payment wajib reviewer senior ──
|
|
17
|
+
/src/auth/ @<senior-dev>
|
|
18
|
+
/src/auth/** @<senior-dev>
|
|
19
|
+
/src/payment/ @<senior-dev>
|
|
20
|
+
/src/payment/** @<senior-dev>
|
|
21
|
+
|
|
22
|
+
# ── Dokumentasi: owner + tech writer ──
|
|
23
|
+
/docs/ @<owner-username> @<tech-writer>
|
|
24
|
+
/docs/** @<owner-username> @<tech-writer>
|
|
25
|
+
|
|
26
|
+
# ── Infra CI/CD & meta repo: cuma owner ──
|
|
27
|
+
/.github/ @<owner-username>
|
|
28
|
+
/.github/** @<owner-username>
|
|
29
|
+
|
|
30
|
+
# ── Konfigurasi env & secret-ish (kalau ada) ──
|
|
31
|
+
/.env.example @<owner-username> @<senior-dev>
|
|
32
|
+
|
|
33
|
+
# ──────────────────────────────────────────────────────────────────
|
|
34
|
+
# CONTOH POLA UNTUK SPLIT 2-TIER (Frontend / Backend / Shared)
|
|
35
|
+
# ──────────────────────────────────────────────────────────────────
|
|
36
|
+
# Pakai pola ini kalau proyek pakai monorepo dengan apps/ folder
|
|
37
|
+
# (atau adaptasi pattern path-nya kalau pakai split-repo terpisah).
|
|
38
|
+
#
|
|
39
|
+
# Konvensi 2-tier:
|
|
40
|
+
# - Frontend Staff (4 orang): akses Frontend area + Shared (CRUD via API, no DDL)
|
|
41
|
+
# - Backend Staff (2 orang): akses semua area (full DB control + DDL)
|
|
42
|
+
# - Owner: fallback reviewer untuk semua area
|
|
43
|
+
|
|
44
|
+
# Frontend area — Frontend + Backend + owner boleh review
|
|
45
|
+
/apps/frontend/ @<frontend1> @<frontend2> @<frontend3> @<frontend4> @<backend1> @<backend2> @<owner-username>
|
|
46
|
+
/apps/frontend/** @<frontend1> @<frontend2> @<frontend3> @<frontend4> @<backend1> @<backend2> @<owner-username>
|
|
47
|
+
|
|
48
|
+
# Backend area — Backend + owner saja (Frontend Staff dikecualikan)
|
|
49
|
+
/apps/backend/ @<backend1> @<backend2> @<owner-username>
|
|
50
|
+
/apps/backend/** @<backend1> @<backend2> @<owner-username>
|
|
51
|
+
|
|
52
|
+
# Shared area (types + zod schema) — semua staff + owner
|
|
53
|
+
/apps/shared/ @<frontend1> @<frontend2> @<frontend3> @<frontend4> @<backend1> @<backend2> @<owner-username>
|
|
54
|
+
/apps/shared/** @<frontend1> @<frontend2> @<frontend3> @<frontend4> @<backend1> @<backend2> @<owner-username>
|
|
55
|
+
|
|
56
|
+
# CATATAN:
|
|
57
|
+
# - Username harus member repo dengan minimal write access supaya bisa dipanggil sebagai reviewer.
|
|
58
|
+
# - Hapus baris yang tidak relevan untuk proyekmu.
|
|
59
|
+
# - Jangan commit file ini dalam keadaan masih ada placeholder `<...>` — CI akan menolak.
|
|
60
|
+
# - Kalau pakai split-repo (3 repo terpisah, bukan monorepo): salin pola di atas ke CODEOWNERS
|
|
61
|
+
# repo masing-masing, tanpa prefix `/apps/<area>/` — cukup pakai `*` per repo.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Auto Types Generation Setup
|
|
2
|
+
|
|
3
|
+
## Backend repo: package.json scripts
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"scripts": {
|
|
8
|
+
"generate:types": "prisma generate && tsup --config tsup.shared.config.ts",
|
|
9
|
+
"build:shared": "tsup --config tsup.shared.config.ts",
|
|
10
|
+
"publish:shared:dry": "cd shared-dist && npm publish --dry-run",
|
|
11
|
+
"publish:shared": "cd shared-dist && npm publish"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## tsup.shared.config.ts
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { defineConfig } from 'tsup'
|
|
20
|
+
import pkg from './shared-package.json'
|
|
21
|
+
|
|
22
|
+
export default defineConfig({
|
|
23
|
+
entry: ['src/shared/index.ts'],
|
|
24
|
+
format: ['esm', 'cjs'],
|
|
25
|
+
dts: true,
|
|
26
|
+
outDir: 'shared-dist',
|
|
27
|
+
clean: true,
|
|
28
|
+
external: ['@prisma/client'],
|
|
29
|
+
onSuccess: 'cp shared-package.json shared-dist/package.json',
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## shared-package.json (template untuk @<project>/shared)
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"name": "@<project>/shared",
|
|
38
|
+
"version": "1.0.0",
|
|
39
|
+
"main": "./index.js",
|
|
40
|
+
"module": "./index.mjs",
|
|
41
|
+
"types": "./index.d.ts",
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"registry": "https://npm.pkg.github.com"
|
|
44
|
+
},
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/<owner>/<project>-backend.git"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"zod": "^3.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## src/shared/index.ts (manual maintained)
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Re-export selective Prisma types (yang aman di-share)
|
|
59
|
+
export type { User, Order, Platform } from '@prisma/client'
|
|
60
|
+
|
|
61
|
+
// Re-export domain types
|
|
62
|
+
export * from './schemas/user'
|
|
63
|
+
export * from './schemas/tracking'
|
|
64
|
+
|
|
65
|
+
// Common API wrappers
|
|
66
|
+
export type ApiResponse<T> =
|
|
67
|
+
| { data: T; meta?: Record<string, any> }
|
|
68
|
+
| { error: string; code?: string }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Verify
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm run generate:types
|
|
75
|
+
ls shared-dist/
|
|
76
|
+
# Should output: index.js, index.mjs, index.d.ts, package.json
|
|
77
|
+
```
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: Publish @<project>/shared
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- 'prisma/schema.prisma'
|
|
8
|
+
- 'src/shared/**'
|
|
9
|
+
- 'package.json'
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
contents: write
|
|
17
|
+
packages: write
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
- uses: actions/setup-node@v4
|
|
23
|
+
with:
|
|
24
|
+
node-version: '20'
|
|
25
|
+
registry-url: 'https://npm.pkg.github.com'
|
|
26
|
+
scope: '@<project>'
|
|
27
|
+
- run: npm ci
|
|
28
|
+
- name: Generate types
|
|
29
|
+
run: npm run generate:types
|
|
30
|
+
- name: Bump version
|
|
31
|
+
run: |
|
|
32
|
+
cd shared-dist
|
|
33
|
+
npm version patch -m 'chore(shared): bump version [skip ci]'
|
|
34
|
+
- name: Publish to GitHub Packages
|
|
35
|
+
env:
|
|
36
|
+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
37
|
+
run: |
|
|
38
|
+
cd shared-dist
|
|
39
|
+
npm publish
|
|
40
|
+
- name: Notify Discord
|
|
41
|
+
if: env.DISCORD_WEBHOOK_DEPS != ''
|
|
42
|
+
env:
|
|
43
|
+
DISCORD_WEBHOOK_DEPS: ${{ secrets.DISCORD_WEBHOOK_DEPS }}
|
|
44
|
+
run: |
|
|
45
|
+
VERSION=$(node -p "require('./shared-dist/package.json').version")
|
|
46
|
+
MESSAGE=$(printf '{"content":"🔔 **@<project>/shared v%s published**\\nFrontend tim: PR Renovate akan masuk dalam 24 jam, atau manual \`npm install @<project>/shared@latest\` untuk segera dapat update.\\nChangelog: https://github.com/<owner>/<project>-backend/commits/main"}' "$VERSION")
|
|
47
|
+
curl -X POST -H 'Content-Type: application/json' -d "$MESSAGE" "$DISCORD_WEBHOOK_DEPS"
|
|
48
|
+
- name: Push version commit
|
|
49
|
+
run: |
|
|
50
|
+
git config user.name 'github-actions[bot]'
|
|
51
|
+
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
|
52
|
+
git push
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
name: Receive @<project>/shared update (Real-time)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
repository_dispatch:
|
|
5
|
+
types: [shared-package-published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
update:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
contents: write
|
|
12
|
+
pull-requests: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: '20'
|
|
21
|
+
registry-url: 'https://npm.pkg.github.com'
|
|
22
|
+
scope: '@<project>'
|
|
23
|
+
|
|
24
|
+
- name: Install new shared version
|
|
25
|
+
env:
|
|
26
|
+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
27
|
+
run: |
|
|
28
|
+
npm install @<project>/shared@${{ github.event.client_payload.version }}
|
|
29
|
+
|
|
30
|
+
- name: Check if breaking change
|
|
31
|
+
id: breaking
|
|
32
|
+
run: |
|
|
33
|
+
IS_BREAKING="${{ github.event.client_payload.is_breaking }}"
|
|
34
|
+
if [ "$IS_BREAKING" = "true" ]; then
|
|
35
|
+
echo "is_breaking=true" >> $GITHUB_OUTPUT
|
|
36
|
+
echo "WARNING: This is a BREAKING change. Manual review required."
|
|
37
|
+
else
|
|
38
|
+
echo "is_breaking=false" >> $GITHUB_OUTPUT
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
- name: Create PR
|
|
42
|
+
id: cpr
|
|
43
|
+
uses: peter-evans/create-pull-request@v6
|
|
44
|
+
with:
|
|
45
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
46
|
+
commit-message: "chore(deps): bump @<project>/shared to v${{ github.event.client_payload.version }}"
|
|
47
|
+
title: "${{ steps.breaking.outputs.is_breaking == 'true' && '⚠️ BREAKING' || '🔄 Auto' }}-update @<project>/shared to v${{ github.event.client_payload.version }}"
|
|
48
|
+
body: |
|
|
49
|
+
**Triggered by**: Backend publish (real-time)
|
|
50
|
+
**Version**: v${{ github.event.client_payload.version }}
|
|
51
|
+
**Breaking**: ${{ github.event.client_payload.is_breaking }}
|
|
52
|
+
**Backend commit**: [`${{ github.event.client_payload.commit }}`](${{ github.event.client_payload.changelog_url }})
|
|
53
|
+
|
|
54
|
+
## Backend Commit Message
|
|
55
|
+
\`\`\`
|
|
56
|
+
${{ github.event.client_payload.commit_message }}
|
|
57
|
+
\`\`\`
|
|
58
|
+
|
|
59
|
+
## Action Required
|
|
60
|
+
|
|
61
|
+
**Untuk Frontend Staff**:
|
|
62
|
+
1. Pull branch ini di local
|
|
63
|
+
2. Test halaman yang affected (kalau yakin breaking change)
|
|
64
|
+
3. Approve + merge kalau OK
|
|
65
|
+
|
|
66
|
+
**Untuk Owner (if BREAKING)**:
|
|
67
|
+
- JANGAN auto-merge
|
|
68
|
+
- Review backend commit dulu
|
|
69
|
+
- Test di staging
|
|
70
|
+
- Plan rollback kalau perlu
|
|
71
|
+
|
|
72
|
+
## Auto-Generated
|
|
73
|
+
Latency: 3-5 menit dari backend publish.
|
|
74
|
+
Workflow: `.github/workflows/receive-shared-update.yml`
|
|
75
|
+
branch: auto/shared-update-${{ github.event.client_payload.version }}
|
|
76
|
+
delete-branch: true
|
|
77
|
+
labels: |
|
|
78
|
+
auto-update
|
|
79
|
+
shared-types
|
|
80
|
+
${{ steps.breaking.outputs.is_breaking == 'true' && 'breaking-change' || '' }}
|
|
81
|
+
|
|
82
|
+
- name: Notify Discord (optional)
|
|
83
|
+
if: env.DISCORD_WEBHOOK_FRONTEND != ''
|
|
84
|
+
env:
|
|
85
|
+
DISCORD_WEBHOOK_FRONTEND: ${{ secrets.DISCORD_WEBHOOK_FRONTEND }}
|
|
86
|
+
run: |
|
|
87
|
+
if [ "${{ steps.breaking.outputs.is_breaking }}" = "true" ]; then
|
|
88
|
+
EMOJI=":warning:"
|
|
89
|
+
TITLE="BREAKING change PR ready"
|
|
90
|
+
else
|
|
91
|
+
EMOJI=":arrows_counterclockwise:"
|
|
92
|
+
TITLE="Auto-update PR ready"
|
|
93
|
+
fi
|
|
94
|
+
curl -X POST -H 'Content-Type: application/json' \\
|
|
95
|
+
-d "{\"content\":\"$EMOJI **$TITLE**\\n@<project>/shared v${{ github.event.client_payload.version }}\\nPR: ${{ steps.cpr.outputs.pull-request-url }}\"}" \\
|
|
96
|
+
"$DISCORD_WEBHOOK_FRONTEND"
|
|
97
|
+
|
|
98
|
+
# Setup:
|
|
99
|
+
# Save sebagai .github/workflows/receive-shared-update.yml di FRONTEND repo (akses-frontend).
|
|
100
|
+
# Default secrets (no setup needed):
|
|
101
|
+
# - GITHUB_TOKEN (auto-provided by GitHub Actions)
|
|
102
|
+
# Optional secret untuk Discord:
|
|
103
|
+
# - DISCORD_WEBHOOK_FRONTEND
|
|
104
|
+
#
|
|
105
|
+
# Replace placeholder:
|
|
106
|
+
# - <project> → project name (e.g. akses)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
+
"extends": ["config:recommended"],
|
|
4
|
+
"schedule": ["after 9am every weekday"],
|
|
5
|
+
"timezone": "Asia/Jakarta",
|
|
6
|
+
"labels": ["renovate"],
|
|
7
|
+
"packageRules": [
|
|
8
|
+
{
|
|
9
|
+
"matchPackageNames": ["@<project>/shared"],
|
|
10
|
+
"schedule": ["at any time"],
|
|
11
|
+
"automerge": false,
|
|
12
|
+
"groupName": "shared package",
|
|
13
|
+
"reviewers": ["<owner-username>"],
|
|
14
|
+
"labels": ["auto-update", "shared-types"],
|
|
15
|
+
"minimumReleaseAge": "5 minutes"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"matchDepTypes": ["devDependencies"],
|
|
19
|
+
"minimumReleaseAge": "7 days"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"vulnerabilityAlerts": {
|
|
23
|
+
"enabled": true,
|
|
24
|
+
"labels": ["security"]
|
|
25
|
+
},
|
|
26
|
+
"rangeStrategy": "bump",
|
|
27
|
+
"rebaseWhen": "behind-base-branch"
|
|
28
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Append to .github/workflows/publish-shared.yml di akses-backend
|
|
2
|
+
# Trigger frontend repo untuk auto-update setelah publish
|
|
3
|
+
|
|
4
|
+
# Step ini ditambahkan SETELAH "Publish to GitHub Packages" + "Notify Discord"
|
|
5
|
+
|
|
6
|
+
- name: Trigger frontend repo update (real-time)
|
|
7
|
+
uses: peter-evans/repository-dispatch@v3
|
|
8
|
+
with:
|
|
9
|
+
token: ${{ secrets.FRONTEND_REPO_DISPATCH_TOKEN }}
|
|
10
|
+
repository: <owner>/<project>-frontend
|
|
11
|
+
event-type: shared-package-published
|
|
12
|
+
client-payload: |
|
|
13
|
+
{
|
|
14
|
+
"version": "${{ env.NEW_VERSION }}",
|
|
15
|
+
"commit": "${{ github.sha }}",
|
|
16
|
+
"commit_message": ${{ toJson(github.event.head_commit.message) }},
|
|
17
|
+
"changelog_url": "https://github.com/<owner>/<project>-backend/commits/main",
|
|
18
|
+
"is_breaking": "${{ contains(github.event.head_commit.message, 'BREAKING') }}"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Setup:
|
|
22
|
+
# 1. Generate PAT di GitHub > Settings > Developer settings > Personal access tokens (classic)
|
|
23
|
+
# 2. Scope: repo (full) + workflow
|
|
24
|
+
# 3. Save as: FRONTEND_REPO_DISPATCH_TOKEN
|
|
25
|
+
# 4. Tambah ke backend repo > Settings > Secrets > Actions
|
|
26
|
+
#
|
|
27
|
+
# Replace placeholder:
|
|
28
|
+
# - <owner> → GitHub username/org (e.g. ojokesusu)
|
|
29
|
+
# - <project> → project name (e.g. akses)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
.github/pull_request_template.md — template PR tim AI-first
|
|
3
|
+
Isi semua section di bawah. Yang tidak relevan: tulis "-" jangan dihapus.
|
|
4
|
+
Bahasa: Indonesia. Singkat, padat, konkret.
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
## Ringkasan
|
|
8
|
+
<!-- 1-3 kalimat: apa yang PR ini lakukan, dalam bahasa manusia. -->
|
|
9
|
+
|
|
10
|
+
## Kenapa
|
|
11
|
+
<!-- Link issue / task ID / keputusan. Contoh: Closes #123, ref TASK-456, diskusi di docs/decisions/2026-xx-xx.md -->
|
|
12
|
+
|
|
13
|
+
## Apa yang berubah
|
|
14
|
+
<!-- Bulleted list perubahan utama. Fokus ke "what", bukan baris kode. -->
|
|
15
|
+
-
|
|
16
|
+
-
|
|
17
|
+
-
|
|
18
|
+
|
|
19
|
+
## Cara verifikasi
|
|
20
|
+
<!-- Langkah konkret supaya reviewer (atau AI) bisa reproduce hasilnya. -->
|
|
21
|
+
1.
|
|
22
|
+
2.
|
|
23
|
+
3.
|
|
24
|
+
|
|
25
|
+
## Risk + Rollback
|
|
26
|
+
<!-- Risiko paling mungkin + cara balikin kalau ternyata bermasalah di produksi.
|
|
27
|
+
Tulis "-" kalau PR-nya pure docs/refactor tanpa risk. -->
|
|
28
|
+
- Risk:
|
|
29
|
+
- Rollback:
|
|
30
|
+
|
|
31
|
+
## Checklist
|
|
32
|
+
- [ ] Commit pakai **Conventional Commits** (`feat:`, `fix:`, `chore:`, `docs:`, dll.)
|
|
33
|
+
- [ ] File `.md` terkait di `docs/` sudah diupdate (sesuai aturan AUTO-SYNC kit)
|
|
34
|
+
- [ ] Edge case sudah dipikirkan (input kosong, null, error network, race)
|
|
35
|
+
- [ ] Sudah manual test di **preview URL** / lokal (sertakan link kalau ada)
|
|
36
|
+
- [ ] Kalau ada perubahan UI: **screenshot before/after** dilampirkan di bawah
|
|
37
|
+
- [ ] Tidak ada secret / API key / data sensitif yang ke-commit
|
|
38
|
+
- [ ] Reuse komponen yang sudah ada (cek `src/components/` & `docs/_PATTERNS.md`)
|
|
39
|
+
|
|
40
|
+
## Screenshot (kalau UI berubah)
|
|
41
|
+
<!-- Drag & drop gambar di sini. Hapus section ini kalau bukan perubahan UI. -->
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
<sub>Senior AI Reviewer akan otomatis posting review di PR ini. Tetap tunggu review manusia untuk perubahan kritis (auth, payment, migrasi DB).</sub>
|