@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.
Files changed (86) hide show
  1. package/.github/workflows/publish-npm.yml +40 -0
  2. package/.github/workflows/validate.yml +93 -0
  3. package/AUDIT_POST_SETUP_PROMPT_v1.md +280 -0
  4. package/BOOTSTRAP_PROJECT_DOCS_PROMPT_v1.md +3 -0
  5. package/CHANGELOG.md +313 -0
  6. package/CLAUDE_universal_v1.md +1021 -0
  7. package/CONTRIBUTING.md +101 -0
  8. package/FIRST_SESSION_PROMPT_v1.md +7 -0
  9. package/JALANKAN_KIT.md +188 -0
  10. package/LICENSE +21 -0
  11. package/MULAI_DI_SINI.md +145 -0
  12. package/PROJECT_KICKOFF_PROMPT_v1.md +3 -0
  13. package/PROJECT_LIFECYCLE_PROMPT_v1.md +536 -0
  14. package/PROJECT_MIGRATION_PROMPT_v1.md +3 -0
  15. package/README.md +505 -0
  16. package/SETUP_POLA_B_PROMPT_v1.md +5 -0
  17. package/SPLIT_REPO_MIGRATION_PROMPT_v1.md +485 -0
  18. package/TEAM_ROLLOUT_GUIDE_v1.md +172 -0
  19. package/UPDATE_DOCS_PROMPT_v1.md +3 -0
  20. package/UPDATE_KIT_PROMPT_v1.md +213 -0
  21. package/bin/lintasai.js +81 -0
  22. package/docs/SIGNED_RELEASE.md +162 -0
  23. package/install-windows.ps1 +225 -0
  24. package/kit.ps1 +508 -0
  25. package/lib/agents-md.ps1 +174 -0
  26. package/lib/git-helpers.ps1 +104 -0
  27. package/lib/kit-files.psd1 +133 -0
  28. package/lib/manifest-signing.ps1 +65 -0
  29. package/lib/manifest.ps1 +267 -0
  30. package/lib/rollback.ps1 +241 -0
  31. package/lib/safety.ps1 +193 -0
  32. package/lib/template-deploy.ps1 +242 -0
  33. package/lib/version-detect.ps1 +161 -0
  34. package/package.json +36 -0
  35. package/setup-pola-b.ps1 +687 -0
  36. package/templates/ANALOGI_LIBRARY.md +7 -0
  37. package/templates/CLAUDE_TEAM_GUIDE.md +505 -0
  38. package/templates/CROSS_REPO_TYPES_PIPELINE.md +473 -0
  39. package/templates/DB_SCHEMA_SCAN_PROMPT.md +194 -0
  40. package/templates/DISCORD_BOT_INTEGRATION.md +187 -0
  41. package/templates/GLOSSARY_NON_PROGRAMMER.md +361 -0
  42. package/templates/INDEX.md +157 -0
  43. package/templates/MCP_SETUP.md +1145 -0
  44. package/templates/MIGRATE_TO_SUBFOLDER_PROMPT_v1.md +220 -0
  45. package/templates/ONBOARDING.md +172 -0
  46. package/templates/PROJECT_STARTER_TEMPLATES.md +264 -0
  47. package/templates/PROMPT_LIBRARY.md +790 -0
  48. package/templates/RLS_SETUP_PROMPT.md +167 -0
  49. package/templates/SECURITY_INCIDENT_PLAYBOOK.md +191 -0
  50. package/templates/SPLIT_REPO_AGENTS_TEMPLATES.md +32 -0
  51. package/templates/SPLIT_REPO_NON_PROGRAMMER_PROMPTS.md +604 -0
  52. package/templates/SPLIT_REPO_TOOLS_SETUP.md +388 -0
  53. package/templates/STACK_DETECTION_PATTERN.md +261 -0
  54. package/templates/STACK_GUIDE.md +564 -0
  55. package/templates/STACK_MIGRATION_GUIDE.md +154 -0
  56. package/templates/STACK_VERSIONS.md +31 -0
  57. package/templates/UPDATE_GUIDE.md +246 -0
  58. package/templates/_EXAMPLE.md +110 -0
  59. package/templates/_PATTERNS.md +173 -0
  60. package/templates/architecture.md +180 -0
  61. package/templates/architecture_auto.md +61 -0
  62. package/templates/decisions/README.md +108 -0
  63. package/templates/decisions/_TEMPLATE.md +84 -0
  64. package/templates/feature-flags-advanced.md +171 -0
  65. package/templates/github/CODEOWNERS.template +61 -0
  66. package/templates/github/GENERATE_TYPES_SCRIPT.md +77 -0
  67. package/templates/github/PUBLISH_SHARED_WORKFLOW.yml +52 -0
  68. package/templates/github/RECEIVE_BACKEND_UPDATE.yml +106 -0
  69. package/templates/github/RENOVATE_FRONTEND.json +28 -0
  70. package/templates/github/TRIGGER_FRONTEND_UPDATE.yml +29 -0
  71. package/templates/github/pull_request_template.md +44 -0
  72. package/templates/github/scripts/ai-review.js +153 -0
  73. package/templates/github/workflows/ai-review.yml +61 -0
  74. package/templates/github/workflows/backup-schemas.yml +169 -0
  75. package/templates/glossary.md +110 -0
  76. package/templates/split-agents/BACKEND.md +149 -0
  77. package/templates/split-agents/FRONTEND.md +141 -0
  78. package/templates/split-agents/SHARED.md +82 -0
  79. package/templates/split-agents/TOOLS.md +77 -0
  80. package/tests/Run-Tests.ps1 +19 -0
  81. package/tests/lib-safety.Tests.ps1 +66 -0
  82. package/tests/rollback.Tests.ps1 +66 -0
  83. package/tests/uninstall.Tests.ps1 +265 -0
  84. package/tests/update-kit.Tests.ps1 +78 -0
  85. package/uninstall.ps1 +794 -0
  86. package/update-kit.ps1 +907 -0
