# AIK Digital × EFU Life — Laravel Integration

Complete Laravel 10 implementation of the **AIK Digital × EFU Life Technical Integration Specification v1.0**.

---

## Quick Start (Windows)

```powershell
# In the project folder:
composer install
copy .env.example .env
php artisan key:generate
php generate-keys.php
php artisan migrate
php artisan serve
```

Or run the automated setup script:
```powershell
.\setup.ps1
```

---

## Quick Start (Linux / Mac)

```bash
bash setup.sh
```

---

## Configuration (`.env`)

After `copy .env.example .env`, fill in:

```env
# AIK Digital credentials (get from AIK Digital team)
AIK_CLIENT_ID=YOUR_CLIENT_ID_HERE
AIK_API_KEY=YOUR_API_KEY_HERE
AIK_MERCHANT_ID=EFULAssurance

# Your public callback URL (must be reachable by AIK Digital)
EFU_PAYMENT_NOTIFY_URL=https://your-domain.com/api/callbacks/payment
```

**Database:** Default config uses SQLite (`database/database.sqlite`) — no MySQL setup needed for local dev.
To switch to MySQL, change `DB_CONNECTION=mysql` and set `DB_HOST`, `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD`.

---

## RSA Keys

Run `php generate-keys.php` to create:

| File | Action |
|------|--------|
| `storage/keys/efu_private.pem` | Keep secret — used to sign outgoing requests |
| `storage/keys/efu_public.pem` | **Send to AIK Digital** (they verify your requests) |
| `storage/keys/aik_public.pem` | **Replace with AIK Digital's real key** (verify callbacks) |

Contact AIK Digital at `security@aikdigital.com` for their public key.

---

## API Endpoints

| Method | URL | Description |
|--------|-----|-------------|
| GET | `/api/iframe?uuid={UUID}` | iframe entry point — UUID resolution & onboarding |
| POST | `/api/aik/auth/apply-token` | Obtain AIK Digital access token |
| POST | `/api/aik/auth/revoke-token` | Revoke current token |
| POST | `/api/customers/inquire` | Call AIK Digital inquireUserInfo |
| GET | `/api/customers/{openId}` | Fetch customer from EFUL DB |
| POST | `/api/payments/create` | Create payment order |
| GET | `/api/payments/{orderId}/status` | Query payment order status |
| POST | `/api/callbacks/payment` | AIK Digital payment callback (notifyUrl) |

### Test with Postman
Import `AIK_EFU_Integration.postman_collection.json`.
Set collection variable `base_url` to `http://localhost:8000`.

---

## Project Structure

```
app/
├── Http/Controllers/
│   ├── AuthController.php       ← applyToken / revokeToken
│   ├── CustomerController.php   ← inquire + fetch customer
│   ├── IframeController.php     ← UUID entry point (WebView)
│   └── PaymentController.php    ← create order + callback + status
├── Models/
│   ├── Customer.php
│   └── PaymentOrder.php
├── Providers/
│   └── AppServiceProvider.php   ← DI bindings
└── Services/
    ├── AikDigitalApiClient.php  ← HTTP client + token management + retry
    ├── CustomerService.php      ← UUID validation + onboarding logic
    ├── PaymentService.php       ← order creation + callback processing
    └── SignatureService.php     ← RSA2048/SHA256 sign & verify

config/
└── aikdigital.php               ← All AIK Digital config

database/
├── database.sqlite              ← SQLite DB (auto-used in local dev)
└── migrations/
    ├── ..._create_customers_table.php
    └── ..._create_payment_orders_table.php

routes/api.php                   ← All routes
generate-keys.php                ← RSA key generator
setup.ps1                        ← Windows one-command setup
setup.sh                         ← Linux/Mac one-command setup
AIK_EFU_Integration.postman_collection.json
```

---

## Key Spec Rules Enforced in Code

- `createPayment` returning `S` does **NOT** activate policy — only callback `S` does
- Status `U` never triggers activation or refund (logged and escalated)
- Callback handler is **idempotent** — duplicate callbacks silently ignored
- `paymentAmount` cross-validated against original order before activation
- `openId` validated against customer before activation
- Token auto-refreshed on `INVALID_ACCESS_TOKEN` / `EXPIRED_ACCESS_TOKEN`
- Callback always returns HTTP 200 after signature check (per spec Section 6.7)
