# Membuat Mini App dengan Masuk <Badge type="warning" text="Belum dirilis" />

Langkah dari nol sampai Mini App yang memasukkan seseorang dengan akun Micromeet-nya, lalu memanggil Micromeet atas nama orang itu dari backend-nya sendiri. Setiap fungsi dijelaskan di [Masuk](https://docs.micromeet.ai/id/miniapp-sdk/auth.md), pengemasan di [Pengemasan dan Tanda Tangan](https://docs.micromeet.ai/id/miniapp-sdk/build.md), dan semua aturan paket di [Spesifikasi Paket](https://docs.micromeet.ai/id/miniapp-sdk/package-spec.md).

## Alur lengkap

Siapa melakukan apa, dari build pertama sampai seseorang membuka Mini App:

```mermaid
flowchart TB
  subgraph dev["Anda"]
    build["vite build<br/>miniapp-package/"]
    verify["micromeet-miniapp verify"]
    zip["micromeet-miniapp zip<br/>zip bertanda tangan"]
    file["sajikan file verifikasi<br/>di domain backend"]
  end
  subgraph mm["Micromeet"]
    reg["daftarkan AppID<br/>client secret per region"]
    dom["verifikasi domain server"]
    sign["daftarkan dan tandatangani versi<br/>memeriksa setiap file dan domain"]
  end
  subgraph cw["Cowork"]
    install["pasang"]
    open{"tanda tangan valid<br/>dan file tidak berubah?"}
    run["buka Mini App"]
    refuse["belum tersertifikasi:<br/>tidak dibuka"]
  end
  reg --> file --> dom
  build --> verify --> sign
  dom --> sign
  sign -->|manifest.json bertanda tangan| zip --> install --> open
  open -->|ya| run
  open -->|tidak| refuse
```

Cowork memeriksa tanda tangan setiap kali membuka, dan setiap file setiap kali halaman membacanya; file yang berubah membuat Mini App ditutup.

Proses masuk, setelah orang itu mengklik tombol Anda:

```mermaid
sequenceDiagram
  actor P as Pengguna
  participant Page as Halaman
  participant C as Cowork
  participant M as Micromeet
  participant B as Backend Anda
  P->>Page: klik Masuk
  Page->>C: auth.login()
  C->>M: Mini App apa ini, apa yang boleh diminta
  C->>P: kartu (pertama kali): Mini App, scope, akun
  P->>C: Izinkan
  C->>M: code untuk versi dan orang ini
  Note over M: AppID aktif, versi terdaftar,<br/>file sama, domain server terverifikasi, scope diizinkan
  M-->>C: code (5 menit, sekali pakai)
  C-->>Page: code dan region
  Page->>B: code dan region
  B->>M: code dan client secret
  M-->>B: access token, refresh token, user.ref
  B->>M: profile dengan access token
  M-->>B: nama, email, institusi
  B-->>Page: sesi Anda sendiri
```

Halaman tidak pernah melihat kata sandi, token, atau client secret. Langkah-langkah di bawah membangun setiap bagiannya.

## 1. Minta Micromeet mendaftarkan Mini App

Tidak ada pendaftaran mandiri. Kirim ke Micromeet:

| Apa | Contoh |
|---|---|
| AppID: domain terbalik huruf kecil | `ai.example.app` |
| Nama (bahasa Inggris; Mandarin opsional) dan pengembang | Example · Example Ltd |
| Scope yang dibutuhkan Mini App | `profile:read` |
| Region orang-orang yang akan masuk (SG, HK, ID) | HK |
| Origin backend Anda | `https://api.example.com` |

Untuk setiap region Anda menerima **client secret** yang hanya ditampilkan sekali: simpan di penyimpanan rahasia backend. Untuk setiap origin Anda menerima file verifikasi (langkah 2).

## 2. Buktikan domain backend milik Anda

Sajikan file itu di `https://api.example.com/micromeet-miniapp-<16 karakter>.txt` lewat HTTPS dengan status 200 dan tanpa redirect, lalu biarkan tetap di sana; Micromeet mengambilnya untuk memverifikasi domain. Selama pengembangan backend bisa berjalan di `http://localhost:<port>` atau `http://127.0.0.1:<port>`, yang tidak perlu file di region yang diizinkan Micromeet. Lihat [Domain server](https://docs.micromeet.ai/id/miniapp-sdk/build.md#domain-server).

## 3. Tulis halaman

Pasang `@micromeet-ai/miniapp-sdk` (lihat [Pengemasan dan Tanda Tangan](https://docs.micromeet.ai/id/miniapp-sdk/build.md)), lalu:

```js
import { maestroSdk } from '@micromeet-ai/miniapp-sdk';

const BACKEND = 'https://api.example.com';      // domain server yang sudah diverifikasi

export async function signIn() {
  const sdk = maestroSdk();                     // null di luar Cowork
  if (!sdk?.auth) return { error: 'open_in_cowork' };
  const login = await sdk.auth.login({ scopes: ['profile:read'] });
  if (!login.ok) return { error: login.error };
  const response = await fetch(`${BACKEND}/login`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code: login.code, region: login.region })
  });
  return response.json();                       // { session, name }: kirim session di request berikutnya
}
```

- Panggil `auth.login()` saat orang itu mengklik: Cowork menampilkan kartunya hanya di tab yang sedang dilihat.
- `auth.status()` memberi tahu apakah paket bertanda tangan dan apakah ada yang masuk ke Cowork; pakai untuk menampilkan atau menyembunyikan tombol.
- Taruh setiap skrip di file: `<script>` inline tidak berjalan.

## 4. Tulis backend

Backend Node.js minimal:

```js
import { createServer } from 'node:http';
import { randomUUID } from 'node:crypto';
import { createMiniappAuthClient, MiniappAuthError } from '@micromeet-ai/miniapp-sdk/server';

const APP_ID = 'ai.example.app';
const PAGE = `miniapp://${APP_ID}`;             // origin halaman
// Satu client per region, masing-masing dengan secret region itu.
const clients = { HK: createMiniappAuthClient({ appId: APP_ID, clientSecret: process.env.MINIAPP_SECRET_HK }) };
const sessions = new Map();                     // simpan di database Anda

const reply = (res, status, body) => {
  res.writeHead(status, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': PAGE, Vary: 'Origin' });
  res.end(JSON.stringify(body));
};

createServer((req, res) => {
  if (req.method === 'OPTIONS') {
    res.writeHead(204, { 'Access-Control-Allow-Origin': PAGE, 'Access-Control-Allow-Methods': 'POST', 'Access-Control-Allow-Headers': 'Content-Type, Authorization' });
    return res.end();
  }
  if (req.method !== 'POST' || req.url !== '/login') return reply(res, 404, { error: 'not_found' });
  let raw = '';
  req.on('data', (part) => (raw += part));
  req.on('end', async () => {
    try {
      const { code, region } = JSON.parse(raw);
      const auth = clients[region];
      if (!auth) return reply(res, 400, { error: 'region_not_supported' });
      const tokens = await auth.exchangeCode({ code, region });
      const session = randomUUID();
      sessions.set(session, { ref: tokens.user.ref, region, refreshToken: tokens.refreshToken });
      reply(res, 200, { session, name: tokens.user.name });
    } catch (error) {
      reply(res, 400, { error: error instanceof MiniappAuthError ? error.code : 'bad_request' });
    }
  });
}).listen(8787);
```

- Jawab dengan `Access-Control-Allow-Origin: miniapp://<appId>`: itulah origin halaman, dan tanpa header itu request gagal di halaman sebelum sampai ke kode Anda.
- Gunakan `user.ref` sebagai kunci pengguna, simpan refresh token, dan ambil token baru dengan `refresh` saat Anda memanggil Micromeet nanti.
- Halaman hanya mendapat sesi Anda sendiri; token Micromeet tetap di backend.
- Jalankan di domain server yang sudah diverifikasi; selama pengembangan, di localhost. Backend dalam bahasa lain melakukan panggilan yang sama (lihat [Masuk](https://docs.micromeet.ai/id/miniapp-sdk/auth.md), bagian Panggilan HTTP).

## 5. Build, tanda tangan, dan pasang

1. Tambahkan `domains: ['https://api.example.com']` ke plugin Vite dan jalankan `vite build` (lihat [Pengemasan dan Tanda Tangan](https://docs.micromeet.ai/id/miniapp-sdk/build.md)).
2. Jalankan `micromeet-miniapp verify miniapp-package`, lalu serahkan paket ke Micromeet, yang mendaftarkan dan menandatangani versi ini di setiap region dan mengembalikan `manifest.json` bertanda tangan: taruh kembali di paket.
3. Jalankan `micromeet-miniapp verify miniapp-package --signed`, lalu `micromeet-miniapp zip miniapp-package`.
4. Di Cowork, minta agent memasang zip itu, buka Mini App, lalu masuk.

Cowork rilis hanya membuka versi yang ditandatangani Micromeet produksi; tidak ada mode pengembangan tanpa tanda tangan.

## 6. Kembangkan dan uji

- Tampilan dan logika yang tidak perlu masuk: `vite dev` di browser. Di sana `maestroSdk()` bernilai `null`, jadi tampilkan catatan singkat sebagai ganti tombol.
- Hanya file halaman yang ditandatangani: perubahan backend tidak perlu versi baru. Buat halaman sederhana dan taruh logika di backend.
- Perubahan pada file halaman mana pun atau pada `domains` perlu `version` baru, didaftarkan, ditandatangani, dan dipasang lagi.
- Menguji masuk dari awal sampai akhir perlu versi bertanda tangan dan Cowork yang masuk dengan akun dari region tempat Mini App terdaftar.
- Versi pengembangan boleh hanya mencantumkan domain localhost. Jangan sertakan localhost di versi rilis: region yang tidak mengizinkan localhost menolak proses masuknya dengan `no_server_domain`.

## Jika ada masalah

| Di mana | Yang terlihat | Penyebab dan solusi |
|---|---|---|
| Cowork | Mini App belum tersertifikasi dan tidak terbuka | Paket tidak bertanda tangan, ditandatangani lingkungan Micromeet lain, atau ada file yang berubah setelah ditandatangani: pasang zip yang bertanda tangan |
| Halaman | `app_not_available` | AppID tidak terdaftar di region orang itu, atau dinonaktifkan |
| Halaman | `version_not_available` | Versi ini tidak terdaftar di region itu, atau dinonaktifkan |
| Halaman | `no_server_domain` | Versi ini tidak punya domain server terverifikasi di region itu, atau file verifikasinya hilang |
| Halaman | `scope_denied` | Halaman meminta scope yang tidak diizinkan Micromeet untuk Mini App ini |
| Halaman | `fetch` gagal dengan galat CORS | Backend tidak menjawab dengan `Access-Control-Allow-Origin: miniapp://<appId>` |
| Backend | `invalid_client` | Secret salah untuk region ini, atau sudah diganti |
| Backend | `invalid_grant` | Code sudah dipakai, lebih dari 5 menit, atau untuk AppID lain |

## Terkait

- [Masuk](https://docs.micromeet.ai/id/miniapp-sdk/auth.md): Semua fungsi masuk, helper backend, dan galatnya
- [Pengemasan dan Tanda Tangan](https://docs.micromeet.ai/id/miniapp-sdk/build.md): Membuat paket dan meminta Micromeet menandatanganinya
- [Spesifikasi Paket](https://docs.micromeet.ai/id/miniapp-sdk/package-spec.md): Semua aturan yang harus dipenuhi paket