@@ -0,0 +1,564 @@
1
+ # templates/STACK_GUIDE.md — Panduan Stack Standar Tim AI-first
2
+
3
+ > Versi 1 · 2026-06-01
4
+
5
+ ---
6
+
7
+ ## 1. Pengantar
8
+
9
+ File ini = **panduan opinionated** untuk stack standar tim AI-first.
10
+ Target stack default:
11
+
12
+ - **Frontend + Backend** → Next.js (lihat STACK_VERSIONS.md untuk versi terbaru) (App Router) + TypeScript 5+
13
+ - **Hosting primary** → Vercel (deploy auto dari Git)
14
+ - **Database** → Supabase (PostgreSQL managed)
15
+ - **UI** → Tailwind 4 + shadcn/ui
16
+ - **Future migration path** → Railway / Render (kalau butuh background worker native atau biaya Vercel kelebihan)
17
+
18
+ ### Filosofi opinionated
19
+
20
+ - **Satu cara untuk satu hal** — jangan campur Pages Router & App Router, jangan campur Server Action & client-fetch untuk mutation.
21
+ - **Server-first** — default Server Component, baru ke Client kalau butuh interaktivitas.
22
+ - **Vendor-aware tapi tidak vendor-locked** — pakai Vercel sampai mahal, lalu pindah ke Railway/Render. Jangan pakai fitur Vercel-only kalau ada padanan portable.
23
+ - **AI-first** — semua konvensi di file ini juga dibaca AI tiap sesi → AI nulis kode yang konsisten tanpa user perlu ulang-ulang aturan.
24
+
25
+ > *Opinionated* = punya pendapat tegas soal cara kerja. Lawannya *unopinionated* (bebas pilih cara apa saja, tapi tim jadi berantakan).
26
+
27
+ ---
28
+
29
+ ## 2. Next.js App Router Convention
30
+
31
+ ### 2.1. Server Component vs Client Component
32
+
33
+ **Default = Server Component** (tanpa `'use client'` di atas file).
34
+
35
+ Kapan pakai `'use client'`:
36
+
37
+ | Butuh | Pakai `'use client'`? |
38
+ |--------------------------------------------------|------------------------|
39
+ | `useState`, `useEffect`, `useRef` | YA |
40
+ | Event handler (`onClick`, `onChange`, `onSubmit`)| YA |
41
+ | Browser API (`window`, `localStorage`, `navigator`) | YA |
42
+ | Library client-only (mis. Framer Motion, Chart.js) | YA |
43
+ | Cuma render data dari DB / API | TIDAK (Server saja) |
44
+ | Form static (pakai Server Action) | TIDAK (Server saja) |
45
+
46
+ **Pola yang benar**: Server Component sebagai *shell*, Client Component sebagai *island* interaktif kecil.
47
+
48
+ ```tsx
49
+ // app/dashboard/page.tsx — Server Component (default)
50
+ import { db } from '@/lib/db'
51
+ import { LikeButton } from './like-button' // ini Client
52
+
53
+ export default async function DashboardPage() {
54
+ const posts = await db.post.findMany() // fetch langsung di Server
55
+
56
+ return (
57
+ <div>
58
+ {posts.map((post) => (
59
+ <article key={post.id}>
60
+ <h2>{post.title}</h2>
61
+ <LikeButton postId={post.id} /> {/* island interaktif */}
62
+ </article>
63
+ ))}
64
+ </div>
65
+ )
66
+ }
67
+ ```
68
+
69
+ ```tsx
70
+ // app/dashboard/like-button.tsx — Client Component
71
+ 'use client'
72
+ import { useState } from 'react'
73
+
74
+ export function LikeButton({ postId }: { postId: string }) {
75
+ const [liked, setLiked] = useState(false)
76
+ return <button onClick={() => setLiked(!liked)}>{liked ? '♥' : '♡'}</button>
77
+ }
78
+ ```
79
+
80
+ ### 2.2. Data Fetching
81
+
82
+ **WAJIB**: fetch data di **Server Component** pakai `async/await` langsung.
83
+ **JANGAN**: pakai `useEffect` + `fetch` di Client Component untuk initial data.
84
+
85
+ ```tsx
86
+ // BENAR — Server Component
87
+ export default async function Page() {
88
+ const data = await fetch('https://api.example.com/data', {
89
+ next: { revalidate: 60 } // ISR: re-fetch tiap 60 detik
90
+ }).then(r => r.json())
91
+ return <div>{data.title}</div>
92
+ }
93
+
94
+ // SALAH — useEffect di Client Component untuk initial data
95
+ 'use client'
96
+ export default function Page() {
97
+ const [data, setData] = useState(null)
98
+ useEffect(() => { fetch('...').then(...) }, []) // loading spinner, SEO buruk
99
+ }
100
+ ```
101
+
102
+ Kapan pakai client-fetch (`SWR`, `React Query`, `useEffect+fetch`): **hanya** kalau data harus auto-refresh per interval atau triggered by user action setelah halaman load.
103
+
104
+ ### 2.3. Metadata SEO
105
+
106
+ Setiap route export `metadata` (static) atau `generateMetadata` (dynamic).
107
+
108
+ ```tsx
109
+ // Static metadata
110
+ export const metadata = {
111
+ title: 'Dashboard | Akses',
112
+ description: 'Panel admin proyek akses.',
113
+ openGraph: {
114
+ title: 'Dashboard | Akses',
115
+ description: 'Panel admin proyek akses.',
116
+ images: ['/og-dashboard.png'],
117
+ },
118
+ }
119
+
120
+ // Dynamic metadata (per slug / per ID)
121
+ export async function generateMetadata({ params }: { params: { slug: string } }) {
122
+ const post = await db.post.findUnique({ where: { slug: params.slug } })
123
+ return {
124
+ title: `${post.title} | Akses`,
125
+ description: post.excerpt,
126
+ openGraph: { images: [post.coverImage] },
127
+ }
128
+ }
129
+ ```
130
+
131
+ Di `app/layout.tsx` root, set default site-wide:
132
+
133
+ ```tsx
134
+ export const metadata = {
135
+ metadataBase: new URL('https://akses.app'),
136
+ title: { default: 'Akses', template: '%s | Akses' },
137
+ description: 'Manajemen akses & dashboard.',
138
+ robots: { index: true, follow: true },
139
+ }
140
+ ```
141
+
142
+ ### 2.4. Form & Mutation
143
+
144
+ **WAJIB**: pakai **Server Action** untuk semua mutation (create, update, delete).
145
+ **JANGAN**: pakai client `fetch('/api/...', { method: 'POST' })` untuk form internal.
146
+
147
+ ```tsx
148
+ // app/posts/new/page.tsx — form static + Server Action
149
+ import { createPost } from './actions'
150
+
151
+ export default function NewPostPage() {
152
+ return (
153
+ <form action={createPost}>
154
+ <input name="title" required />
155
+ <textarea name="content" required />
156
+ <button type="submit">Simpan</button>
157
+ </form>
158
+ )
159
+ }
160
+ ```
161
+
162
+ ```tsx
163
+ // app/posts/new/actions.ts — Server Action
164
+ 'use server'
165
+ import { redirect } from 'next/navigation'
166
+ import { db } from '@/lib/db'
167
+ import { revalidatePath } from 'next/cache'
168
+
169
+ export async function createPost(formData: FormData) {
170
+ const title = formData.get('title') as string
171
+ const content = formData.get('content') as string
172
+
173
+ // validasi (pakai Zod di produksi)
174
+ if (!title || title.length < 3) throw new Error('Title min 3 char')
175
+
176
+ await db.post.create({ data: { title, content } })
177
+ revalidatePath('/posts')
178
+ redirect('/posts')
179
+ }
180
+ ```
181
+
182
+ Kalau butuh feedback interaktif (loading, error) di form → wrap dengan Client Component pakai `useActionState` (React 19).
183
+
184
+ ### 2.5. Loading & Error State (File Convention)
185
+
186
+ Next.js App Router auto-render file ini di tiap route segment:
187
+
188
+ ```text
189
+ app/
190
+ ├── dashboard/
191
+ │ ├── page.tsx // halaman utama
192
+ │ ├── loading.tsx // muncul saat page.tsx masih loading data
193
+ │ ├── error.tsx // muncul kalau page.tsx throw error
194
+ │ └── not-found.tsx // muncul kalau notFound() dipanggil
195
+ ```
196
+
197
+ ```tsx
198
+ // app/dashboard/loading.tsx
199
+ export default function Loading() {
200
+ return <div className="animate-pulse">Memuat data...</div>
201
+ }
202
+
203
+ // app/dashboard/error.tsx — WAJIB 'use client'
204
+ 'use client'
205
+ export default function Error({ error, reset }: { error: Error; reset: () => void }) {
206
+ return (
207
+ <div>
208
+ <h2>Ada error</h2>
209
+ <p>{error.message}</p>
210
+ <button onClick={reset}>Coba lagi</button>
211
+ </div>
212
+ )
213
+ }
214
+ ```
215
+
216
+ ### 2.6. Image & Font Optimization
217
+
218
+ **Gambar**: pakai `next/image` (auto-resize, lazy-load, AVIF/WebP).
219
+
220
+ ```tsx
221
+ import Image from 'next/image'
222
+
223
+ <Image
224
+ src="/hero.jpg"
225
+ alt="Hero proyek akses"
226
+ width={1200}
227
+ height={600}
228
+ priority // untuk above-the-fold (LCP)
229
+ />
230
+ ```
231
+
232
+ **Font**: pakai `next/font` (self-hosted, no layout shift, no FOUT).
233
+
234
+ ```tsx
235
+ // app/layout.tsx
236
+ import { Inter } from 'next/font/google'
237
+
238
+ const inter = Inter({ subsets: ['latin'], display: 'swap' })
239
+
240
+ export default function RootLayout({ children }) {
241
+ return (
242
+ <html lang="id" className={inter.className}>
243
+ <body>{children}</body>
244
+ </html>
245
+ )
246
+ }
247
+ ```
248
+
249
+ ---
250
+
251
+ ## 3. Vercel Setup (Primary Hosting)
252
+
253
+ ### 3.1. Connect Repo
254
+
255
+ 1. Login https://vercel.com pakai akun GitHub tim.
256
+ 2. **Add New → Project** → pilih repo dari GitHub.
257
+ 3. Framework Preset: **Next.js** (auto-detect).
258
+ 4. Root directory: `./` (kecuali monorepo).
259
+ 5. Build command default: `next build` (jangan ganti kecuali perlu).
260
+
261
+ ### 3.2. Environment Variables (Production / Preview / Development)
262
+
263
+ Vercel punya 3 environment terpisah:
264
+
265
+ | Env | Kapan dipakai |
266
+ |-------------|------------------------------------------------------|
267
+ | Production | Deploy dari branch `main` (= public domain) |
268
+ | Preview | Deploy auto per PR / branch lain (= URL random) |
269
+ | Development | Saat `vercel dev` lokal (jarang dipakai) |
270
+
271
+ **WAJIB**: split env vars per environment. Production pakai DB produksi, Preview pakai DB staging (kalau ada).
272
+
273
+ Contoh isi env vars di dashboard Vercel:
274
+
275
+ ```text
276
+ Production:
277
+ DATABASE_URL = postgresql://...@prod-db.supabase.co:6543/postgres
278
+ NEXT_PUBLIC_SITE_URL = https://akses.app
279
+
280
+ Preview:
281
+ DATABASE_URL = postgresql://...@staging-db.supabase.co:6543/postgres
282
+ NEXT_PUBLIC_SITE_URL = https://akses-preview.vercel.app
283
+ ```
284
+
285
+ Variabel `NEXT_PUBLIC_*` = ter-expose ke browser (jangan taruh secret di sini). Tanpa prefix = server-only.
286
+
287
+ ### 3.3. Custom Domain + SSL
288
+
289
+ 1. Project Settings → **Domains** → Add domain (mis. `akses.app`).
290
+ 2. Update DNS di registrar: tambah record `A` ke `76.76.21.21` atau `CNAME` ke `cname.vercel-dns.com`.
291
+ 3. SSL otomatis (Let's Encrypt) — tunggu 1-5 menit.
292
+ 4. Tambah subdomain `www` → set redirect ke apex (atau sebaliknya).
293
+
294
+ ### 3.4. Edge Function (untuk Middleware)
295
+
296
+ File `middleware.ts` di root → otomatis jalan di Edge Runtime (cepat, deploy global).
297
+
298
+ ```ts
299
+ // middleware.ts — proteksi route /dashboard
300
+ import { NextResponse } from 'next/server'
301
+ import type { NextRequest } from 'next/server'
302
+
303
+ export function middleware(req: NextRequest) {
304
+ const token = req.cookies.get('session')?.value
305
+ if (!token && req.nextUrl.pathname.startsWith('/dashboard')) {
306
+ return NextResponse.redirect(new URL('/login', req.url))
307
+ }
308
+ return NextResponse.next()
309
+ }
310
+
311
+ export const config = { matcher: ['/dashboard/:path*'] }
312
+ ```
313
+
314
+ ### 3.5. Web Analytics + Speed Insights
315
+
316
+ Gratis di plan Hobby. Wajib pasang untuk SEO + Core Web Vitals monitoring.
317
+
318
+ ```bash
319
+ npm i @vercel/analytics @vercel/speed-insights
320
+ ```
321
+
322
+ ```tsx
323
+ // app/layout.tsx
324
+ import { Analytics } from '@vercel/analytics/react'
325
+ import { SpeedInsights } from '@vercel/speed-insights/next'
326
+
327
+ export default function RootLayout({ children }) {
328
+ return (
329
+ <html>
330
+ <body>
331
+ {children}
332
+ <Analytics />
333
+ <SpeedInsights />
334
+ </body>
335
+ </html>
336
+ )
337
+ }
338
+ ```
339
+
340
+ Aktifkan di dashboard: Project → Analytics → Enable; Speed Insights → Enable.
341
+
342
+ ### 3.6. Preview Deploy Workflow
343
+
344
+ - Push ke branch apa saja (kecuali `main`) → Vercel auto-deploy **Preview** dengan URL unik (mis. `akses-git-feat-login-team.vercel.app`).
345
+ - Buka PR di GitHub → Vercel bot auto-comment URL Preview.
346
+ - QA test di Preview URL, kalau OK → merge ke `main`.
347
+
348
+ ### 3.7. Production Deploy
349
+
350
+ - Merge PR ke `main` → Vercel auto-deploy ke Production (domain custom).
351
+ - Deploy time biasanya 30-90 detik (Next.js + Tailwind).
352
+ - Build log lengkap di dashboard → Project → Deployments → klik deployment.
353
+
354
+ ### 3.8. Rollback
355
+
356
+ Kalau production rusak setelah deploy:
357
+
358
+ 1. Dashboard → Project → **Deployments**.
359
+ 2. Cari deployment lama yang stabil.
360
+ 3. Klik `...` (tiga titik) → **Promote to Production**.
361
+ 4. Selesai dalam <10 detik — traffic langsung pindah ke deployment lama.
362
+
363
+ > Rollback **tidak** memutar balik DB. Kalau migrasi DB sudah jalan, rollback aplikasi saja bisa bikin error skema. Solusi: pakai migrasi backward-compatible (additive only).
364
+
365
+ ---
366
+
367
+ ## 4. Migration ke Railway / Render (Advanced --- Post-Launch)
368
+
369
+ > Default tim = **Vercel saja**. Section ini cuma jadi pointer.
370
+
371
+ Migrasi ke Railway atau Render = **operasi advanced** yang baru relevan kalau salah satu kondisi ini terjadi: (a) bill Vercel sudah lewat budget (mis. >$100/bulan untuk satu project), atau (b) butuh **background worker persistent** / **WebSocket long-lived** yang tidak cocok di model serverless Vercel. Untuk Day 0--1 staff IT non-programmer: **abaikan section ini**, pakai Vercel + Supabase saja. Detail step-by-step setup (provision, env vars, Dockerfile, worker, cron, healthcheck) ada di **`templates/STACK_MIGRATION_GUIDE.md`** --- file terpisah supaya STACK_GUIDE tetap fokus ke default workflow. Decision Matrix vendor (Vercel vs Railway vs Render) tetap dipertahankan di section 9 sebagai bahan pertimbangan kapan harus migrasi.
372
+
373
+ ---
374
+
375
+ ## 6. SEO Checklist Mandatory
376
+
377
+ Kategori prioritas:
378
+
379
+ - **P0** = WAJIB pre-launch. Tanpa ini, situs tidak ter-index Google atau muncul broken.
380
+ - **P1** = affect ranking. Boleh nyusul minggu pertama setelah launch.
381
+ - **P2** = boost ranking. Optimasi lanjutan, nice-to-have.
382
+
383
+ ### P0 (wajib pre-launch)
384
+
385
+ - [ ] `metadata.title` & `metadata.description` di tiap route (bukan default Next.js).
386
+ - [ ] `metadataBase` di root `layout.tsx` (untuk URL absolut di OG image).
387
+ - [ ] `robots.txt` di `app/robots.ts` atau `public/robots.txt` — pastikan **tidak** disallow `/` di production.
388
+ - [ ] `sitemap.xml` di `app/sitemap.ts` (Next.js auto-generate dari array).
389
+ - [ ] `lang="id"` (atau bahasa sesuai target) di tag `<html>`.
390
+ - [ ] Canonical URL di metadata (`alternates: { canonical: '...' }`) untuk halaman dengan query string.
391
+ - [ ] HTTPS aktif (Vercel auto, tidak perlu config).
392
+ - [ ] No `noindex` accidental di production (cek `robots` meta tag).
393
+
394
+ ### P1 (affect ranking)
395
+
396
+ - [ ] Open Graph image (`og-image.png`, 1200x630px) per route penting.
397
+ - [ ] Structured data (JSON-LD) untuk artikel, produk, FAQ (pakai `<script type="application/ld+json">`).
398
+ - [ ] Alt text di semua `<Image>` (jangan kosong, jangan filename mentah).
399
+ - [ ] Heading hierarchy benar (`h1` satu per halaman, `h2/h3` ter-nest logis).
400
+ - [ ] Internal linking antar-halaman (anchor text deskriptif, bukan "klik di sini").
401
+ - [ ] Core Web Vitals: LCP <2.5s, CLS <0.1, INP <200ms (monitor via Speed Insights).
402
+ - [ ] Mobile responsive (test di Chrome DevTools device mode).
403
+
404
+ ### P2 (boost ranking)
405
+
406
+ - [ ] Breadcrumb structured data.
407
+ - [ ] FAQ structured data di halaman dengan Q&A.
408
+ - [ ] Page speed: convert image ke AVIF/WebP (next/image auto-handle).
409
+ - [ ] Preconnect ke domain eksternal sering dipakai (`<link rel="preconnect" href="https://fonts.googleapis.com">`).
410
+ - [ ] Lazy-load iframe (YouTube embed, map).
411
+ - [ ] hreflang tag kalau multi-bahasa.
412
+
413
+ Contoh `app/robots.ts`:
414
+
415
+ ```ts
416
+ import type { MetadataRoute } from 'next'
417
+
418
+ export default function robots(): MetadataRoute.Robots {
419
+ return {
420
+ rules: { userAgent: '*', allow: '/', disallow: ['/admin/', '/api/'] },
421
+ sitemap: 'https://akses.app/sitemap.xml',
422
+ }
423
+ }
424
+ ```
425
+
426
+ Contoh `app/sitemap.ts`:
427
+
428
+ ```ts
429
+ import type { MetadataRoute } from 'next'
430
+ import { db } from '@/lib/db'
431
+
432
+ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
433
+ const posts = await db.post.findMany({ select: { slug: true, updatedAt: true } })
434
+ return [
435
+ { url: 'https://akses.app', lastModified: new Date(), priority: 1 },
436
+ ...posts.map(p => ({
437
+ url: `https://akses.app/post/${p.slug}`,
438
+ lastModified: p.updatedAt,
439
+ priority: 0.8,
440
+ })),
441
+ ]
442
+ }
443
+ ```
444
+
445
+ ---
446
+
447
+ ## 7. Security Checklist
448
+
449
+ ### 7.1. Env Vars
450
+
451
+ - [ ] Tidak ada secret hard-coded di repo (cek pakai `gitleaks` atau `truffleHog`).
452
+ - [ ] `.env.local` di `.gitignore`.
453
+ - [ ] Secret di Vercel env vars di-mark **Sensitive** (icon mata) — encrypted at rest.
454
+ - [ ] `NEXT_PUBLIC_*` cuma untuk data yang aman ke browser (URL, feature flag boolean) — JANGAN API key, JANGAN service_role_key.
455
+ - [ ] Rotate secret tiap quarter atau saat staff keluar.
456
+
457
+ ### 7.2. Auth
458
+
459
+ - [ ] Session token via cookie `HttpOnly` + `Secure` + `SameSite=Lax`.
460
+ - [ ] Password hash pakai `bcrypt` (cost ≥10) atau `argon2`. JANGAN MD5/SHA1.
461
+ - [ ] CSRF protection di Server Action (Next.js handle by default via origin check, tapi kalau cross-domain → tambah token manual).
462
+ - [ ] Rate limit login endpoint (`@upstash/ratelimit` atau Vercel Edge Config).
463
+ - [ ] Lock account setelah 5 percobaan gagal (15 menit).
464
+
465
+ ### 7.3. DB Connection
466
+
467
+ - [ ] Pakai **connection pooling** Supabase (`port 6543`, mode `transaction`) untuk serverless Vercel.
468
+ - [ ] JANGAN expose `service_role_key` ke client — itu bypass RLS.
469
+ - [ ] Pakai `anon_key` (limited) di browser, `service_role_key` di Server Action saja.
470
+ - [ ] Row-Level Security (RLS) aktif di semua tabel publik.
471
+
472
+ ### 7.4. CSP Header
473
+
474
+ Content Security Policy mencegah XSS injection.
475
+
476
+ ```ts
477
+ // next.config.js
478
+ module.exports = {
479
+ async headers() {
480
+ return [{
481
+ source: '/(.*)',
482
+ headers: [
483
+ { key: 'X-Frame-Options', value: 'DENY' },
484
+ { key: 'X-Content-Type-Options', value: 'nosniff' },
485
+ { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
486
+ { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
487
+ { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
488
+ ],
489
+ }]
490
+ },
491
+ }
492
+ ```
493
+
494
+ ---
495
+
496
+ ## 8. Feature Flag Pattern (ADVANCED — Post-Launch Only)
497
+
498
+ > ⚠️ **Default workflow tim TIDAK pakai feature flag.** Untuk early-stage project (belum launch / progress <50%), staging via **Vercel Preview Deploy per PR** sudah cukup. Lihat `CLAUDE_TEAM_GUIDE.md` section 7b (Risk Level Decision Tree) untuk default workflow.
499
+ >
500
+ > Feature flag = advanced operation yang butuh owner familiar dengan Vercel env vars + redeploy cycle. **Tambahkan post-launch** kalau project sudah punya user aktif dan butuh:
501
+ > - Kill switch instant untuk fitur kritis (mis. payment toggle saat Black Friday)
502
+ > - A/B test gradual rollout (10% → 50% → 100%)
503
+ > - Per-user targeting (beta tester subset)
504
+
505
+ Detail implementasi lengkap (decision tree, naming convention, cleanup ritual, testing pattern, per-user hash) di **`./.claude-kit/templates/feature-flags-advanced.md`** — file terpisah supaya tidak ngebebanin kit default workflow.
506
+
507
+ **Untuk early-stage akses (progress ~5%)**: skip section ini, pakai Risk Level (CLAUDE_TEAM_GUIDE.md 7b) + staging-only.
508
+
509
+ ---
510
+
511
+ ## 9. Decision Matrix: Vercel vs Railway vs Render
512
+
513
+ | Aspek | Vercel | Railway | Render |
514
+ |---------------------------------|-----------------------|----------------------|----------------------|
515
+ | **Setup speed** | ★★★★★ (auto Next.js) | ★★★★ (Nixpacks) | ★★★ (manual config) |
516
+ | **DX (Developer Experience)** | ★★★★★ | ★★★★ | ★★★ |
517
+ | **Preview deploy per PR** | YA (default) | YA (default) | YA (paid plan) |
518
+ | **Background worker persistent**| TIDAK (serverless) | YA | YA |
519
+ | **Cron native** | Vercel Cron (Pro+) | YA (gratis) | YA (gratis) |
520
+ | **WebSocket / SSE long-lived** | Terbatas (Edge) | YA | YA |
521
+ | **PostgreSQL bundled** | TIDAK (pakai Supabase)| YA (plugin) | YA (managed) |
522
+ | **Pricing transparency** | ★★★ (function invoke) | ★★★★ (per-resource) | ★★★★★ (flat) |
523
+ | **Free tier (small project)** | Hobby gratis cukup | $5 credit/bulan | Free 750 jam/bulan |
524
+ | **Vendor lock-in** | Tinggi (Edge runtime) | Rendah (Docker) | Rendah (Docker) |
525
+ | **Best untuk** | Marketing site, SaaS, dashboard | App butuh worker / WS | Stabilitas + predictable |
526
+
527
+ ### Rekomendasi default
528
+
529
+ - **0 → MVP**: Vercel (deploy 5 menit, gratis).
530
+ - **MVP → 1000 user**: Tetap Vercel, monitor cost. Pakai Supabase untuk DB.
531
+ - **1000 → 10k user**: Cek bill Vercel. Kalau >$100/bulan & butuh worker → pindah ke Railway.
532
+ - **Enterprise / butuh on-premise**: Render (lebih konservatif) atau self-host Docker.
533
+
534
+ ---
535
+
536
+ ## 10. Checklist Pre-Launch
537
+
538
+ Sebelum announce launch produksi:
539
+
540
+ - [ ] Semua P0 SEO terisi (section 6).
541
+ - [ ] Semua Security checklist terisi (section 7).
542
+ - [ ] Speed Insights + Analytics aktif.
543
+ - [ ] Custom domain + SSL aktif (bukan `.vercel.app`).
544
+ - [ ] Rollback plan dipahami (section 3.8).
545
+ - [ ] Backup DB Supabase aktif (Settings → Database → Backups).
546
+ - [ ] Error monitoring (Sentry / Vercel logs) aktif.
547
+ - [ ] Healthcheck endpoint `/api/health` ada (untuk uptime monitor).
548
+ - [ ] Robots & sitemap di-submit ke Google Search Console.
549
+ - [ ] Feature flag default = stable path (rollout fitur baru bertahap).
550
+
551
+ ---
552
+
553
+ ## Referensi Eksternal
554
+
555
+ - Next.js App Router docs: https://nextjs.org/docs/app
556
+ - Vercel docs: https://vercel.com/docs
557
+ - Railway docs: https://docs.railway.app
558
+ - Render docs: https://render.com/docs
559
+ - Google Search Central (SEO): https://developers.google.com/search
560
+ - Web.dev (Core Web Vitals): https://web.dev/vitals
561
+
562
+ ---
563
+
564
+ > **Update file ini** tiap kali tim ganti vendor, ganti versi major Next.js, atau ada keputusan stack baru. Catat di `CHANGELOG.md` kit + bump versi.